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:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/CMakeLists.txt1
-rw-r--r--source/blender/SConscript1
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h205
-rw-r--r--source/blender/blenkernel/BKE_blender.h1
-rw-r--r--source/blender/blenkernel/BKE_bmesh.h1
-rw-r--r--source/blender/blenkernel/BKE_cdderivedmesh.h52
-rw-r--r--source/blender/blenkernel/BKE_context.h18
-rw-r--r--source/blender/blenkernel/BKE_customdata.h49
-rwxr-xr-x[-rw-r--r--]source/blender/blenkernel/BKE_idcode.h0
-rw-r--r--source/blender/blenkernel/BKE_key.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh.h42
-rw-r--r--source/blender/blenkernel/BKE_modifier.h7
-rw-r--r--source/blender/blenkernel/BKE_paint.h2
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h8
-rw-r--r--source/blender/blenkernel/BKE_tessmesh.h72
-rw-r--r--source/blender/blenkernel/BKE_utildefines.h15
-rw-r--r--source/blender/blenkernel/BKE_verse.h586
-rw-r--r--source/blender/blenkernel/CMakeLists.txt3
-rw-r--r--source/blender/blenkernel/SConscript1
-rw-r--r--source/blender/blenkernel/intern/BME_Customdata.c5
-rw-r--r--source/blender/blenkernel/intern/BME_conversions.c16
-rw-r--r--source/blender/blenkernel/intern/BME_eulers.c107
-rw-r--r--source/blender/blenkernel/intern/BME_mesh.c41
-rw-r--r--source/blender/blenkernel/intern/BME_structure.c68
-rw-r--r--source/blender/blenkernel/intern/BME_tools.c117
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c1401
-rw-r--r--source/blender/blenkernel/intern/anim.c31
-rw-r--r--source/blender/blenkernel/intern/armature.c1
-rw-r--r--source/blender/blenkernel/intern/blender.c20
-rw-r--r--source/blender/blenkernel/intern/booleanops.c603
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c8
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c1087
-rw-r--r--source/blender/blenkernel/intern/cloth.c11
-rw-r--r--source/blender/blenkernel/intern/constraint.c16
-rw-r--r--source/blender/blenkernel/intern/context.c69
-rw-r--r--source/blender/blenkernel/intern/curve.c1
-rw-r--r--source/blender/blenkernel/intern/customdata.c484
-rw-r--r--source/blender/blenkernel/intern/deform.c9
-rw-r--r--source/blender/blenkernel/intern/displist.c10
-rw-r--r--source/blender/blenkernel/intern/editderivedbmesh.c1711
-rw-r--r--source/blender/blenkernel/intern/effect.c2
-rw-r--r--source/blender/blenkernel/intern/exotic.c4
-rw-r--r--source/blender/blenkernel/intern/fluidsim.c5
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c2
-rw-r--r--source/blender/blenkernel/intern/font.c2
-rwxr-xr-x[-rw-r--r--]source/blender/blenkernel/intern/idcode.c0
-rw-r--r--source/blender/blenkernel/intern/key.c72
-rw-r--r--source/blender/blenkernel/intern/lattice.c1
-rw-r--r--source/blender/blenkernel/intern/library.c2
-rw-r--r--source/blender/blenkernel/intern/mesh.c657
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c2
-rw-r--r--source/blender/blenkernel/intern/modifiers_bmesh.c226
-rw-r--r--source/blender/blenkernel/intern/multires.c185
-rw-r--r--source/blender/blenkernel/intern/node.c3
-rw-r--r--source/blender/blenkernel/intern/object.c34
-rw-r--r--source/blender/blenkernel/intern/particle.c47
-rw-r--r--source/blender/blenkernel/intern/particle_system.c37
-rw-r--r--source/blender/blenkernel/intern/sca.c9
-rwxr-xr-x[-rw-r--r--]source/blender/blenkernel/intern/seqcache.c4
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c9
-rw-r--r--source/blender/blenkernel/intern/smoke.c14
-rw-r--r--source/blender/blenkernel/intern/softbody.c19
-rw-r--r--source/blender/blenkernel/intern/sound.c4
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c1423
-rw-r--r--source/blender/blenkernel/intern/verse_bitmap_node.c451
-rw-r--r--source/blender/blenkernel/intern/verse_geometry_node.c2101
-rw-r--r--source/blender/blenkernel/intern/verse_method.c523
-rw-r--r--source/blender/blenkernel/intern/verse_node.c750
-rw-r--r--source/blender/blenkernel/intern/verse_object_node.c620
-rw-r--r--source/blender/blenkernel/intern/verse_session.c480
-rw-r--r--source/blender/blenkernel/nla_private.h2
-rw-r--r--source/blender/blenlib/BLI_arithb.h569
-rw-r--r--source/blender/blenlib/BLI_array.h99
-rw-r--r--source/blender/blenlib/BLI_cellalloc.h51
-rw-r--r--source/blender/blenlib/BLI_edgehash.h106
-rw-r--r--source/blender/blenlib/BLI_editVert.h3
-rw-r--r--source/blender/blenlib/BLI_ghash.h36
-rw-r--r--source/blender/blenlib/BLI_math_color.h6
-rw-r--r--source/blender/blenlib/BLI_math_vector.h2
-rw-r--r--source/blender/blenlib/BLI_mempool.h114
-rwxr-xr-xsource/blender/blenlib/BLI_smallhash.h205
-rwxr-xr-xsource/blender/blenlib/BLI_sparsemap.h73
-rw-r--r--source/blender/blenlib/CMakeLists.txt1
-rw-r--r--source/blender/blenlib/SConscript6
-rw-r--r--source/blender/blenlib/intern/BLI_cellalloc.c198
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c2
-rw-r--r--source/blender/blenlib/intern/BLI_mempool.c130
-rw-r--r--source/blender/blenlib/intern/edgehash.c124
-rw-r--r--source/blender/blenlib/intern/math_geom.c2
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c23
-rw-r--r--source/blender/blenlib/intern/pbvh.c3
-rw-r--r--source/blender/blenlib/intern/rct.c2
-rw-r--r--source/blender/blenlib/intern/scanfill.c50
-rw-r--r--source/blender/blenloader/SConscript2
-rw-r--r--source/blender/blenloader/intern/readfile.c185
-rw-r--r--source/blender/blenloader/intern/writefile.c8
-rw-r--r--source/blender/blenpluginapi/SConscript2
-rw-r--r--source/blender/bmesh/CMakeLists.txt124
-rw-r--r--source/blender/bmesh/SConscript39
-rw-r--r--source/blender/bmesh/bmesh.h400
-rw-r--r--source/blender/bmesh/bmesh_class.h273
-rw-r--r--source/blender/bmesh/bmesh_error.h42
-rw-r--r--source/blender/bmesh/bmesh_filters.h4
-rw-r--r--source/blender/bmesh/bmesh_iterators.h91
-rw-r--r--source/blender/bmesh/bmesh_marking.h52
-rw-r--r--source/blender/bmesh/bmesh_operator_api.h481
-rw-r--r--source/blender/bmesh/bmesh_operators.h93
-rw-r--r--source/blender/bmesh/bmesh_queries.h89
-rw-r--r--source/blender/bmesh/bmesh_walkers.h73
-rw-r--r--source/blender/bmesh/editmesh_tools.c (renamed from source/blender/editors/mesh/editmesh_tools.c)6620
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c644
-rw-r--r--source/blender/bmesh/intern/bmesh_eulers.c1208
-rw-r--r--source/blender/bmesh/intern/bmesh_filters.c5
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c297
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c466
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c709
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c302
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c569
-rw-r--r--source/blender/bmesh/intern/bmesh_newcore.c1222
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c1002
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c1338
-rw-r--r--source/blender/bmesh/intern/bmesh_operators_private.h72
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c916
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h105
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c541
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.c938
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.h100
-rw-r--r--source/blender/bmesh/intern/bmesh_to_editmesh.c318
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.c919
-rw-r--r--source/blender/bmesh/intern/editmesh_to_bmesh.c476
-rw-r--r--source/blender/bmesh/intern/in-progress/BME_conversions.c478
-rw-r--r--source/blender/bmesh/operators/bmesh_dupeops.c575
-rw-r--r--source/blender/bmesh/operators/connectops.c103
-rw-r--r--source/blender/bmesh/operators/createops.c1284
-rw-r--r--source/blender/bmesh/operators/dissolveops.c430
-rw-r--r--source/blender/bmesh/operators/edgesplitop.c360
-rw-r--r--source/blender/bmesh/operators/extrudeops.c311
-rw-r--r--source/blender/bmesh/operators/join_triangles.c358
-rw-r--r--source/blender/bmesh/operators/mesh_conv.c754
-rw-r--r--source/blender/bmesh/operators/mirror.c127
-rw-r--r--source/blender/bmesh/operators/primitiveops.c594
-rw-r--r--source/blender/bmesh/operators/removedoubles.c610
-rw-r--r--source/blender/bmesh/operators/subdivideop.c1075
-rw-r--r--source/blender/bmesh/operators/subdivideop.h38
-rw-r--r--source/blender/bmesh/operators/triangulateop.c56
-rw-r--r--source/blender/bmesh/operators/utils.c1300
-rw-r--r--source/blender/bmesh/tools/BME_bevel.c918
-rw-r--r--source/blender/bmesh/tools/BME_dupe_ops.c318
-rw-r--r--source/blender/bmesh/tools/BME_duplicate.c307
-rw-r--r--source/blender/bmesh/tools/BME_extrude.c216
-rw-r--r--source/blender/bmesh/tools/BME_weld.c333
-rw-r--r--source/blender/collada/CMakeLists.txt8
-rw-r--r--source/blender/collada/DocumentExporter.cpp452
-rw-r--r--source/blender/editors/animation/SConscript5
-rw-r--r--source/blender/editors/armature/SConscript1
-rw-r--r--source/blender/editors/armature/editarmature.c9
-rw-r--r--source/blender/editors/armature/meshlaplacian.c12
-rw-r--r--source/blender/editors/armature/poseobject.c6
-rw-r--r--source/blender/editors/armature/reeb.c12
-rw-r--r--source/blender/editors/curve/SConscript4
-rw-r--r--source/blender/editors/curve/editcurve.c4
-rw-r--r--source/blender/editors/curve/editfont.c4
-rw-r--r--source/blender/editors/datafiles/SConscript2
-rw-r--r--source/blender/editors/gpencil/SConscript4
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c10
-rw-r--r--source/blender/editors/include/ED_mesh.h245
-rwxr-xr-xsource/blender/editors/include/ED_toolmode.h80
-rw-r--r--source/blender/editors/include/ED_util.h7
-rw-r--r--source/blender/editors/include/ED_uvedit.h21
-rw-r--r--source/blender/editors/include/ED_view3d.h17
-rw-r--r--source/blender/editors/include/UI_interface.h1
-rw-r--r--source/blender/editors/include/UI_resources.h3
-rw-r--r--source/blender/editors/interface/SConscript5
-rw-r--r--source/blender/editors/interface/interface_handlers.c2
-rw-r--r--source/blender/editors/interface/resources.c8
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt23
-rw-r--r--source/blender/editors/mesh/SConscript1
-rw-r--r--source/blender/editors/mesh/bmesh_select.c2170
-rw-r--r--source/blender/editors/mesh/bmesh_selecthistory.c126
-rw-r--r--source/blender/editors/mesh/bmesh_tools.c4795
-rw-r--r--source/blender/editors/mesh/bmeshutils.c897
-rw-r--r--source/blender/editors/mesh/editbmesh_add.c588
-rw-r--r--source/blender/editors/mesh/editbmesh_bvh.c715
-rw-r--r--source/blender/editors/mesh/editbmesh_bvh.h31
-rw-r--r--source/blender/editors/mesh/editface.c492
-rw-r--r--source/blender/editors/mesh/editmesh.c1952
-rw-r--r--source/blender/editors/mesh/editmesh_add.c1768
-rw-r--r--source/blender/editors/mesh/editmesh_lib.c2842
-rw-r--r--source/blender/editors/mesh/editmesh_loop.c731
-rw-r--r--source/blender/editors/mesh/editmesh_mods.c4459
-rwxr-xr-xsource/blender/editors/mesh/knifetool.c1685
-rw-r--r--source/blender/editors/mesh/loopcut.c391
-rw-r--r--source/blender/editors/mesh/mesh_data.c153
-rw-r--r--source/blender/editors/mesh/mesh_intern.h107
-rw-r--r--source/blender/editors/mesh/mesh_ops.c37
-rw-r--r--source/blender/editors/mesh/meshtools.c219
-rw-r--r--source/blender/editors/metaball/mball_edit.c4
-rw-r--r--source/blender/editors/object/CMakeLists.txt1
-rw-r--r--source/blender/editors/object/SConscript2
-rw-r--r--source/blender/editors/object/object_add.c3
-rw-r--r--source/blender/editors/object/object_constraint.c2
-rw-r--r--source/blender/editors/object/object_edit.c44
-rw-r--r--source/blender/editors/object/object_hook.c45
-rw-r--r--source/blender/editors/object/object_lattice.c4
-rw-r--r--source/blender/editors/object/object_modifier.c24
-rw-r--r--source/blender/editors/object/object_relations.c31
-rw-r--r--source/blender/editors/object/object_shapekey.c6
-rw-r--r--source/blender/editors/object/object_transform.c64
-rw-r--r--source/blender/editors/object/object_vgroup.c170
-rw-r--r--source/blender/editors/physics/SConscript4
-rw-r--r--source/blender/editors/physics/particle_edit.c6
-rw-r--r--source/blender/editors/physics/particle_object.c4
-rw-r--r--source/blender/editors/render/CMakeLists.txt1
-rw-r--r--source/blender/editors/render/SConscript2
-rw-r--r--source/blender/editors/render/render_shading.c16
-rw-r--r--source/blender/editors/screen/CMakeLists.txt1
-rw-r--r--source/blender/editors/screen/Makefile68
-rw-r--r--source/blender/editors/screen/SConscript2
-rw-r--r--source/blender/editors/screen/screen_edit.c4
-rw-r--r--source/blender/editors/screen/screen_ops.c16
-rw-r--r--source/blender/editors/sculpt_paint/SConscript4
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c36
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c8
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c452
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c41
-rw-r--r--source/blender/editors/space_api/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_api/SConscript2
-rw-r--r--source/blender/editors/space_api/spacetypes.c3
-rw-r--r--source/blender/editors/space_buttons/SConscript4
-rw-r--r--source/blender/editors/space_file/Makefile76
-rw-r--r--source/blender/editors/space_image/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_image/Makefile77
-rw-r--r--source/blender/editors/space_image/SConscript4
-rw-r--r--source/blender/editors/space_image/image_buttons.c77
-rw-r--r--source/blender/editors/space_image/image_draw.c4
-rw-r--r--source/blender/editors/space_image/image_header.c1
-rw-r--r--source/blender/editors/space_image/image_ops.c4
-rw-r--r--source/blender/editors/space_image/space_image.c22
-rw-r--r--source/blender/editors/space_info/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_info/Makefile56
-rw-r--r--source/blender/editors/space_info/SConscript4
-rw-r--r--source/blender/editors/space_info/info_stats.c27
-rw-r--r--source/blender/editors/space_logic/logic_buttons.c2
-rw-r--r--source/blender/editors/space_node/SConscript2
-rw-r--r--source/blender/editors/space_outliner/outliner.c5
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_view3d/SConscript2
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c64
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c71
-rw-r--r--source/blender/editors/space_view3d/drawobject.c577
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c157
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c11
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c45
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h3
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c164
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c87
-rw-r--r--source/blender/editors/space_view3d/view3d_toolbar.c24
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c23
-rw-r--r--source/blender/editors/transform/CMakeLists.txt1
-rw-r--r--source/blender/editors/transform/SConscript4
-rw-r--r--source/blender/editors/transform/transform.c359
-rw-r--r--source/blender/editors/transform/transform.h15
-rw-r--r--source/blender/editors/transform/transform_constraints.c2
-rw-r--r--source/blender/editors/transform/transform_conversions.c447
-rw-r--r--source/blender/editors/transform/transform_generics.c210
-rw-r--r--source/blender/editors/transform/transform_manipulator.c27
-rw-r--r--source/blender/editors/transform/transform_orientations.c152
-rw-r--r--source/blender/editors/transform/transform_snap.c80
-rw-r--r--source/blender/editors/util/CMakeLists.txt1
-rw-r--r--source/blender/editors/util/SConscript2
-rw-r--r--source/blender/editors/util/crazyspace.c28
-rw-r--r--source/blender/editors/util/ed_util.c16
-rw-r--r--source/blender/editors/util/editmode_undo.c22
-rw-r--r--source/blender/editors/uvedit/CMakeLists.txt1
-rw-r--r--source/blender/editors/uvedit/SConscript4
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c475
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h14
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c2153
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.h2
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c619
-rw-r--r--source/blender/gpu/GPU_material.h2
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c30
-rw-r--r--source/blender/gpu/intern/gpu_draw.c10
-rw-r--r--source/blender/gpu/intern/gpu_material.c63
-rw-r--r--source/blender/gpu/intern/gpu_shader_material.glsl5
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp14
-rw-r--r--source/blender/makesdna/DNA_color_types.h2
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h32
-rw-r--r--source/blender/makesdna/DNA_key_types.h9
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h33
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h38
-rw-r--r--source/blender/makesdna/DNA_object_types.h5
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h3
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h1
-rw-r--r--source/blender/makesdna/intern/SConscript17
-rw-r--r--source/blender/makesdna/intern/makesdna.c2
-rw-r--r--source/blender/makesrna/SConscript2
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt1
-rw-r--r--source/blender/makesrna/intern/SConscript6
-rw-r--r--source/blender/makesrna/intern/makesrna.c1
-rw-r--r--source/blender/makesrna/intern/rna_animviz.c2
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c2
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c2
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c562
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c19
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c4
-rw-r--r--source/blender/makesrna/intern/rna_nla.c2
-rw-r--r--source/blender/makesrna/intern/rna_object.c10
-rw-r--r--source/blender/makesrna/intern/rna_pose_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c10
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c10
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c2
-rw-r--r--source/blender/makesrna/rna_cleanup/rna_properties.txt4608
-rwxr-xr-xsource/blender/makesrna/rna_cleanup/rna_update.sh16
-rw-r--r--source/blender/modifiers/CMakeLists.txt1
-rw-r--r--source/blender/modifiers/SConscript8
-rw-r--r--source/blender/modifiers/intern/MOD_array.c780
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c4
-rw-r--r--source/blender/modifiers/intern/MOD_boolean_util.c34
-rw-r--r--source/blender/modifiers/intern/MOD_build.c12
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c6
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c17
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c4
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c1407
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c37
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c10
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c16
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c8
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c286
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c4
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c14
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c6
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c14
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c22
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c2
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c4
-rw-r--r--source/blender/modifiers/intern/MOD_util.c2
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c4
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c4
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_output.c2
-rw-r--r--source/blender/python/BPY_menus.c1118
-rw-r--r--source/blender/python/BPY_menus.h128
-rw-r--r--source/blender/python/Makefile34
-rw-r--r--source/blender/python/epy_doc_gen.py753
-rw-r--r--source/blender/python/generic/bpy_internal_import.h2
-rw-r--r--source/blender/python/intern/Makefile67
-rw-r--r--source/blender/python/intern/bpy.c2
-rw-r--r--source/blender/python/intern/bpy_array.c606
-rw-r--r--source/blender/python/intern/bpy_interface.c4
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.c1
-rw-r--r--source/blender/python/intern/bpy_rna.c2
-rw-r--r--source/blender/python/intern/bpy_ui.c69
-rw-r--r--source/blender/python/intern/bpy_ui.h31
-rw-r--r--source/blender/python/simple_enum_gen.py54
-rw-r--r--source/blender/readblenfile/intern/BLO_readblenfile.c1
-rw-r--r--source/blender/render/SConscript4
-rw-r--r--source/blender/render/intern/include/raycounter.h2
-rw-r--r--source/blender/render/intern/include/rayobject.h2
-rw-r--r--source/blender/render/intern/raytrace/reorganize.h8
-rw-r--r--source/blender/render/intern/source/convertblender.c30
-rw-r--r--source/blender/render/intern/source/pipeline.c2
-rw-r--r--source/blender/render/intern/source/pointdensity.c4
-rw-r--r--source/blender/render/intern/source/rayobject_blibvh.c169
-rw-r--r--source/blender/render/intern/source/rayobject_instance.c207
-rw-r--r--source/blender/render/intern/source/rayobject_octree.c1080
-rw-r--r--source/blender/render/intern/source/rayobject_raycounter.c87
-rw-r--r--source/blender/render/intern/source/shadeoutput.c35
-rw-r--r--source/blender/render/intern/source/strand.c4
-rw-r--r--source/blender/windowmanager/CMakeLists.txt2
-rw-r--r--source/blender/windowmanager/SConscript2
-rw-r--r--source/blender/windowmanager/WM_types.h3
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c13
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c8
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c12
-rw-r--r--source/blender/windowmanager/intern/wm_window.c6
380 files changed, 69470 insertions, 23383 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 263d81fab0a..2871c4cd214 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -88,6 +88,7 @@ add_subdirectory(editors)
add_subdirectory(windowmanager)
add_subdirectory(blenkernel)
add_subdirectory(blenlib)
+add_subdirectory(bmesh)
add_subdirectory(render)
add_subdirectory(blenfont)
add_subdirectory(blenloader)
diff --git a/source/blender/SConscript b/source/blender/SConscript
index 549725a57a0..24514f1660c 100644
--- a/source/blender/SConscript
+++ b/source/blender/SConscript
@@ -3,6 +3,7 @@ Import ('env')
import sys
SConscript(['avi/SConscript',
+ 'bmesh/SConscript',
'blenkernel/SConscript',
'blenlib/SConscript',
'blenloader/SConscript',
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 857c88a6004..ea5b9e8367f 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -30,21 +30,49 @@
#ifndef BKE_DERIVEDMESH_H
#define BKE_DERIVEDMESH_H
-/** \file BKE_DerivedMesh.h
- * \ingroup bke
- *
- * \todo
- * - Make drawMapped* functions take a predicate function that
- * determines whether to draw the edge (this predicate can
- * also set color, etc). This will be slightly more general
- * and allow some of the functions to be collapsed.
- * - Once accessor functions are added then single element draw
- * functions can be implemented using primitive accessors.
- * - Add function to dispatch to renderer instead of using
- * conversion to DLM.
+/*
+ Basic design of the DerivedMesh system:
+
+ DerivedMesh is a common set of interfaces for mesh systems.
+
+ There are three main mesh data structures in Blender: Mesh, CDDM, and BMesh.
+ These, and a few others, all implement DerivedMesh interfaces,
+ which contains unified drawing interfaces, a few utility interfaces,
+ and a bunch of read-only interfaces intended mostly for conversion from
+ one format to another.
+
+ All Mesh structures in blender make use of CustomData, which is used to store
+ per-element attributes and interpolate them (e.g. uvs, vcols, vgroups, etc).
+
+ Mesh is the "serialized" structure, used for storing object-mode mesh data
+ and also for saving stuff to disk. It's interfaces are also what DerivedMesh
+ uses to communicate with.
+
+ CDDM is a little mesh library, that uses Mesh data structures in the backend.
+ It's mostly used for modifiers, and has the advantages of not taking much
+ resources.
+
+ BMesh is a full-on brep, used for editmode, some modifiers, etc. It's much
+ more capable (if memory-intensive) then CDDM.
+
+ DerivedMesh is somewhat hackish. Many places assumes that a DerivedMesh is
+ a CDDM (most of the time by simply copying it and converting it to one).
+ CDDM is the original structure for modifiers, but has since been superseded
+ by BMesh, at least for the foreseeable future.
+*/
+
+/*
+ * Note: This sturcture is read-only, for all practical purposes.
+ * At some point in the future, we may want to consider
+ * creating a replacement structure that implements a proper
+ * abstract mesh kernel interface. Or, we can leave this
+ * as it is and stick with using BMesh and CDDM.
*/
+
#include "DNA_customdata_types.h"
+#include "DNA_meshdata_types.h"
+
#include "BKE_customdata.h"
#include "BKE_bvhutils.h"
@@ -55,20 +83,63 @@ struct MTFace;
struct Object;
struct Scene;
struct Mesh;
-struct EditMesh;
+struct BMEditMesh;
struct KeyBlock;
struct ModifierData;
struct MCol;
struct ColorBand;
struct GPUVertexAttribs;
struct GPUDrawObject;
+struct BMEditMesh;
struct ListBase;
struct PBVH;
/* number of sub-elements each mesh element has (for interpolation) */
#define SUB_ELEMS_VERT 0
#define SUB_ELEMS_EDGE 2
-#define SUB_ELEMS_FACE 4
+#define SUB_ELEMS_FACE 50
+
+/*
+Note: all mface interfaces now officially operate on tesselated data.
+ Also, the mface origindex layer indexes mpolys, not mfaces.
+*/
+
+/*DM Iterators. For now, first implement face iterators.
+ These are read-only, at least for now.*/
+
+typedef struct DMLoopIter {
+ void (*step)(void *self);
+ int done;
+
+ int index, vindex, eindex;
+ MVert v; /*copy of the associated vert's data*/
+
+ /*note: if layer is -1, then the active layer is retrieved.
+ loop refers to per-face-vertex data.*/
+ void *(*getLoopCDData)(void *self, int type, int layer);
+ void *(*getVertCDData)(void *self, int type, int layer);
+} DMLoopIter;
+
+typedef struct DMFaceIter {
+ void (*step)(void *self);
+ void (*free)(void *self);
+ int done;
+
+ int index;
+ int len;
+
+ /*you can set mat_nr and flags, and the backends
+ must detect and update the internal faces*/
+ int mat_nr;
+ int flags;
+
+ /*note: you may only use one
+ loop iterator at a time.*/
+ DMLoopIter *(*getLoopsIter)(void *self);
+
+ /*if layer is -1, returns active layer*/
+ void *(*getCDData)(void *self, int type, int layer);
+} DMFaceIter;
typedef struct DMGridData {
float co[3];
@@ -82,15 +153,15 @@ typedef struct DMGridAdjacency {
typedef enum DerivedMeshType {
DM_TYPE_CDDM,
- DM_TYPE_EDITMESH,
+ DM_TYPE_EDITBMESH,
DM_TYPE_CCGDM
} DerivedMeshType;
typedef struct DerivedMesh DerivedMesh;
struct DerivedMesh {
/* Private DerivedMesh data, only for internal DerivedMesh use */
- CustomData vertData, edgeData, faceData;
- int numVertData, numEdgeData, numFaceData;
+ CustomData vertData, edgeData, faceData, loopData, polyData;
+ int numVertData, numEdgeData, numFaceData, numLoopData, numPolyData;
int needsFree; /* checked on ->release, is set to 0 for cached results */
int deformedOnly; /* set by modifier stack if only deformed from original */
BVHCache bvhCache;
@@ -98,22 +169,27 @@ struct DerivedMesh {
DerivedMeshType type;
/* Misc. Queries */
+
+ /*face iterator. initializes iter.*/
+ DMFaceIter *(*newFaceIter)(DerivedMesh *dm);
+
+ /*recalculates mesh tesselation*/
+ void (*recalcTesselation)(DerivedMesh *dm);
/* Also called in Editmode */
int (*getNumVerts)(DerivedMesh *dm);
- /* Also called in Editmode */
- int (*getNumFaces)(DerivedMesh *dm);
-
int (*getNumEdges)(DerivedMesh *dm);
+ int (*getNumTessFaces)(DerivedMesh *dm);
+ int (*getNumFaces) (DerivedMesh *dm);
- /* copy a single vert/edge/face from the derived mesh into
+ /* copy a single vert/edge/tesselated face from the derived mesh into
* *{vert/edge/face}_r. note that the current implementation
* of this function can be quite slow, iterating over all
* elements (editmesh)
*/
void (*getVert)(DerivedMesh *dm, int index, struct MVert *vert_r);
void (*getEdge)(DerivedMesh *dm, int index, struct MEdge *edge_r);
- void (*getFace)(DerivedMesh *dm, int index, struct MFace *face_r);
+ void (*getTessFace)(DerivedMesh *dm, int index, struct MFace *face_r);
/* return a pointer to the entire array of verts/edges/face from the
* derived mesh. if such an array does not exist yet, it will be created,
@@ -122,21 +198,21 @@ struct DerivedMesh {
*/
struct MVert *(*getVertArray)(DerivedMesh *dm);
struct MEdge *(*getEdgeArray)(DerivedMesh *dm);
- struct MFace *(*getFaceArray)(DerivedMesh *dm);
+ struct MFace *(*getTessFaceArray)(DerivedMesh *dm);
/* copy all verts/edges/faces from the derived mesh into
* *{vert/edge/face}_r (must point to a buffer large enough)
*/
void (*copyVertArray)(DerivedMesh *dm, struct MVert *vert_r);
void (*copyEdgeArray)(DerivedMesh *dm, struct MEdge *edge_r);
- void (*copyFaceArray)(DerivedMesh *dm, struct MFace *face_r);
+ void (*copyTessFaceArray)(DerivedMesh *dm, struct MFace *face_r);
/* return a copy of all verts/edges/faces from the derived mesh
* it is the caller's responsibility to free the returned pointer
*/
struct MVert *(*dupVertArray)(DerivedMesh *dm);
struct MEdge *(*dupEdgeArray)(DerivedMesh *dm);
- struct MFace *(*dupFaceArray)(DerivedMesh *dm);
+ struct MFace *(*dupTessFaceArray)(DerivedMesh *dm);
/* return a pointer to a single element of vert/edge/face custom data
* from the derived mesh (this gives a pointer to the actual data, not
@@ -144,7 +220,7 @@ struct DerivedMesh {
*/
void *(*getVertData)(DerivedMesh *dm, int index, int type);
void *(*getEdgeData)(DerivedMesh *dm, int index, int type);
- void *(*getFaceData)(DerivedMesh *dm, int index, int type);
+ void *(*getTessFaceData)(DerivedMesh *dm, int index, int type);
/* return a pointer to the entire array of vert/edge/face custom data
* from the derived mesh (this gives a pointer to the actual data, not
@@ -152,8 +228,21 @@ struct DerivedMesh {
*/
void *(*getVertDataArray)(DerivedMesh *dm, int type);
void *(*getEdgeDataArray)(DerivedMesh *dm, int type);
- void *(*getFaceDataArray)(DerivedMesh *dm, int type);
-
+ void *(*getTessFaceDataArray)(DerivedMesh *dm, int type);
+
+ /*retrieves the base CustomData structures for
+ verts/edges/tessfaces/loops/facdes*/
+ CustomData *(*getVertDataLayout)(DerivedMesh *dm);
+ CustomData *(*getEdgeDataLayout)(DerivedMesh *dm);
+ CustomData *(*getTessFaceDataLayout)(DerivedMesh *dm);
+ CustomData *(*getLoopDataLayout)(DerivedMesh *dm);
+ CustomData *(*getFaceDataLayout)(DerivedMesh *dm);
+
+ /*copies all customdata for an element source into dst at index dest*/
+ void (*copyFromVertCData)(DerivedMesh *dm, int source, CustomData *dst, int dest);
+ void (*copyFromEdgeCData)(DerivedMesh *dm, int source, CustomData *dst, int dest);
+ void (*copyFromFaceCData)(DerivedMesh *dm, int source, CustomData *dst, int dest);
+
/* optional grid access for subsurf */
int (*getNumGrids)(DerivedMesh *dm);
int (*getGridSize)(DerivedMesh *dm);
@@ -256,8 +345,8 @@ struct DerivedMesh {
* o Drawing options too complicated to enumerate, look at code.
*/
void (*drawFacesTex)(DerivedMesh *dm,
- int (*setDrawOptions)(struct MTFace *tface,
- struct MCol *mcol, int matnr));
+ int (*setDrawOptions)(struct MTFace *tface,
+ int has_vcol, int matnr));
/* Draw all faces with GLSL materials
* o setMaterial is called for every different material nr
@@ -339,15 +428,16 @@ void DM_init_funcs(DerivedMesh *dm);
* of vertices, edges and faces (doesn't allocate memory for them, just
* sets up the custom data layers)
*/
-void DM_init(DerivedMesh *dm, DerivedMeshType type,
- int numVerts, int numEdges, int numFaces);
+void DM_init(DerivedMesh *dm, DerivedMeshType type, int numVerts, int numEdges,
+ int numFaces, int numLoops, int numPolys);
/* utility function to initialise a DerivedMesh for the desired number
* of vertices, edges and faces, with a layer setup copied from source
*/
void DM_from_template(DerivedMesh *dm, DerivedMesh *source,
- DerivedMeshType type,
- int numVerts, int numEdges, int numFaces);
+ DerivedMeshType type,
+ int numVerts, int numEdges, int numFaces,
+ int numLoops, int numPolys);
/* utility function to release a DerivedMesh's layers
* returns 1 if DerivedMesh has to be released by the backend, 0 otherwise
@@ -377,6 +467,8 @@ void DM_add_vert_layer(struct DerivedMesh *dm, int type, int alloctype,
void *layer);
void DM_add_edge_layer(struct DerivedMesh *dm, int type, int alloctype,
void *layer);
+void DM_add_tessface_layer(struct DerivedMesh *dm, int type, int alloctype,
+ void *layer);
void DM_add_face_layer(struct DerivedMesh *dm, int type, int alloctype,
void *layer);
@@ -396,6 +488,7 @@ void *DM_get_face_data(struct DerivedMesh *dm, int index, int type);
*/
void *DM_get_vert_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_edge_data_layer(struct DerivedMesh *dm, int type);
+void *DM_get_tessface_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_face_data_layer(struct DerivedMesh *dm, int type);
/* custom data setting functions
@@ -414,6 +507,10 @@ void DM_copy_vert_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int source_index, int dest_index, int count);
void DM_copy_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int source_index, int dest_index, int count);
+void DM_copy_tessface_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+ int source_index, int dest_index, int count);
+void DM_copy_loop_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+ int source_index, int dest_index, int count);
void DM_copy_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int source_index, int dest_index, int count);
@@ -423,8 +520,13 @@ void DM_copy_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
*/
void DM_free_vert_data(struct DerivedMesh *dm, int index, int count);
void DM_free_edge_data(struct DerivedMesh *dm, int index, int count);
+void DM_free_tessface_data(struct DerivedMesh *dm, int index, int count);
+void DM_free_loop_data(struct DerivedMesh *dm, int index, int count);
void DM_free_face_data(struct DerivedMesh *dm, int index, int count);
+/*sets up mpolys for a DM based on face iterators in source*/
+void DM_DupPolys(DerivedMesh *source, DerivedMesh *target);
+
/* interpolates vertex data from the vertices indexed by src_indices in the
* source mesh using the given weights and stores the result in the vertex
* indexed by dest_index in the dest mesh
@@ -454,12 +556,20 @@ void DM_interp_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest,
* vert_weights[i] multiplied by weights[i].
*/
typedef float FaceVertWeight[SUB_ELEMS_FACE][SUB_ELEMS_FACE];
-void DM_interp_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+void DM_interp_tessface_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int *src_indices,
float *weights, FaceVertWeight *vert_weights,
int count, int dest_index);
-void DM_swap_face_data(struct DerivedMesh *dm, int index, const int *corner_indices);
+void DM_swap_tessface_data(struct DerivedMesh *dm, int index, const int *corner_indices);
+
+void DM_interp_loop_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+ int *src_indices,
+ float *weights, int count, int dest_index);
+
+void DM_interp_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+ int *src_indices,
+ float *weights, int count, int dest_index);
/* Temporary? A function to give a colorband to derivedmesh for vertexcolor ranges */
void vDM_ColorBand_store(struct ColorBand *coba);
@@ -480,6 +590,9 @@ DerivedMesh *mesh_create_derived_for_modifier(struct Scene *scene, struct Object
DerivedMesh *mesh_create_derived_render(struct Scene *scene, struct Object *ob,
CustomDataMask dataMask);
+DerivedMesh *getEditDerivedBMesh(struct BMEditMesh *em, struct Object *ob,
+ float (*vertexCos)[3]);
+
DerivedMesh *mesh_create_derived_index_render(struct Scene *scene, struct Object *ob, CustomDataMask dataMask, int index);
/* same as above but wont use render settings */
@@ -498,20 +611,20 @@ DerivedMesh *mesh_create_derived_no_virtual(struct Scene *scene, struct Object *
DerivedMesh *mesh_create_derived_physics(struct Scene *scene, struct Object *ob, float (*vertCos)[3],
CustomDataMask dataMask);
-DerivedMesh *editmesh_get_derived(struct EditMesh *em, float (*vertexCos)[3]);
-DerivedMesh *editmesh_get_derived_base(struct Object *, struct EditMesh *em);
-DerivedMesh *editmesh_get_derived_cage(struct Scene *scene, struct Object *,
- struct EditMesh *em, CustomDataMask dataMask);
-DerivedMesh *editmesh_get_derived_cage_and_final(struct Scene *scene, struct Object *,
- struct EditMesh *em, DerivedMesh **final_r,
+DerivedMesh *editbmesh_get_derived(struct BMEditMesh *em, float (*vertexCos)[3]);
+DerivedMesh *editbmesh_get_derived_base(struct Object *, struct BMEditMesh *em);
+DerivedMesh *editbmesh_get_derived_cage(struct Scene *scene, struct Object *,
+ struct BMEditMesh *em, CustomDataMask dataMask);
+DerivedMesh *editbmesh_get_derived_cage_and_final(struct Scene *scene, struct Object *,
+ struct BMEditMesh *em, DerivedMesh **final_r,
CustomDataMask dataMask);
-float (*editmesh_get_vertex_cos(struct EditMesh *em, int *numVerts_r))[3];
-int editmesh_modifier_is_enabled(struct Scene *scene, struct ModifierData *md, DerivedMesh *dm);
-void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct EditMesh *em, CustomDataMask dataMask);
+float (*editbmesh_get_vertex_cos(struct BMEditMesh *em, int *numVerts_r))[3];
+int editbmesh_modifier_is_enabled(struct Scene *scene, struct ModifierData *md, DerivedMesh *dm);
+void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct BMEditMesh *em, CustomDataMask dataMask);
/* returns an array of deform matrices for crazyspace correction, and the
number of modifiers left */
-int editmesh_get_first_deform_matrices(struct Scene *, struct Object *, struct EditMesh *em,
+int editbmesh_get_first_deform_matrices(struct Scene *, struct Object *, struct BMEditMesh *em,
float (**deformmats)[3][3], float (**deformcos)[3]);
/* returns an array of deform matrices for crazyspace correction when sculpting,
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index f6bb4fbb635..44ce6060f1b 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -89,6 +89,7 @@ extern int BKE_undo_valid(const char *name);
extern void BKE_reset_undo(void);
extern char *BKE_undo_menu_string(void);
extern void BKE_undo_number(struct bContext *C, int nr);
+void BKE_undo_save(char *fname);
extern void BKE_undo_save_quit(void);
extern struct Main *BKE_undo_get_main(struct Scene **scene);
diff --git a/source/blender/blenkernel/BKE_bmesh.h b/source/blender/blenkernel/BKE_bmesh.h
index 5c28fa88503..e347f8fe76e 100644
--- a/source/blender/blenkernel/BKE_bmesh.h
+++ b/source/blender/blenkernel/BKE_bmesh.h
@@ -56,6 +56,7 @@ struct BME_Edge;
struct BME_Poly;
struct BME_Loop;
+/*NOTE: this is the bmesh 1.0 code. it's completely outdated.*/
/*Notes on further structure Cleanup:
-Remove the tflags, they belong in custom data layers
diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h
index 1edec2b69d9..c1161e7c65b 100644
--- a/source/blender/blenkernel/BKE_cdderivedmesh.h
+++ b/source/blender/blenkernel/BKE_cdderivedmesh.h
@@ -40,12 +40,17 @@
#include "BKE_DerivedMesh.h"
struct DerivedMesh;
+struct BMEditMesh;
struct EditMesh;
struct Mesh;
struct Object;
/* creates a new CDDerivedMesh */
-struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces);
+struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces,
+ int numLoops, int numPolys);
+
+/*tests if a given DerivedMesh is a CDDM*/
+int CDDM_Check(struct DerivedMesh *dm);
/* creates a CDDerivedMesh from the given Mesh, this will reference the
original data in Mesh, but it is safe to apply vertex coordinates or
@@ -56,6 +61,12 @@ struct DerivedMesh *CDDM_from_mesh(struct Mesh *mesh, struct Object *ob);
/* creates a CDDerivedMesh from the given EditMesh */
struct DerivedMesh *CDDM_from_editmesh(struct EditMesh *em, struct Mesh *me);
+/* creates a CDDerivedMesh from the given BMEditMesh */
+DerivedMesh *CDDM_from_BMEditMesh(struct BMEditMesh *em, struct Mesh *me);
+
+/* merge verts */
+DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, int *vtargetmap);
+
/* creates a CDDerivedMesh from the given curve object */
struct DerivedMesh *CDDM_from_curve(struct Object *ob);
@@ -63,17 +74,26 @@ struct DerivedMesh *CDDM_from_curve(struct Object *ob);
/* useful for OrcoDM creation for curves with constructive modifiers */
DerivedMesh *CDDM_from_curve_customDB(struct Object *ob, struct ListBase *dispbase);
+struct BMEditMesh *CDDM_To_BMesh(DerivedMesh *dm, struct BMEditMesh *existing);
+
+
/* Copies the given DerivedMesh with verts, faces & edges stored as
* custom element data.
*/
-struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm);
+struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm, int faces_from_tessfaces);
/* creates a CDDerivedMesh with the same layer stack configuration as the
* given DerivedMesh and containing the requested numbers of elements.
* elements are initialised to all zeros
*/
struct DerivedMesh *CDDM_from_template(struct DerivedMesh *source,
- int numVerts, int numEdges, int numFaces);
+ int numVerts, int numEdges, int numFaces,
+ int numLoops, int numPolys);
+
+/*converts mfaces to mpolys. note things may break if there are not valid
+ *medges surrounding each mface.
+ */
+void CDDM_tessfaces_to_faces(struct DerivedMesh *dm);
/* applies vertex coordinates or normals to a CDDerivedMesh. if the MVert
* layer is a referenced layer, it will be duplicate to not overwrite the
@@ -88,9 +108,17 @@ void CDDM_calc_normals(struct DerivedMesh *dm);
/* calculates edges for a CDDerivedMesh (from face data)
* this completely replaces the current edge data in the DerivedMesh
+ * builds edges from the tesselated face data.
*/
void CDDM_calc_edges(struct DerivedMesh *dm);
+/* same as CDDM_calc_edges only makes edges from ngon faces instead of tesselation
+ faces*/
+void CDDM_calc_edges_poly(struct DerivedMesh *dm);
+
+/*reconstitute face triangulation*/
+void CDDM_recalc_tesselation(struct DerivedMesh *dm);
+
/* lowers the number of vertices/edges/faces in a CDDerivedMesh
* the layer data stays the same size
*/
@@ -104,7 +132,9 @@ void CDDM_lower_num_faces(struct DerivedMesh *dm, int numFaces);
*/
struct MVert *CDDM_get_vert(struct DerivedMesh *dm, int index);
struct MEdge *CDDM_get_edge(struct DerivedMesh *dm, int index);
-struct MFace *CDDM_get_face(struct DerivedMesh *dm, int index);
+struct MFace *CDDM_get_tessface(struct DerivedMesh *dm, int index);
+struct MLoop *CDDM_get_loop(struct DerivedMesh *dm, int index);
+struct MPoly *CDDM_get_face(struct DerivedMesh *dm, int index);
/* vertex/edge/face array access functions - return the array holding the
* desired data
@@ -113,6 +143,18 @@ struct MFace *CDDM_get_face(struct DerivedMesh *dm, int index);
*/
struct MVert *CDDM_get_verts(struct DerivedMesh *dm);
struct MEdge *CDDM_get_edges(struct DerivedMesh *dm);
-struct MFace *CDDM_get_faces(struct DerivedMesh *dm);
+struct MFace *CDDM_get_tessfaces(struct DerivedMesh *dm);
+struct MLoop *CDDM_get_loops(struct DerivedMesh *dm);
+struct MPoly *CDDM_get_polys(struct DerivedMesh *dm);
+
+/*Assigns news m*** layers to the cddm. Note that you must handle
+ freeing the old ones yourself. Also you must ensure dm->num****Data
+ is correct.*/
+void CDDM_set_mvert(struct DerivedMesh *dm, struct MVert *mvert);
+void CDDM_set_medge(struct DerivedMesh *dm, struct MEdge *medge);
+void CDDM_set_mface(struct DerivedMesh *dm, struct MFace *mface);
+void CDDM_set_mloop(struct DerivedMesh *dm, struct MLoop *mloop);
+void CDDM_set_mpoly(struct DerivedMesh *dm, struct MPoly *mpoly);
+
#endif
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 7254536b555..36c442741ec 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -267,6 +267,24 @@ struct bPoseChannel *CTX_data_active_pose_bone(const bContext *C);
int CTX_data_selected_pose_bones(const bContext *C, ListBase *list);
int CTX_data_visible_pose_bones(const bContext *C, ListBase *list);
+//stupid compiler flag isn't working
+//remember to undef this later
+#ifndef EVENT_RECORDER
+#define EVENT_RECORDER
+#endif
+
+#ifdef EVENT_RECORDER
+#include <stdio.h>
+
+int CTX_rec_events(bContext *C);
+FILE *CTX_rec_file(bContext *C);
+int CTX_set_events_path(bContext *C, char *path);
+int CTX_play_events(bContext *C, char **playpath);
+int CTX_rec_events_set(bContext *C, int state);
+double CTX_rec_lasttime(bContext *C, double newtime);
+
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index c30100ea55a..319519cf363 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -40,11 +40,15 @@
extern "C" {
#endif
+struct BMesh;
struct ID;
struct CustomData;
struct CustomDataLayer;
typedef unsigned int CustomDataMask;
+/*a data type large enough to hold 1 element from any customdata layer type*/
+typedef struct {unsigned char data[64];} CDBlockBytes;
+
extern const CustomDataMask CD_MASK_BAREMESH;
extern const CustomDataMask CD_MASK_MESH;
extern const CustomDataMask CD_MASK_EDITMESH;
@@ -67,6 +71,25 @@ extern const CustomDataMask CD_MASK_FACECORNERS;
#define CD_DUPLICATE 4 /* do a full copy of all layers, only allowed if source
has same number of elements */
+/* Checks if the layer at physical offset layern (in data->layers) support math
+ * the below operations.
+ */
+int CustomData_layer_has_math(struct CustomData *data, int layern);
+
+/*copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
+ another, while not overwriting anything else (e.g. flags). probably only
+ implemented for mloopuv/mloopcol, for now.*/
+void CustomData_data_copy_value(int type, void *source, void *dest);
+
+/* compares if data1 is equal to data2. type is a valid CustomData type
+ * enum (e.g. CD_MLOOPUV). the layer type's equal function is used to compare
+ * the data, if it exists, otherwise memcmp is used.*/
+int CustomData_data_equals(int type, void *data1, void *data2);
+void CustomData_data_initminmax(int type, void *min, void *max);
+void CustomData_data_dominmax(int type, void *data, void *min, void *max);
+void CustomData_data_multiply(int type, void *data, float fac);
+void CustomData_data_add(int type, void *data1, void *data2);
+
/* initialises a CustomData object with the same layer setup as source.
* mask is a bitfield where (mask & (1 << (layer type))) indicates
* if a layer should be copied or not. alloctype must be one of the above. */
@@ -78,6 +101,12 @@ void CustomData_copy(const struct CustomData *source, struct CustomData *dest,
void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
CustomDataMask mask, int alloctype, int totelem);
+/*bmesh version of CustomData_merge; merges the layouts of source and dest,
+ then goes through the mesh and makes sure all the customdata blocks are
+ consistent with the new layout.*/
+void CustomData_bmesh_merge(struct CustomData *source, struct CustomData *dest,
+ int mask, int alloctype, struct BMesh *bm, int type);
+
/* frees data associated with a CustomData object (doesn't free the object
* itself, though)
*/
@@ -142,12 +171,13 @@ void CustomData_set_only_copy(const struct CustomData *data,
void CustomData_copy_data(const struct CustomData *source,
struct CustomData *dest, int source_index,
int dest_index, int count);
+void CustomData_copy_elements(int type, void *source, void *dest, int count);
void CustomData_em_copy_data(const struct CustomData *source,
struct CustomData *dest, void *src_block,
void **dest_block);
void CustomData_bmesh_copy_data(const struct CustomData *source,
- struct CustomData *dest,void *src_block,
- void **dest_block);
+ struct CustomData *dest, void *src_block,
+ void **dest_block);
void CustomData_em_validate_data(struct CustomData *data, void *block, int sub_elements);
/* frees data in a CustomData object
@@ -189,11 +219,16 @@ void CustomData_swap(struct CustomData *data, int index, const int *corner_indic
* returns NULL if there is no layer of type
*/
void *CustomData_get(const struct CustomData *data, int index, int type);
+void *CustomData_get_n(const struct CustomData *data, int type, int index, int n);
void *CustomData_em_get(const struct CustomData *data, void *block, int type);
void *CustomData_em_get_n(const struct CustomData *data, void *block, int type, int n);
void *CustomData_bmesh_get(const struct CustomData *data, void *block, int type);
void *CustomData_bmesh_get_n(const struct CustomData *data, void *block, int type, int n);
+/* gets the layer at physical index n, with no type checking.
+ */
+void *CustomData_bmesh_get_layer_n(const struct CustomData *data, void *block, int n);
+
/* gets a pointer to the active or first layer of type
* returns NULL if there is no layer of type
*/
@@ -201,8 +236,8 @@ void *CustomData_get_layer(const struct CustomData *data, int type);
void *CustomData_get_layer_n(const struct CustomData *data, int type, int n);
void *CustomData_get_layer_named(const struct CustomData *data, int type,
const char *name);
-
int CustomData_get_layer_index(const struct CustomData *data, int type);
+int CustomData_get_layer_index_n(const struct CustomData *data, int type, int n);
int CustomData_get_named_layer_index(const struct CustomData *data, int type, const char *name);
int CustomData_get_active_layer_index(const struct CustomData *data, int type);
int CustomData_get_render_layer_index(const struct CustomData *data, int type);
@@ -229,6 +264,11 @@ void CustomData_bmesh_set(const struct CustomData *data, void *block, int type,
void CustomData_bmesh_set_n(struct CustomData *data, void *block, int type, int n,
void *source);
+/*sets the data of the block at physical layer n. no real type checking
+ *is performed.
+ */
+void CustomData_bmesh_set_layer_n(struct CustomData *data, void *block, int n,
+ void *source);
/* set the pointer of to the first layer of type. the old data is not freed.
* returns the value of ptr if the layer is found, NULL otherwise
@@ -285,7 +325,8 @@ void CustomData_set_layer_unique_name(struct CustomData *data, int index);
int CustomData_verify_versions(struct CustomData *data, int index);
/*BMesh specific customdata stuff*/
-void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata);
+void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata,
+ struct CustomData *ldata, int totloop, int totpoly);
void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata, int total);
void CustomData_bmesh_init_pool(struct CustomData *data, int allocsize);
diff --git a/source/blender/blenkernel/BKE_idcode.h b/source/blender/blenkernel/BKE_idcode.h
index 1b2b3d2ee95..1b2b3d2ee95 100644..100755
--- a/source/blender/blenkernel/BKE_idcode.h
+++ b/source/blender/blenkernel/BKE_idcode.h
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index c29320ef13c..aeaf17bec27 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -50,8 +50,10 @@ extern "C" {
#endif
void free_key(struct Key *sc);
+void free_key_nolib(struct Key *key);
struct Key *add_key(struct ID *id);
struct Key *copy_key(struct Key *key);
+struct Key *copy_key_nolib(struct Key *key);
void make_local_key(struct Key *key);
void sort_keys(struct Key *key);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 0f5780ed5b0..7dc1172d32e 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -40,12 +40,15 @@
struct BoundBox;
struct DispList;
struct ListBase;
-struct EditMesh;
-struct MDeformVert;
+struct BMEditMesh;
+struct BMesh;
struct Mesh;
+struct MPoly;
+struct MLoop;
struct MFace;
struct MEdge;
struct MVert;
+struct MDeformVert;
struct MCol;
struct Object;
struct MTFace;
@@ -60,12 +63,39 @@ extern "C" {
struct EditMesh *BKE_mesh_get_editmesh(struct Mesh *me);
void BKE_mesh_end_editmesh(struct Mesh *me, struct EditMesh *em);
+struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob);
+
+/*
+ this function recreates a tesselation.
+ returns number of tesselation faces.
+
+ use_poly_origindex sets whether or not the tesselation faces' origindex
+ layer should point to original poly indices or real poly indices.
+
+ use_face_origindex sets the tesselation faces' origindex layer
+ to point to the tesselation faces themselves, not the polys.
+
+ if both of the above are 0, it'll use the indices of the mpolys of the MPoly
+ data in pdata, and ignore the origindex layer altogether.
+ */
+int mesh_recalcTesselation(struct CustomData *fdata, struct CustomData *ldata,
+ struct CustomData *pdata, struct MVert *mvert, int totface,
+ int totloop, int totpoly, int use_poly_origindex, int use_face_origindex);
+
+/*calculates a face normal.*/
+void mesh_calc_poly_normal(struct MPoly *mpoly, struct MLoop *loopstart,
+ struct MVert *mvarray, float *no);
void unlink_mesh(struct Mesh *me);
-void free_mesh(struct Mesh *me);
+void free_mesh(struct Mesh *me, int unlink);
struct Mesh *add_mesh(const char *name);
struct Mesh *copy_mesh(struct Mesh *me);
void mesh_update_customdata_pointers(struct Mesh *me);
+
+/*this ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or
+ mloopcol and mcol) have the same relative active/render/clone/mask indices.*/
+void mesh_update_linked_customdata(struct Mesh *me);
+
void make_local_tface(struct Mesh *me);
void make_local_mesh(struct Mesh *me);
void boundbox_mesh(struct Mesh *me, float *loc, float *size);
@@ -88,6 +118,12 @@ void copy_dverts(struct MDeformVert *dst, struct MDeformVert *src, int totvert);
void mesh_delete_material_index(struct Mesh *me, int index);
void mesh_set_smooth_flag(struct Object *meshOb, int enableSmooth);
+/*used for unit testing; compares two meshes, checking only
+ differences we care about. should be usable with leaf's
+ testing framework I get RNA work done, will use hackish
+ testing code for now.*/
+char *mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh);
+
struct BoundBox *mesh_get_bb(struct Object *ob);
void mesh_get_texspace(struct Mesh *me, float *loc_r, float *rot_r, float *size_r);
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index af625ae9d9c..5f6120509f0 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -47,6 +47,7 @@ struct ListBase;
struct LinkNode;
struct bArmature;
struct ModifierData;
+struct BMEditMesh;
typedef enum {
/* Should not be used, only for None modifier type */
@@ -147,13 +148,13 @@ typedef struct ModifierTypeInfo {
*/
void (*deformVertsEM)(
struct ModifierData *md, struct Object *ob,
- struct EditMesh *editData, struct DerivedMesh *derivedData,
+ struct BMEditMesh *editData, struct DerivedMesh *derivedData,
float (*vertexCos)[3], int numVerts);
/* Set deform matrix per vertex for crazyspace correction */
void (*deformMatricesEM)(
struct ModifierData *md, struct Object *ob,
- struct EditMesh *editData, struct DerivedMesh *derivedData,
+ struct BMEditMesh *editData, struct DerivedMesh *derivedData,
float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
/********************* Non-deform modifier functions *********************/
@@ -191,7 +192,7 @@ typedef struct ModifierTypeInfo {
*/
struct DerivedMesh *(*applyModifierEM)(
struct ModifierData *md, struct Object *ob,
- struct EditMesh *editData,
+ struct BMEditMesh *editData,
struct DerivedMesh *derivedData);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 238c812906d..e6caae7a954 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -90,7 +90,7 @@ typedef struct SculptSession {
/* Partial redraw */
int partial_redraw;
-
+
/* Used to cache the render of the active texture */
unsigned int texcache_side, *texcache, texcache_actual;
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index b82db853d37..3394d5b7bf6 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -47,6 +47,10 @@ struct _CCGEdge;
struct _CCGFace;
struct _CCGSubsurf;
struct _CCGVert;
+struct EdgeHash;
+struct PBVH;
+struct DMGridData;
+struct DMGridAdjacency;
/**************************** External *****************************/
@@ -75,6 +79,8 @@ typedef struct CCGDerivedMesh {
short *edgeFlags;
char *faceFlags;
+ int *reverseFaceMap;
+
struct PBVH *pbvh;
struct ListBase *fmap;
struct IndexNode *fmap_mem;
@@ -96,6 +102,8 @@ typedef struct CCGDerivedMesh {
void (*update)(DerivedMesh*);
} multires;
+
+ struct EdgeHash *ehash;
} CCGDerivedMesh;
#endif
diff --git a/source/blender/blenkernel/BKE_tessmesh.h b/source/blender/blenkernel/BKE_tessmesh.h
new file mode 100644
index 00000000000..f2827747555
--- /dev/null
+++ b/source/blender/blenkernel/BKE_tessmesh.h
@@ -0,0 +1,72 @@
+#ifndef _BKE_TESSMESH_H
+#define _BKE_TESSMESH_H
+
+#include "bmesh.h"
+
+struct BMesh;
+struct BMLoop;
+struct BMFace;
+struct Mesh;
+struct DerivedMesh;
+
+/*
+ok: the EDBM module is for editmode bmesh stuff. in contrast, the
+ BMEdit module is for code shared with blenkernel that concerns
+ the BMEditMesh structure.
+*/
+
+/*this structure replaces EditMesh.
+
+ through this, you get access to both the edit bmesh,
+ it's tesselation, and various stuff that doesn't belong in the BMesh
+ struct itself.
+
+ the entire derivedmesh and modifier system works with this structure,
+ and not BMesh. Mesh->edit_bmesh stores a pointer to this structure.*/
+typedef struct BMEditMesh {
+ struct BMesh *bm;
+
+ /*this is for undoing failed operations*/
+ struct BMEditMesh *emcopy;
+ int emcopyusers;
+
+ /*we store tesselations as triplets of three loops,
+ which each define a triangle.*/
+ struct BMLoop *(*looptris)[3];
+ int tottri;
+
+ /*derivedmesh stuff*/
+ struct DerivedMesh *derivedFinal, *derivedCage;
+ int lastDataMask;
+
+ /*retopo data pointer*/
+ struct RetopoPaintData *retopo_paint_data;
+
+ /*index tables, to map indices to elements via
+ EDBM_init_index_arrays and associated functions. don't
+ touch this or read it directly.*/
+ struct BMVert **vert_index;
+ struct BMEdge **edge_index;
+ struct BMFace **face_index;
+
+ /*selection mode*/
+ int selectmode;
+
+ int mat_nr;
+
+ /*Mesh structure this editmesh came from, if it came from one*/
+ struct Mesh *me;
+ struct Object *ob;
+
+ /*temp variables for x-mirror editing*/
+ int mirror_cdlayer;
+ int mirr_free_arrays;
+} BMEditMesh;
+
+void BMEdit_RecalcTesselation(BMEditMesh *tm);
+BMEditMesh *BMEdit_Create(BMesh *bm);
+BMEditMesh *BMEdit_Copy(BMEditMesh *tm);
+void BMEdit_Free(BMEditMesh *em);
+void BMEdit_UpdateLinkedCustomData(BMEditMesh *em);
+
+#endif /* _BKE_TESSMESH_H */ \ No newline at end of file
diff --git a/source/blender/blenkernel/BKE_utildefines.h b/source/blender/blenkernel/BKE_utildefines.h
index 14e622c972e..0e2817365f8 100644
--- a/source/blender/blenkernel/BKE_utildefines.h
+++ b/source/blender/blenkernel/BKE_utildefines.h
@@ -37,6 +37,10 @@
#ifndef BKE_UTILDEFINES_H
#define BKE_UTILDEFINES_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* these values need to be hardcoded in structs, dna does not recognize defines */
/* also defined in DNA_space_types.h */
#ifndef FILE_MAXDIR
@@ -83,5 +87,16 @@
#define BROW(min, max) (((max)>=31? 0xFFFFFFFF: (1<<(max+1))-1) - ((min)? ((1<<(min))-1):0) )
#define BMEMSET(mem, val, size) {unsigned int _i; char *_c = (char*) mem; for (_i=0; _i<size; _i++) *_c++ = val;}
+/*little macro so inline keyword works*/
+#if defined(_MSC_VER)
+#define BM_INLINE static __forceinline
+#else
+#define BM_INLINE static inline __attribute((always_inline))
+#endif
+
+#ifdef __cplusplus
+}
+#endif
#endif // BKE_UTILDEFINES_H
+
diff --git a/source/blender/blenkernel/BKE_verse.h b/source/blender/blenkernel/BKE_verse.h
new file mode 100644
index 00000000000..ee22081b03f
--- /dev/null
+++ b/source/blender/blenkernel/BKE_verse.h
@@ -0,0 +1,586 @@
+/**
+ * $Id: BKE_verse.h 12931 2007-12-17 18:20:48Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* #define WITH_VERSE */
+
+#ifndef BKE_VERSE_H
+#define BKE_VERSE_H
+
+#include "DNA_listBase.h"
+#include "BLI_dynamiclist.h"
+
+#include "verse.h"
+#include "verse_ms.h"
+
+struct VNode;
+struct VerseEdge;
+
+/*
+ * Verse Edge Hash (similar to edit edge hash)
+ */
+#define VEDHASHSIZE (512*512)
+#define VEDHASH(a, b) ((a<b ? a : b) % VEDHASHSIZE)
+
+/*
+ * verse data: 4 float value
+ */
+typedef struct quat_real32_item {
+ struct quat_real32_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ real32 value[4];
+} quat_real32_item;
+
+/*
+ * verse data: 4 uint32 values
+ */
+typedef struct quat_uint32_item {
+ struct quat_uint32_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ uint32 value[4];
+} quat_uint32_item;
+
+/*
+ * verse data: 3 float values
+ */
+typedef struct vec_real32_item {
+ struct vec_real32_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ real32 value[3];
+} vec_real32_item;
+
+/*
+ * verse data: float value (weight)
+ */
+typedef struct real32_item {
+ struct real32_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ real32 value;
+} real32_item;
+
+/*
+ * verse data: uint32 value
+ */
+typedef struct uint32_item {
+ struct uint32_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ uint32 value;
+} uint32_item;
+
+/*
+ * verse data: uint8 value
+ */
+typedef struct uint8_item {
+ struct uint8_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ uint8 value;
+} uint8_item;
+
+/*
+ * verse data: vertex
+ */
+typedef struct VerseVert {
+ struct VerseVert *next, *prev;
+ /* verse data */
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of vertex */
+ real32 co[3]; /* x,y,z-coordinates of vertex */
+ real32 no[3]; /* normal of vertex */
+ /* blender internals */
+ short flag; /* flags: VERT_DELETED, VERT_RECEIVED, etc. */
+ void *vertex; /* pointer at EditVert or MVert */
+ int counter; /* counter of VerseFaces using this VerseVert */
+ union {
+ unsigned int index; /* counter need during transformation to mesh */
+ struct VerseVert *vvert;
+ } tmp; /* pointer at new created verse vert, it is
+ * used during duplicating geometry node */
+ float *cos; /* modified coordinates of vertex */
+ float *nos; /* modified normal vector */
+} VerseVert;
+
+/*
+ * structture used for verse edge hash
+ */
+typedef struct HashVerseEdge {
+ struct VerseEdge *vedge;
+ struct HashVerseEdge *next;
+} HashVerseEdge;
+
+/*
+ * fake verse data: edge
+ */
+typedef struct VerseEdge {
+ struct VerseEdge *next, *prev;
+ uint32 v0, v1; /* indexes of verse vertexes */
+ int counter; /* counter of verse faces using this edge */
+ struct HashVerseEdge hash; /* hash table */
+ union {
+ unsigned int index; /* temporary index of edge */
+ } tmp;
+} VerseEdge;
+
+/*
+ * verse data: polygon
+ */
+typedef struct VerseFace {
+ struct VerseFace *next, *prev;
+ /* verse data */
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of face */
+ struct VerseVert *vvert0; /* pointer at 1st VerseVert */
+ struct VerseVert *vvert1; /* pointer at 2nd VerseVert */
+ struct VerseVert *vvert2; /* pointer at 3th VerseVert */
+ struct VerseVert *vvert3; /* pointer at 4th VerseVert */
+ unsigned int v0, v1, v2, v3; /* indexes of VerseVerts ... needed during receiving */
+ /* blender internals */
+ char flag; /* flags: FACE_SEND_READY, FACE_SENT, FACE_RECEIVED, FACE_CHANGED*/
+ short counter; /* counter of missed VerseVertexes */
+ void *face; /* pointer at EditFace */
+ float no[3]; /* normal vector */
+ float *nos; /* modified normal vector */
+} VerseFace;
+
+/*
+ * verse data: layer
+ */
+typedef struct VLayer {
+ struct VLayer *next, *prev;
+ /* verse data*/
+ struct VNode *vnode; /* pointer at VerseNode */
+ uint16 id; /* id of layer */
+ char *name; /* name of layer */
+ VNGLayerType type; /* type of layer (VN_G_LAYER_VERTEX_XYZ, VN_G_LAYER_POLYGON_CORNER_UINT32) */
+ uint32 def_int; /* default integer value */
+ real64 def_real; /* default float value */
+ /* blender internals */
+ char flag; /* flags: LAYER_SENT, LAYER_RECEIVED, LAYER_DELETED, LAYER_OBSOLETE */
+ short content; /* type of content (VERTEX_LAYER, POLYGON_LAYER) */
+ struct DynamicList dl; /* vertexes, polygons, etc. */
+ struct ListBase queue; /* queue of vertexes, polygons, etc. waiting for sending to verse server */
+ struct ListBase orphans; /* list of versedata (polygons, etc.), that can be added to the DynamicList
+ * due to not received VerseVerts */
+ unsigned int counter; /* counter of sent items */
+ /* client dependent methods */
+ void (*post_layer_create)(struct VLayer *vlayer);
+ void (*post_layer_destroy)(struct VLayer *vlayer);
+} VLayer;
+
+/*
+ * verse data: link
+ */
+typedef struct VLink{
+ struct VLink *next, *prev;
+ /* verse data */
+ struct VerseSession *session; /* session pointer */
+ struct VNode *source; /* object VerseNode "pointing" at some other VerseNode */
+ struct VNode *target; /* VerseNode linked with some object node */
+ unsigned int id; /* id of VerseLink */
+ unsigned int target_id; /* some unknow id */
+ char *label; /* name/label of VerseLink */
+ /* blender internals */
+ char flag; /* flags: LINK_SEND_READY */
+ /* client dependent methods */
+ void (*post_link_set)(struct VLink *vlink);
+ void (*post_link_destroy)(struct VLink *vlink);
+} VLink;
+
+/*
+ * bitmap layer
+ */
+typedef struct VBitmapLayer {
+ struct VBitmapLayer *next, *prev;
+ /* verse data */
+ struct VNode *vnode; /* pointer at Verse Node */
+ VLayerID id; /* id of layer */
+ char *name; /* name of layer */
+ VNBLayerType type; /* type of layer (bits per channel) 1, 8, 16, 32, 64 */
+ void *data; /* dynamic allocated data */
+ /* blender internals */
+ char flag;
+} VBitmapLayer;
+
+/*
+ * data of bitmap node
+ */
+typedef struct VBitmapData {
+ struct DynamicList layers; /* dynamic list with access array of bitmap layers */
+ struct ListBase queue; /* queue of layers waiting for receiving from verse server */
+ uint16 width; /* width of all verse layers */
+ uint16 height; /* height of all verse layers */
+ uint16 depth; /* depth of bitmap 1 is 2D bitmap, >1 is 3D bitmap */
+ /* blender internals */
+ uint16 t_width; /* = (width/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE */
+ uint16 t_height; /* = (height/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE */
+ void *image; /* pointer at image */
+ /* client dependent methods */
+ void (*post_bitmap_dimension_set)(struct VNode *vnode);
+ void (*post_bitmap_layer_create)(struct VBitmapLayer *vblayer);
+ void (*post_bitmap_layer_destroy)(struct VBitmapLayer *vblayer);
+ void (*post_bitmap_tile_set)(struct VBitmapLayer *vblayer, unsigned int xs, unsigned int ys);
+}VBitmapData;
+
+/*
+ * data of geometry node
+ */
+typedef struct VGeomData {
+ struct DynamicList layers; /* dynamic list with access array of Layers */
+ struct VLink *vlink; /* pointer at VerseLink connecting object node and geom node */
+ struct ListBase queue; /* queue of our layers waiting for receiving from verse server */
+ void *mesh; /* pointer at Mesh (object node) */
+ void *editmesh; /* pointer at EditMesh (edit mode) */
+ struct HashVerseEdge *hash; /* verse edge hash */
+ struct ListBase edges; /* list of fake verse edges */
+ /* client dependent methods */
+ void (*post_vertex_create)(struct VerseVert *vvert);
+ void (*post_vertex_set_xyz)(struct VerseVert *vvert);
+ void (*post_vertex_delete)(struct VerseVert *vvert);
+ void (*post_vertex_free_constraint)(struct VerseVert *vvert);
+ void (*post_polygon_create)(struct VerseFace *vface);
+ void (*post_polygon_set_corner)(struct VerseFace *vface);
+ void (*post_polygon_delete)(struct VerseFace *vface);
+ void (*post_polygon_free_constraint)(struct VerseFace *vface);
+ void (*post_geometry_free_constraint)(struct VNode *vnode);
+ void (*post_polygon_set_uint8)(struct VerseFace *vface);
+} VGeomData;
+
+/*
+ * data of object node
+ */
+typedef struct VObjectData {
+ struct DynamicList links; /* dynamic list with access array of links between other nodes */
+ struct ListBase queue; /* queue of links waiting for sending and receiving from verse server */
+ float pos[3]; /* position of object VerseNode */
+ float quat[4]; /* rotation of object VerseNode stored in quat */
+ float scale[3]; /* scale of object VerseNode */
+ void *object; /* pointer at object */
+ short flag; /* flag: POS_RECEIVE_READY, ROT_RECEIVE_READY. SCALE_RECEIVE_READY */
+ /* client dependent methods */
+/* void (*post_transform)(struct VNode *vnode);*/
+ void (*post_transform_pos)(struct VNode *vnode);
+ void (*post_transform_rot)(struct VNode *vnode);
+ void (*post_transform_scale)(struct VNode *vnode);
+ void (*post_object_free_constraint)(struct VNode *vnode);
+} VObjectData;
+
+/*
+ * Verse Tag
+ */
+typedef struct VTag {
+ struct VTag *next, *prev;
+ /* verse data*/
+ struct VTagGroup *vtaggroup; /* pointer at Verse Tag Group */
+ uint16 id; /* id of this tag */
+ char *name; /* name of this tag*/
+ VNTagType type; /* type: VN_TAG_BOOLEAN, VN_TAG_UINT32, VN_TAG_REAL64, VN_TAG_REAL64_VEC3,
+ VN_TAG_LINK, VN_TAG_ANIMATION, VN_TAG_BLOB */
+ VNTag *tag; /* pointer at value (enum: vboolean, vuint32, vreal64, vstring,
+ vreal64_vec3, vlink, vanimation, vblob)*/
+ /* blender internals */
+ void *value; /* pointer at blender value */
+} VTag;
+
+/*
+ * Verse Tag Group (verse tags are grouped in tag groups)
+ */
+typedef struct VTagGroup {
+ struct VTagGroup *next, *prev;
+ /* verse data*/
+ struct VNode *vnode; /* pointer at Verse Node */
+ uint16 id; /* id of this tag group */
+ char *name; /* name of this tag group */
+ /* blender internals */
+ struct DynamicList tags; /* dynamic list with access array containing tags */
+ struct ListBase queue; /* list of tags waiting for receiving from verse server */
+ /* client dependent methods */
+ void (*post_tag_change)(struct VTag *vatg);
+ void (*post_taggroup_create)(struct VTagGroup *vtaggroup);
+} VTagGroup;
+
+ /*
+ * Verse Method Group
+ */
+typedef struct VMethodGroup
+{
+ struct VMethodGroup *next, *prev;
+ uint16 group_id;
+ char name[16];
+ struct ListBase methods;
+} VMethodGroup;
+
+/*
+ * Verse Method
+ */
+typedef struct VMethod
+{
+ struct VMethod *next, *prev;
+ uint16 id;
+ char name[500];
+ uint8 param_count;
+ VNOParamType *param_type;
+ char **param_name;
+} VMethod;
+
+/*
+ * Verse Node
+ */
+typedef struct VNode {
+ struct VNode *next, *prev;
+ /* verse data*/
+ struct VerseSession *session; /* session pointer */
+ VNodeID id; /* node id */
+ VNodeID owner_id; /* owner's id of this node */
+ char *name; /* name of this node */
+ uint32 type; /* type of node (V_NT_OBJECT, V_NT_GEOMETRY, V_NT_BITMAP) */
+ /* blender internals */
+ char flag; /* flags: NODE_SENT, NODE_RECEIVED, NODE_DELTED, NODE_OBSOLETE */
+ struct DynamicList taggroups; /* dynamic list with access array of taggroups */
+ struct ListBase methodgroups; /* method groups */
+ struct ListBase queue; /* list of taggroups waiting for receiving from verse server */
+ void *data; /* generic pointer at some data (VObjectData, VGeomData, ...) */
+ int counter; /* counter of verse link pointing at this vnode (vlink->target) */
+ /* client dependent methods */
+ void (*post_node_create)(struct VNode *vnode);
+ void (*post_node_destroy)(struct VNode *vnode);
+ void (*post_node_name_set)(struct VNode *vnode);
+#ifdef VERSECHAT
+ /* verse chat */
+ int chat_flag; /* CHAT_LOGGED, CHAT_NOTLOGGED */
+#endif
+} VNode;
+
+
+/*
+ * Verse Session: verse client can be connected to several verse servers
+ * it is neccessary to store some information about each session
+ */
+typedef struct VerseSession {
+ struct VerseSession *next, *prev;
+ /* verse data */
+ VSession *vsession; /* pointer at VSeesion (verse.h) */
+ uint32 avatar; /* id of avatar */
+ char *address; /* string containg IP/domain name of verse server and number of port */
+ void *connection; /* no clue */
+ uint8 *host_id; /* no clue */
+ /* blender internals */
+ short flag; /* flag: VERSE_CONNECTING, VERSE_CONNECTED */
+ DynamicList nodes; /* list of verse nodes */
+ ListBase queue; /* list of nodes waiting for sending to verse server */
+ unsigned int counter; /* count of events, when connection wasn't accepted */
+ /* client dependent methods */
+ void (*post_connect_accept)(struct VerseSession *session);
+ void (*post_connect_terminated)(struct VerseSession *session);
+ void (*post_connect_update)(struct VerseSession *session);
+} VerseSession;
+
+typedef struct VerseServer {
+ struct VerseServer *next, *prev;
+ char *name; /* human-readable server name */
+ char *ip; /* string containing IP/domain name of verse server and number of port */
+ short flag; /* flag: VERSE_CONNECTING, VERSE_CONNECTED */
+ struct VerseSession *session; /* pointer to related session */
+} VerseServer;
+/*
+ * list of post callback functions
+ */
+typedef struct PostCallbackFunction {
+ void (*function)(void *arg);
+ void *param;
+} PostCallbackFunction;
+
+/* VerseSession->flag */
+#define VERSE_CONNECTING 1
+#define VERSE_CONNECTED 2
+#define VERSE_AUTOSUBSCRIBE 4
+
+/* max VerseSession->counter value */
+#define MAX_UNCONNECTED_EVENTS 100
+
+/* VNode flags */
+#define NODE_SENT 1
+#define NODE_RECEIVED 2
+#define NODE_DELTED 4
+#define NODE_OBSOLETE 8
+
+#ifdef VERSECHAT
+#define CHAT_NOTLOGGED 0
+#define CHAT_LOGGED 1
+#endif
+
+/* VLayer flags */
+#define LAYER_SENT 1
+#define LAYER_RECEIVED 2
+#define LAYER_DELETED 4
+#define LAYER_OBSOLETE 8
+
+/* VLink->flag */
+#define LINK_SEND_READY 1
+
+/* VObjectData->flag */
+#define POS_RECEIVE_READY 1
+#define ROT_RECEIVE_READY 2
+#define SCALE_RECEIVE_READY 4
+#define POS_SEND_READY 8
+#define ROT_SEND_READY 16
+#define SCALE_SEND_READY 32
+
+/* VLayer->content */
+#define VERTEX_LAYER 0
+#define POLYGON_LAYER 1
+
+/* VerseVert->flag */
+#define VERT_DELETED 1 /* vertex delete command was received from verse server */
+#define VERT_RECEIVED 2 /* VerseVert was received from verse server (is not in sending queue) */
+#define VERT_LOCKED 4 /* VerseVert is ready to send local position to verse server */
+#define VERT_POS_OBSOLETE 8 /* position of vertex was changed during sending to verse server */
+#define VERT_OBSOLETE 16 /* vertex delete command was sent to verse server; it means, that
+ * no information related to this vertex shoudln't be sent to verse
+ * until verse vertex is completely deleted ... then this vertex id
+ * can be reused again for new vertex */
+
+/* VerseFace->flag */
+#define FACE_SEND_READY 1 /* VerseFace is ready for sending to verse server */
+#define FACE_RECEIVED 2 /* VerseFace was received from verse server */
+#define FACE_SENT 4 /* VerseFace was sent to verse server and we expect receiving from verse server */
+#define FACE_DELETED 8 /* delete command was sent to verse server */
+#define FACE_CHANGED 16 /* VerseFace was only changed not created */
+#define FACE_OBSOLETE 32 /* VerseFace was changed during sending to verse server */
+
+/* Queue type */
+#define VERSE_NODE 1
+#define VERSE_LINK 2
+#define VERSE_LAYER 3
+#define VERSE_VERT 4
+#define VERSE_FACE 5
+
+#define VERSE_TAG 6
+#define VERSE_TAG_GROUP 7
+
+#define VERSE_VERT_UINT32 8
+#define VERSE_VERT_REAL32 9
+#define VERSE_VERT_VEC_REAL32 10
+
+#define VERSE_FACE_UINT8 11
+#define VERSE_FACE_UINT32 12
+#define VERSE_FACE_REAL32 13
+#define VERSE_FACE_QUAT_UINT32 14
+#define VERSE_FACE_QUAT_REAL32 15
+
+/* Verse Bitmap Layer flags */
+#define VBLAYER_SUBSCRIBED 1
+
+/* function prototypes */
+
+/* functions from verse_session.c */
+void set_verse_session_callbacks(void);
+struct VerseSession *versesession_from_vsession(VSession *vsession);
+struct VerseSession *current_verse_session(void);
+struct VerseSession *create_verse_session(const char *name, const char *pass, const char *address, uint8 *expected_key);
+void free_verse_session(struct VerseSession *session);
+void b_verse_update(void);
+void b_verse_ms_get(void);
+void b_verse_connect(char *address);
+void end_verse_session(struct VerseSession *session);
+void end_all_verse_sessions(void);
+
+/* functions from verse_node.c */
+void send_verse_tag(struct VTag *vtag);
+void send_verse_taggroup(struct VTagGroup *vtaggroup);
+void send_verse_node(struct VNode *vnode);
+void free_verse_node_data(struct VNode *vnode);
+void free_verse_node(struct VNode *vnode);
+struct VNode* lookup_vnode(VerseSession *session, VNodeID node_id);
+struct VNode* create_verse_node(VerseSession *session, VNodeID node_id, uint8 type, VNodeID owner_id);
+void set_node_callbacks(void);
+
+/* functions from verse_object_node.c */
+struct VLink *find_unsent_parent_vlink(struct VerseSession *session, struct VNode *vnode);
+struct VLink *find_unsent_child_vlink(struct VerseSession *session, struct VNode *vnode);
+struct VLink *create_verse_link(VerseSession *session, struct VNode *source, struct VNode *target, uint16 link_id, uint32 target_id, const char *label);
+void send_verse_object_position(struct VNode *vnode);
+void send_verse_object_rotation(struct VNode *vnode);
+void send_verse_object_scale(struct VNode *vnode);
+void send_verse_link(struct VLink *vlink);
+
+void free_object_data(struct VNode *vnode);
+void set_object_callbacks(void);
+struct VObjectData *create_object_data(void);
+
+
+/* functions from verse_method.c */
+void free_verse_methodgroup(VMethodGroup *vmg);
+#ifdef VERSECHAT
+void send_say(const char *chan, const char *utter);
+void send_login(struct VNode *vnode);
+void send_logout(struct VNode *vnode);
+void send_join(struct VNode *vnode, const char *chan);
+void send_leave(struct VNode *vnode, const char *chan);
+#endif
+void set_method_callbacks(void);
+
+/* functions from verse_geometry_node.c */
+struct VerseFace* create_verse_face(struct VLayer *vlayer, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+struct VerseVert* create_verse_vertex(struct VLayer *vlayer, uint32 vertex_id, real32 x, real32 y, real32 z);
+struct VLayer *create_verse_layer(struct VNode *vnode, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_integer, real64 def_real);
+struct VGeomData *create_geometry_data(void);
+
+void send_verse_layer(struct VLayer *vlayer);
+
+void send_verse_face_corner_quat_real32(struct quat_real32_item *item, short type);
+void send_verse_face_corner_quat_uint32(struct quat_uint32_item *item, short type);
+void send_verse_face_real32(struct real32_item *item, short type);
+void send_verse_face_uint32(struct uint32_item *item, short type);
+void send_verse_face_uint8(struct uint8_item *item, short type);
+
+void send_verse_vert_vec_real32(struct vec_real32_item *item, short type);
+void send_verse_vert_real32(struct real32_item *item, short type);
+void send_verse_vert_uint32(struct uint32_item *item, short type);
+
+void send_verse_vertex_delete(struct VerseVert *vvert);
+void send_verse_vertex(struct VerseVert *vvert);
+void send_verse_face_delete(struct VerseFace *vface);
+
+void destroy_geometry(struct VNode *vnode);
+
+struct VLayer* find_verse_layer_type(struct VGeomData *geom, short content);
+void add_item_to_send_queue(struct ListBase *lb, void *item, short type);
+void free_geom_data(struct VNode *vnode);
+void set_geometry_callbacks(void);
+
+/* functions prototypes from verse_bitmap.c */
+void set_bitmap_callbacks(void);
+void free_bitmap_layer_data(struct VBitmapLayer *vblayer);
+struct VBitmapLayer *create_bitmap_layer(struct VNode *vnode, VLayerID layer_id, const char *name, VNBLayerType type);
+void free_bitmap_node_data(struct VNode *vnode);
+struct VBitmapData *create_bitmap_data(void);
+
+#endif
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index c8969f86778..dc485f5dc5f 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -34,6 +34,7 @@ set(INC
../imbuf
../makesdna
../makesrna
+ ../bmesh
../modifiers
../nodes
../editors/include
@@ -86,6 +87,7 @@ set(SRC
intern/depsgraph.c
intern/displist.c
intern/effect.c
+ intern/editderivedbmesh.c
intern/exotic.c
intern/fcurve.c
intern/fluidsim.c
@@ -108,6 +110,7 @@ set(SRC
intern/mesh.c
intern/mesh_validate.c
intern/modifier.c
+ intern/modifiers_bmesh.c
intern/multires.c
intern/nla.c
intern/node.c
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
index bef72d3bf67..33c6a170178 100644
--- a/source/blender/blenkernel/SConscript
+++ b/source/blender/blenkernel/SConscript
@@ -11,6 +11,7 @@ incs += ' #/intern/iksolver/extern ../blenloader'
incs += ' #/extern/bullet2/src'
incs += ' #/intern/opennl/extern #/intern/bsp/extern'
incs += ' ../gpu #/extern/glew/include'
+incs += ' ../bmesh'
incs += ' #/intern/smoke/extern'
incs += ' #/intern/mikktspace'
incs += ' #/intern/audaspace/intern'
diff --git a/source/blender/blenkernel/intern/BME_Customdata.c b/source/blender/blenkernel/intern/BME_Customdata.c
index d2c00d21df3..f8b432ed384 100644
--- a/source/blender/blenkernel/intern/BME_Customdata.c
+++ b/source/blender/blenkernel/intern/BME_Customdata.c
@@ -1,3 +1,5 @@
+#if 0
+/**
/*
* BME_customdata.c jan 2007
*
@@ -82,7 +84,7 @@ void BME_CD_Create(BME_CustomData *data, BME_CustomDataInit *init, int initalloc
if(data->totlayer){
/*alloc memory*/
data->layers = MEM_callocN(sizeof(BME_CustomDataLayer)*data->totlayer, "BMesh Custom Data Layers");
- data->pool = BLI_mempool_create(data->totsize, initalloc, initalloc, 0);
+ data->pool = BLI_mempool_create(data->totsize, initalloc, initalloc, 1);
/*initialize layer data*/
for(i=0; i < BME_CD_NUMTYPES; i++){
if(init->layout[i]){
@@ -195,3 +197,4 @@ void BME_CD_set_default(BME_CustomData *data, void **block)
typeInfo->set_default((char*)*block + offset, 1);
}
}
+#endif
diff --git a/source/blender/blenkernel/intern/BME_conversions.c b/source/blender/blenkernel/intern/BME_conversions.c
index 4f1102bb828..8c399e88d67 100644
--- a/source/blender/blenkernel/intern/BME_conversions.c
+++ b/source/blender/blenkernel/intern/BME_conversions.c
@@ -1,3 +1,5 @@
+#if 0
+/**
/*
* BME_mesh.c jan 2007
*
@@ -262,7 +264,7 @@ BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em) {
CustomData_copy(&em->fdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
/*copy face corner data*/
- CustomData_to_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata);
+ CustomData_to_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata, 0, 0);
/*initialize memory pools*/
CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
@@ -457,7 +459,7 @@ BME_Mesh *BME_derivedmesh_to_bmesh(DerivedMesh *dm)
CustomData_copy(&dm->faceData, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
/*copy face corner data*/
- CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata);
+ CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata, 0, 0);
/*initialize memory pools*/
CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
@@ -469,10 +471,10 @@ BME_Mesh *BME_derivedmesh_to_bmesh(DerivedMesh *dm)
totvert = dm->getNumVerts(dm);
totedge = dm->getNumEdges(dm);
- totface = dm->getNumFaces(dm);
+ totface = dm->getNumTessFaces(dm);
mvert = dm->getVertArray(dm);
medge = dm->getEdgeArray(dm);
- mface = dm->getFaceArray(dm);
+ mface = dm->getTessFaceArray(dm);
vert_array = MEM_mallocN(sizeof(*vert_array)*totvert,"BME_derivedmesh_to_bmesh BME_Vert* array");
@@ -569,7 +571,8 @@ DerivedMesh *BME_bmesh_to_derivedmesh(BME_Mesh *bm, DerivedMesh *dm)
}
/*convert back to mesh*/
- result = CDDM_from_template(dm,totvert,totedge,totface);
+ /*BMESH_TODO this should add in mloops and mpolys as well*/
+ result = CDDM_from_template(dm,totvert,totedge,totface, 0, 0);
CustomData_merge(&bm->vdata, &result->vertData, CD_MASK_BMESH, CD_CALLOC, totvert);
CustomData_merge(&bm->edata, &result->edgeData, CD_MASK_BMESH, CD_CALLOC, totedge);
CustomData_merge(&bm->pdata, &result->faceData, CD_MASK_BMESH, CD_CALLOC, totface);
@@ -612,7 +615,7 @@ DerivedMesh *BME_bmesh_to_derivedmesh(BME_Mesh *bm, DerivedMesh *dm)
}
}
if(totface){
- mface = CDDM_get_faces(result);
+ mface = CDDM_get_tessfaces(result);
origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
/*make faces*/
for(i=0,f=bm->polys.first;f;f=f->next){
@@ -641,3 +644,4 @@ DerivedMesh *BME_bmesh_to_derivedmesh(BME_Mesh *bm, DerivedMesh *dm)
BLI_edgehash_free(edge_hash, NULL);
return result;
}
+#endif
diff --git a/source/blender/blenkernel/intern/BME_eulers.c b/source/blender/blenkernel/intern/BME_eulers.c
index 9d68866bc99..6897b0c8990 100644
--- a/source/blender/blenkernel/intern/BME_eulers.c
+++ b/source/blender/blenkernel/intern/BME_eulers.c
@@ -1,3 +1,5 @@
+#if 0
+/**
/*
* BME_eulers.c jan 2007
*
@@ -126,13 +128,13 @@ BME_Edge *BME_ME(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2){
#ifndef BME_FASTEULER
/*count valance of v1*/
- if(v1->edge){
- d1 = BME_disk_getpointer(v1->edge,v1);
+ if(v1->e){
+ d1 = BME_disk_getpointer(v1->e,v1);
if(d1) valance1 = BME_cycle_length(d1);
else BME_error();
}
- if(v2->edge){
- d2 = BME_disk_getpointer(v2->edge,v2);
+ if(v2->e){
+ d2 = BME_disk_getpointer(v2->e,v2);
if(d2) valance2 = BME_cycle_length(d2);
else BME_error();
}
@@ -200,7 +202,7 @@ BME_Poly *BME_MF(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Edge **elist, int
elist[i]->eflag1 |= MF_CANDIDATE;
/*if elist[i] has a loop, count its radial length*/
- if(elist[i]->loop) elist[i]->eflag2 = BME_cycle_length(&(elist[i]->loop->radial));
+ if(elist[i]->loop) elist[i]->eflag2 = BME_cycle_length(&(elist[i]->l->radial));
else elist[i]->eflag2 = 0;
}
@@ -270,8 +272,8 @@ BME_Poly *BME_MF(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Edge **elist, int
for(i=0;i<len;i++){
curvert = vlist[i];
l = BME_create_loop(bm,curvert,NULL,f,NULL);
- if(!(f->loopbase)) f->loopbase = l;
- BME_cycle_append(f->loopbase, l);
+ if(!(f->loopbase)) f->lbase = l;
+ BME_cycle_append(f->lbase, l);
}
/*take care of edge pointers and radial cycle*/
@@ -295,7 +297,7 @@ BME_Poly *BME_MF(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Edge **elist, int
f->len = len;
/*Validation Loop cycle*/
- edok = BME_cycle_validate(len, f->loopbase);
+ edok = BME_cycle_validate(len, f->lbase);
if(!edok) BME_error();
for(i=0, l = f->loopbase; i<len; i++, l=l->next){
/*validate loop vert pointers*/
@@ -323,7 +325,7 @@ BME_Poly *BME_MF(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Edge **elist, int
*/
int BME_KV(BME_Mesh *bm, BME_Vert *v){
- if(v->edge == NULL){
+ if(v->e == NULL){
BLI_remlink(&(bm->verts), v);
BME_free_vert(bm,v);
return 1;
@@ -346,7 +348,7 @@ int BME_KE(BME_Mesh *bm, BME_Edge *e){
int edok;
/*Make sure that no faces!*/
- if(e->loop == NULL){
+ if(e->l == NULL){
BME_disk_remove_edge(e, e->v1);
BME_disk_remove_edge(e, e->v2);
@@ -382,14 +384,14 @@ int BME_KF(BME_Mesh *bm, BME_Poly *bply){
/*add validation to make sure that radial cycle is cleaned up ok*/
/*deal with radial cycle first*/
- len = BME_cycle_length(bply->loopbase);
+ len = BME_cycle_length(bply->lbase);
for(i=0, curloop=bply->loopbase; i < len; i++, curloop = curloop->next)
BME_radial_remove_loop(curloop, curloop->e);
/*now deallocate the editloops*/
for(i=0; i < len; i++){
- newbase = bply->loopbase->next;
- oldbase = bply->loopbase;
+ newbase = bply->lbase->next;
+ oldbase = bply->lbase;
BME_cycle_remove(oldbase, oldbase);
BME_free_loop(bm, oldbase);
bply->loopbase = newbase;
@@ -449,24 +451,24 @@ BME_Vert *BME_SEMV(BME_Mesh *bm, BME_Vert *tv, BME_Edge *e, BME_Edge **re){
/*add ne to tv's disk cycle*/
BME_disk_append_edge(ne, tv);
/*verify disk cycles*/
- diskbase = BME_disk_getpointer(ov->edge,ov);
+ diskbase = BME_disk_getpointer(ov->e,ov);
edok = BME_cycle_validate(valance1, diskbase);
if(!edok) BME_error();
- diskbase = BME_disk_getpointer(tv->edge,tv);
+ diskbase = BME_disk_getpointer(tv->e,tv);
edok = BME_cycle_validate(valance2, diskbase);
if(!edok) BME_error();
- diskbase = BME_disk_getpointer(nv->edge,nv);
+ diskbase = BME_disk_getpointer(nv->e,nv);
edok = BME_cycle_validate(2, diskbase);
if(!edok) BME_error();
/*Split the radial cycle if present*/
- if(e->loop){
+ if(e->l){
BME_Loop *nl,*l;
BME_CycleNode *radEBase=NULL, *radNEBase=NULL;
- int radlen = BME_cycle_length(&(e->loop->radial));
+ int radlen = BME_cycle_length(&(e->l->radial));
/*Take the next loop. Remove it from radial. Split it. Append to appropriate radials.*/
- while(e->loop){
- l=e->loop;
+ while(e->l){
+ l=e->l;
l->f->len++;
BME_radial_remove_loop(l,e);
@@ -519,17 +521,17 @@ BME_Vert *BME_SEMV(BME_Mesh *bm, BME_Vert *tv, BME_Edge *e, BME_Edge **re){
}
- e->loop = radEBase->data;
- ne->loop = radNEBase->data;
+ e->l = radEBase->data;
+ ne->l = radNEBase->data;
/*verify length of radial cycle*/
- edok = BME_cycle_validate(radlen,&(e->loop->radial));
+ edok = BME_cycle_validate(radlen,&(e->l->radial));
if(!edok) BME_error();
- edok = BME_cycle_validate(radlen,&(ne->loop->radial));
+ edok = BME_cycle_validate(radlen,&(ne->l->radial));
if(!edok) BME_error();
/*verify loop->v and loop->next->v pointers for e*/
- for(i=0,l=e->loop; i < radlen; i++, l = l->radial.next->data){
+ for(i=0,l=e->l; i < radlen; i++, l = l->radial_next){
if(!(l->e == e)) BME_error();
if(!(l->radial.data == l)) BME_error();
if(l->prev->e != ne && l->next->e != ne) BME_error();
@@ -538,11 +540,11 @@ BME_Vert *BME_SEMV(BME_Mesh *bm, BME_Vert *tv, BME_Edge *e, BME_Edge **re){
if(l->v == l->next->v) BME_error();
if(l->e == l->next->e) BME_error();
/*verify loop cycle for kloop->f*/
- edok = BME_cycle_validate(l->f->len, l->f->loopbase);
+ edok = BME_cycle_validate(l->f->len, l->f->lbase);
if(!edok) BME_error();
}
/*verify loop->v and loop->next->v pointers for ne*/
- for(i=0,l=ne->loop; i < radlen; i++, l = l->radial.next->data){
+ for(i=0,l=ne->l; i < radlen; i++, l = l->radial_next){
if(!(l->e == ne)) BME_error();
if(!(l->radial.data == l)) BME_error();
if(l->prev->e != e && l->next->e != e) BME_error();
@@ -551,7 +553,7 @@ BME_Vert *BME_SEMV(BME_Mesh *bm, BME_Vert *tv, BME_Edge *e, BME_Edge **re){
if(l->v == l->next->v) BME_error();
if(l->e == l->next->e) BME_error();
/*verify loop cycle for kloop->f. Redundant*/
- edok = BME_cycle_validate(l->f->len, l->f->loopbase);
+ edok = BME_cycle_validate(l->f->len, l->f->lbase);
if(!edok) BME_error();
}
}
@@ -596,7 +598,7 @@ BME_Poly *BME_SFME(BME_Mesh *bm, BME_Poly *f, BME_Vert *v1, BME_Vert *v2, BME_Lo
/*verify that v1 and v2 are in face.*/
- len = BME_cycle_length(f->loopbase);
+ len = BME_cycle_length(f->lbase);
for(i = 0, curloop = f->loopbase; i < len; i++, curloop = curloop->next){
if(curloop->v == v1) v1loop = curloop;
else if(curloop->v == v2) v2loop = curloop;
@@ -630,7 +632,7 @@ BME_Poly *BME_SFME(BME_Mesh *bm, BME_Poly *f, BME_Vert *v1, BME_Vert *v2, BME_Lo
/*I dont know how many loops are supposed to be in each face at this point! FIXME!*/
/*go through all of f2's loops and make sure they point to it properly.*/
- f2len = BME_cycle_length(f2->loopbase);
+ f2len = BME_cycle_length(f2->lbase);
for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = curloop->next) curloop->f = f2;
/*link up the new loops into the new edges radial*/
@@ -640,7 +642,7 @@ BME_Poly *BME_SFME(BME_Mesh *bm, BME_Poly *f, BME_Vert *v1, BME_Vert *v2, BME_Lo
f2->len = f2len;
- f1len = BME_cycle_length(f->loopbase);
+ f1len = BME_cycle_length(f->lbase);
f->len = f1len;
if(rl) *rl = f2loop;
@@ -688,7 +690,7 @@ int BME_JEKV(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv)
int len,radlen=0, halt = 0, i, valance1, valance2,edok;
if(BME_vert_in_edge(ke,kv) == 0) return 0;
- diskbase = BME_disk_getpointer(kv->edge, kv);
+ diskbase = BME_disk_getpointer(kv->e, kv);
len = BME_cycle_length(diskbase);
if(len == 2){
@@ -701,9 +703,9 @@ int BME_JEKV(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv)
else{
/*For verification later, count valance of ov and tv*/
- diskbase = BME_disk_getpointer(ov->edge, ov);
+ diskbase = BME_disk_getpointer(ov->e, ov);
valance1 = BME_cycle_length(diskbase);
- diskbase = BME_disk_getpointer(tv->edge, tv);
+ diskbase = BME_disk_getpointer(tv->e, tv);
valance2 = BME_cycle_length(diskbase);
/*remove oe from kv's disk cycle*/
@@ -718,10 +720,10 @@ int BME_JEKV(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv)
/*deal with radial cycle of ke*/
- if(ke->loop){
+ if(ke->l){
/*first step, fix the neighboring loops of all loops in ke's radial cycle*/
- radlen = BME_cycle_length(&(ke->loop->radial));
- for(i=0,killoop = ke->loop; i<radlen; i++, killoop = BME_radial_nextloop(killoop)){
+ radlen = BME_cycle_length(&(ke->l->radial));
+ for(i=0,killoop = ke->l; i<radlen; i++, killoop = BME_radial_nextloop(killoop)){
/*relink loops and fix vertex pointer*/
killoop->next->prev = killoop->prev;
killoop->prev->next = killoop->next;
@@ -729,11 +731,11 @@ int BME_JEKV(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv)
/*fix len attribute of face*/
killoop->f->len--;
- if(killoop->f->loopbase == killoop) killoop->f->loopbase = killoop->next;
+ if(killoop->f->loopbase == killoop) killoop->f->lbase = killoop->next;
}
/*second step, remove all the hanging loops attached to ke*/
- killoop = ke->loop;
- radlen = BME_cycle_length(&(ke->loop->radial));
+ killoop = ke->l;
+ radlen = BME_cycle_length(&(ke->l->radial));
/*make sure we have enough room in bm->lpar*/
if(bm->lparlen < radlen){
MEM_freeN(bm->lpar);
@@ -744,7 +746,7 @@ int BME_JEKV(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv)
i=0;
while(i<radlen){
bm->lpar[i] = killoop;
- killoop = killoop->radial.next->data;
+ killoop = killoop->radial_next;
i++;
}
i=0;
@@ -753,22 +755,22 @@ int BME_JEKV(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv)
i++;
}
/*Validate radial cycle of oe*/
- edok = BME_cycle_validate(radlen,&(oe->loop->radial));
+ edok = BME_cycle_validate(radlen,&(oe->l->radial));
}
/*Validate disk cycles*/
- diskbase = BME_disk_getpointer(ov->edge,ov);
+ diskbase = BME_disk_getpointer(ov->e,ov);
edok = BME_cycle_validate(valance1, diskbase);
if(!edok) BME_error();
- diskbase = BME_disk_getpointer(tv->edge,tv);
+ diskbase = BME_disk_getpointer(tv->e,tv);
edok = BME_cycle_validate(valance2, diskbase);
if(!edok) BME_error();
/*Validate loop cycle of all faces attached to oe*/
- for(i=0,nextl = oe->loop; i<radlen; i++, nextl = BME_radial_nextloop(nextl)){
- edok = BME_cycle_validate(nextl->f->len,nextl->f->loopbase);
+ for(i=0,nextl = oe->l; i<radlen; i++, nextl = BME_radial_nextloop(nextl)){
+ edok = BME_cycle_validate(nextl->f->len,nextl->f->lbase);
if(!edok) BME_error();
}
/*deallocate edge*/
@@ -898,8 +900,8 @@ BME_Poly *BME_JFKE(BME_Mesh *bm, BME_Poly *f1, BME_Poly *f2, BME_Edge *e)
if(f1 == f2) return NULL; //can't join a face to itself
/*verify that e is in both f1 and f2*/
- f1len = BME_cycle_length(f1->loopbase);
- f2len = BME_cycle_length(f2->loopbase);
+ f1len = BME_cycle_length(f1->lbase);
+ f2len = BME_cycle_length(f2->lbase);
for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = curloop->next){
if(curloop->e == e){
f1loop = curloop;
@@ -938,19 +940,19 @@ BME_Poly *BME_JFKE(BME_Mesh *bm, BME_Poly *f1, BME_Poly *f2, BME_Edge *e)
f2loop->prev->next = f1loop->next;
/*if f1loop was baseloop, give f1loop->next the base.*/
- if(f1->loopbase == f1loop) f1->loopbase = f1loop->next;
+ if(f1->loopbase == f1loop) f1->lbase = f1loop->next;
/*validate the new loop*/
- loopok = BME_cycle_validate((f1len+f2len)-2, f1->loopbase);
+ loopok = BME_cycle_validate((f1len+f2len)-2, f1->lbase);
if(!loopok) BME_error();
/*make sure each loop points to the proper face*/
- newlen = BME_cycle_length(f1->loopbase);
+ newlen = BME_cycle_length(f1->lbase);
for(i = 0, curloop = f1->loopbase; i < newlen; i++, curloop = curloop->next) curloop->f = f1;
f1->len = newlen;
- edok = BME_cycle_validate(f1->len, f1->loopbase);
+ edok = BME_cycle_validate(f1->len, f1->lbase);
if(!edok) BME_error();
/*remove edge from the disk cycle of its two vertices.*/
@@ -966,3 +968,4 @@ BME_Poly *BME_JFKE(BME_Mesh *bm, BME_Poly *f1, BME_Poly *f2, BME_Edge *e)
BME_free_poly(bm, f2);
return f1;
}
+#endif
diff --git a/source/blender/blenkernel/intern/BME_mesh.c b/source/blender/blenkernel/intern/BME_mesh.c
index ca5d0b412ed..1097b9da2bc 100644
--- a/source/blender/blenkernel/intern/BME_mesh.c
+++ b/source/blender/blenkernel/intern/BME_mesh.c
@@ -1,3 +1,5 @@
+#if 0
+/**
/*
* BME_mesh.c jan 2007
*
@@ -51,10 +53,10 @@ BME_Mesh *BME_make_mesh(int allocsize[4])
/*allocate the structure*/
BME_Mesh *bm = MEM_callocN(sizeof(BME_Mesh),"BMesh");
/*allocate the memory pools for the mesh elements*/
- bm->vpool = BLI_mempool_create(sizeof(BME_Vert), allocsize[0], allocsize[0], 0);
- bm->epool = BLI_mempool_create(sizeof(BME_Edge), allocsize[1], allocsize[1], 0);
- bm->lpool = BLI_mempool_create(sizeof(BME_Loop), allocsize[2], allocsize[2], 0);
- bm->ppool = BLI_mempool_create(sizeof(BME_Poly), allocsize[3], allocsize[3], 0);
+ bm->vpool = BLI_mempool_create(sizeof(BME_Vert), allocsize[0], allocsize[0], 1, 0);
+ bm->epool = BLI_mempool_create(sizeof(BME_Edge), allocsize[1], allocsize[1], 1, 0);
+ bm->lpool = BLI_mempool_create(sizeof(BME_Loop), allocsize[2], allocsize[2], 1, 0);
+ bm->ppool = BLI_mempool_create(sizeof(BME_Poly), allocsize[3], allocsize[3], 1, 0);
return bm;
}
/*
@@ -78,7 +80,7 @@ void BME_free_mesh(BME_Mesh *bm)
do{
CustomData_bmesh_free_block(&bm->ldata, &l->data);
l = l->next;
- }while(l!=f->loopbase);
+ }while(l!=f->lbase);
}
/*Free custom data pools, This should probably go in CustomData_free?*/
@@ -192,9 +194,9 @@ int BME_validate_mesh(struct BME_Mesh *bm, int halt)
if(e->v1 == e->v2) VHALT(halt);
/*validate e->d1.data and e->d2.data*/
if(e->d1.data != e || e->d2.data != e) VHALT(halt);
- /*validate e->loop->e*/
- if(e->loop){
- if(e->loop->e != e) VHALT(halt);
+ /*validate e->l->e*/
+ if(e->l){
+ if(e->l->e != e) VHALT(halt);
}
}
@@ -206,17 +208,17 @@ int BME_validate_mesh(struct BME_Mesh *bm, int halt)
}
/*Validate vertices and disk cycle*/
for(v=bm->verts.first; v; v=v->next){
- /*validate v->edge pointer*/
+ /*validate v->e pointer*/
if(v->tflag1){
- if(v->edge){
- ok = BME_vert_in_edge(v->edge,v);
+ if(v->e){
+ ok = BME_vert_in_edge(v->e,v);
if(!ok) VHALT(halt);
/*validate length of disk cycle*/
- diskbase = BME_disk_getpointer(v->edge, v);
+ diskbase = BME_disk_getpointer(v->e, v);
ok = BME_cycle_validate(v->tflag1, diskbase);
if(!ok) VHALT(halt);
/*validate that each edge in disk cycle contains V*/
- for(i=0, e=v->edge; i < v->tflag1; i++, e = BME_disk_nextedge(e,v)){
+ for(i=0, e=v->e; i < v->tflag1; i++, e = BME_disk_nextedge(e,v)){
ok = BME_vert_in_edge(e, v);
if(!ok) VHALT(halt);
}
@@ -238,7 +240,7 @@ int BME_validate_mesh(struct BME_Mesh *bm, int halt)
for(e=bm->edges.first; e; e=e->next) e->tflag2 = 0; //store incident faces
/*Validate the loop cycle integrity.*/
for(f=bm->polys.first; f; f=f->next){
- ok = BME_cycle_length(f->loopbase);
+ ok = BME_cycle_length(f->lbase);
if(ok > 1){
f->tflag1 = ok;
}
@@ -249,11 +251,11 @@ int BME_validate_mesh(struct BME_Mesh *bm, int halt)
if(!ok) VHALT(halt);
/*verify radial node data pointer*/
if(l->radial.data != l) VHALT(halt);
- /*validate l->e->loop poitner*/
- if(l->e->loop == NULL) VHALT(halt);
+ /*validate l->e->l poitner*/
+ if(l->e->l == NULL) VHALT(halt);
/*validate l->f pointer*/
if(l->f != f) VHALT(halt);
- /*see if l->e->loop is actually in radial cycle*/
+ /*see if l->e->l is actually in radial cycle*/
l->e->tflag2++;
}
@@ -261,8 +263,8 @@ int BME_validate_mesh(struct BME_Mesh *bm, int halt)
/*validate length of radial cycle*/
for(e=bm->edges.first; e; e=e->next){
- if(e->loop){
- ok = BME_cycle_validate(e->tflag2,&(e->loop->radial));
+ if(e->l){
+ ok = BME_cycle_validate(e->tflag2,&(e->l->radial));
if(!ok) VHALT(halt);
}
}
@@ -279,3 +281,4 @@ int BME_validate_mesh(struct BME_Mesh *bm, int halt)
void BME_error(void){
printf("BME modelling error!");
}
+#endif
diff --git a/source/blender/blenkernel/intern/BME_structure.c b/source/blender/blenkernel/intern/BME_structure.c
index 8970e7ff705..f79b8edc866 100644
--- a/source/blender/blenkernel/intern/BME_structure.c
+++ b/source/blender/blenkernel/intern/BME_structure.c
@@ -1,3 +1,5 @@
+#if 0
+/**
/*
* BME_structure.c jan 2007
*
@@ -31,7 +33,7 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-
+#if 0
#include <limits.h>
#include "MEM_guardedalloc.h"
@@ -85,7 +87,7 @@ BME_Vert *BME_addvertlist(BME_Mesh *bm, BME_Vert *example){
v->EID = bm->nextv;
v->co[0] = v->co[1] = v->co[2] = 0.0f;
v->no[0] = v->no[1] = v->no[2] = 0.0f;
- v->edge = NULL;
+ v->e = NULL;
v->data = NULL;
v->eflag1 = v->eflag2 = v->tflag1 = v->tflag2 = 0;
v->flag = v->h = 0;
@@ -113,7 +115,7 @@ BME_Edge *BME_addedgelist(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Edge *ex
e->d1.next = e->d1.prev = e->d2.next = e->d2.prev = NULL;
e->d1.data = e;
e->d2.data = e;
- e->loop = NULL;
+ e->l = NULL;
e->data = NULL;
e->eflag1 = e->eflag2 = e->tflag1 = e->tflag2 = 0;
e->flag = e->h = 0;
@@ -238,7 +240,7 @@ void BME_free_loop(BME_Mesh *bm, BME_Loop *l){
* BME_disk_getpointer
*
* 2: The Radial Cycle - A circle of face edges (BME_Loop) around an edge
- * Base: edge->loop->radial structure.
+ * Base: edge->l->radial structure.
*
* The radial cycle is similar to the radial cycle in the radial edge data structure.*
* Unlike the radial edge however, the radial cycle does not require a large amount of memory
@@ -254,7 +256,7 @@ void BME_free_loop(BME_Mesh *bm, BME_Loop *l){
*
*
* 3: The Loop Cycle - A circle of face edges around a polygon.
- * Base: polygon->loopbase.
+ * Base: polygon->lbase.
*
* The loop cycle keeps track of a faces vertices and edges. It should be noted that the
* direction of a loop cycle is either CW or CCW depending on the face normal, and is
@@ -442,15 +444,15 @@ int BME_disk_append_edge(BME_Edge *e, BME_Vert *v)
if(BME_vert_in_edge(e, v) == 0) return 0; /*check to make sure v is in e*/
/*check for loose vert first*/
- if(v->edge == NULL){
- v->edge = e;
+ if(v->e == NULL){
+ v->e = e;
base = tail = BME_disk_getpointer(e, v);
BME_cycle_append(base, tail); /*circular reference is ok!*/
return 1;
}
- /*insert e at the end of disk cycle and make it the new v->edge*/
- base = BME_disk_getpointer(v->edge, v);
+ /*insert e at the end of disk cycle and make it the new v->e*/
+ base = BME_disk_getpointer(v->e, v);
tail = BME_disk_getpointer(e, v);
BME_cycle_append(base, tail);
return 1;
@@ -473,18 +475,18 @@ void BME_disk_remove_edge(BME_Edge *e, BME_Vert *v)
BME_Edge *newbase;
int len;
- base = BME_disk_getpointer(v->edge, v);
+ base = BME_disk_getpointer(v->e, v);
remnode = BME_disk_getpointer(e, v);
- /*first deal with v->edge pointer...*/
+ /*first deal with v->e pointer...*/
len = BME_cycle_length(base);
if(len == 1) newbase = NULL;
- else if(v->edge == e) newbase = base->next-> data;
- else newbase = v->edge;
+ else if(v->e == e) newbase = base->next-> data;
+ else newbase = v->e;
/*remove and rebase*/
BME_cycle_remove(base, remnode);
- v->edge = newbase;
+ v->e = newbase;
}
/**
@@ -537,12 +539,12 @@ int BME_disk_count_edgeflag(BME_Vert *v, int eflag, int tflag){
BME_Edge *curedge;
int i, len=0, count=0;
- if(v->edge){
+ if(v->e){
if(eflag && tflag) return 0; /*tflag and eflag are reserved for different functions!*/
- diskbase = BME_disk_getpointer(v->edge, v);
+ diskbase = BME_disk_getpointer(v->e, v);
len = BME_cycle_length(diskbase);
- for(i = 0, curedge=v->edge; i<len; i++){
+ for(i = 0, curedge=v->e; i<len; i++){
if(tflag){
if(curedge->tflag1 == tflag) count++;
}
@@ -560,11 +562,11 @@ int BME_disk_hasedge(BME_Vert *v, BME_Edge *e){
BME_Edge *curedge;
int i, len=0;
- if(v->edge){
- diskbase = BME_disk_getpointer(v->edge,v);
+ if(v->e){
+ diskbase = BME_disk_getpointer(v->e,v);
len = BME_cycle_length(diskbase);
- for(i = 0, curedge=v->edge; i<len; i++){
+ for(i = 0, curedge=v->e; i<len; i++){
if(curedge == e) return 1;
else curedge=BME_disk_nextedge(curedge, v);
}
@@ -574,12 +576,12 @@ int BME_disk_hasedge(BME_Vert *v, BME_Edge *e){
/*end disk cycle routines*/
BME_Loop *BME_radial_nextloop(BME_Loop *l){
- return (BME_Loop*)(l->radial.next->data);
+ return (BME_Loop*)(l->radial_next);
}
void BME_radial_append(BME_Edge *e, BME_Loop *l){
- if(e->loop == NULL) e->loop = l;
- BME_cycle_append(&(e->loop->radial), &(l->radial));
+ if(e->l == NULL) e->l = l;
+ BME_cycle_append(&(e->l->radial), &(l->radial));
}
void BME_radial_remove_loop(BME_Loop *l, BME_Edge *e)
@@ -587,15 +589,15 @@ void BME_radial_remove_loop(BME_Loop *l, BME_Edge *e)
BME_Loop *newbase;
int len;
- /*deal with edge->loop pointer*/
- len = BME_cycle_length(&(e->loop->radial));
+ /*deal with edge->l pointer*/
+ len = BME_cycle_length(&(e->l->radial));
if(len == 1) newbase = NULL;
- else if(e->loop == l) newbase = e->loop->radial.next->data;
- else newbase = e->loop;
+ else if(e->l == l) newbase = e->l->radial_next;
+ else newbase = e->l;
/*remove and rebase*/
- BME_cycle_remove(&(e->loop->radial), &(l->radial));
- e->loop = newbase;
+ BME_cycle_remove(&(e->l->radial), &(l->radial));
+ e->l = newbase;
}
int BME_radial_find_face(BME_Edge *e,BME_Poly *f)
@@ -604,8 +606,8 @@ int BME_radial_find_face(BME_Edge *e,BME_Poly *f)
BME_Loop *curloop;
int i, len;
- len = BME_cycle_length(&(e->loop->radial));
- for(i = 0, curloop = e->loop; i < len; i++, curloop = curloop->radial.next->data){
+ len = BME_cycle_length(&(e->l->radial));
+ for(i = 0, curloop = e->l; i < len; i++, curloop = curloop->radial_next){
if(curloop->f == f) return 1;
}
return 0;
@@ -615,9 +617,11 @@ struct BME_Loop *BME_loop_find_loop(struct BME_Poly *f, struct BME_Vert *v) {
BME_Loop *l;
int i, len;
- len = BME_cycle_length(f->loopbase);
+ len = BME_cycle_length(f->lbase);
for (i = 0, l=f->loopbase; i < len; i++, l=l->next) {
if (l->v == v) return l;
}
return NULL;
}
+#endif
+#endif
diff --git a/source/blender/blenkernel/intern/BME_tools.c b/source/blender/blenkernel/intern/BME_tools.c
index 2b28fb705fd..9dd4669ba1f 100644
--- a/source/blender/blenkernel/intern/BME_tools.c
+++ b/source/blender/blenkernel/intern/BME_tools.c
@@ -1,3 +1,5 @@
+#if 0
+/**
/*
* BME_tools.c jan 2007
*
@@ -39,7 +41,11 @@
#include "DNA_object_types.h"
#include "BLI_math.h"
+<<<<<<< .working
+#include "BLI_cellalloc.h"
+=======
#include "BLI_utildefines.h"
+>>>>>>> .merge-right.r35190
#include "BKE_bmesh.h"
@@ -114,20 +120,20 @@ static int BME_is_nonmanifold_vert(BME_Mesh *UNUSED(bm), BME_Vert *v) {
BME_Loop *l;
int len, count, flag;
- if (v->edge == NULL) {
+ if (v->e == NULL) {
/* loose vert */
return 1;
}
/* count edges while looking for non-manifold edges */
- oe = v->edge;
- for (len=0,e=v->edge; e != oe || (e == oe && len == 0); len++,e=BME_disk_nextedge(e,v)) {
- if (e->loop == NULL) {
+ oe = v->e;
+ for (len=0,e=v->e; e != oe || (e == oe && len == 0); len++,e=BME_disk_nextedge(e,v)) {
+ if (e->l == NULL) {
/* loose edge */
return 1;
}
- if (BME_cycle_length(&(e->loop->radial)) > 2) {
+ if (BME_cycle_length(&(e->l->radial)) > 2) {
/* edge shared by more than two faces */
return 1;
}
@@ -136,28 +142,28 @@ static int BME_is_nonmanifold_vert(BME_Mesh *UNUSED(bm), BME_Vert *v) {
count = 1;
flag = 1;
e = NULL;
- oe = v->edge;
- l = oe->loop;
+ oe = v->e;
+ l = oe->l;
while(e != oe) {
if (l->v == v) l = l->prev;
else l = l->next;
e = l->e;
count++; /* count the edges */
- if (flag && l->radial.next->data == l) {
+ if (flag && l->radial_next == l) {
/* we've hit the edge of an open mesh, reset once */
flag = 0;
count = 1;
oe = e;
e = NULL;
- l = oe->loop;
+ l = oe->l;
}
- else if (l->radial.next->data == l) {
+ else if (l->radial_next == l) {
/* break the loop */
e = oe;
}
else {
- l = l->radial.next->data;
+ l = l->radial_next;
}
}
@@ -174,8 +180,8 @@ static int BME_is_nonmanifold_vert(BME_Mesh *UNUSED(bm), BME_Vert *v) {
static BME_Poly *BME_JFKE_safe(BME_Mesh *bm, BME_Poly *f1, BME_Poly *f2, BME_Edge *e) {
BME_Loop *l1, *l2;
- l1 = e->loop;
- l2 = l1->radial.next->data;
+ l1 = e->l;
+ l2 = l1->radial_next;
if (l1->v == l2->v) {
BME_loop_reverse(bm, f2);
}
@@ -227,8 +233,8 @@ static void BME_data_facevert_edgesplit(BME_Mesh *bm, BME_Vert *v1, BME_Vert *UN
w[0] = 1.0f - fac;
w[1] = fac;
- if(!e1->loop) return;
- l = e1->loop;
+ if(!e1->l) return;
+ l = e1->l;
do{
if(l->v == v1){
v1loop = l;
@@ -245,8 +251,8 @@ static void BME_data_facevert_edgesplit(BME_Mesh *bm, BME_Vert *v1, BME_Vert *UN
src[1] = v2loop->data;
CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, vloop->data);
- l = l->radial.next->data;
- }while(l!=e1->loop);
+ l = l->radial_next;
+ }while(l!=e1->l);
}
@@ -283,8 +289,8 @@ static void BME_collapse_vert(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv, float fa
w[0] = 1.0f - fac;
w[1] = fac;
- if(ke->loop){
- l = ke->loop;
+ if(ke->l){
+ l = ke->l;
do{
if(l->v == tv && l->next->v == kv){
tvloop = l;
@@ -294,8 +300,8 @@ static void BME_collapse_vert(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv, float fa
src[1] = tvloop->data;
CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, kvloop->data);
}
- l=l->radial.next->data;
- }while(l!=ke->loop);
+ l=l->radial_next;
+ }while(l!=ke->l);
}
BME_JEKV(bm,ke,kv);
}
@@ -401,12 +407,12 @@ static BME_Vert *BME_bevel_split_edge(BME_Mesh *bm, BME_Vert *v, BME_Vert *v1, B
* so... here we walk around edges to find the needed verts */
forward = 1;
is_split_vert = 0;
- if (v->edge == NULL) {
+ if (v->e == NULL) {
//printf("We can't split a loose vert's edge!\n");
return NULL;
}
- e1 = v->edge; /* we just use the first two edges */
- e2 = BME_disk_nextedge(v->edge, v);
+ e1 = v->e; /* we just use the first two edges */
+ e2 = BME_disk_nextedge(v->e, v);
if (e1 == e2) {
//printf("You need at least two edges to use BME_bevel_split_edge()\n");
return NULL;
@@ -587,8 +593,8 @@ static float BME_bevel_set_max(BME_Vert *v1, BME_Vert *v2, float value, BME_Tran
static BME_Vert *BME_bevel_wire(BME_Mesh *bm, BME_Vert *v, float value, int res, int UNUSED(options), BME_TransData_Head *td) {
BME_Vert *ov1, *ov2, *v1, *v2;
- ov1 = BME_edge_getothervert(v->edge, v);
- ov2 = BME_edge_getothervert(BME_disk_nextedge(v->edge, v), v);
+ ov1 = BME_edge_getothervert(v->e, v);
+ ov2 = BME_edge_getothervert(BME_disk_nextedge(v->e, v), v);
/* split the edges */
v1 = BME_bevel_split_edge(bm,v,ov1,NULL,NULL,value,td);
@@ -603,7 +609,7 @@ static BME_Vert *BME_bevel_wire(BME_Mesh *bm, BME_Vert *v, float value, int res,
/* remove the original vert */
if (res) {
- BME_JEKV(bm,v->edge,v);
+ BME_JEKV(bm,v->e,v);
}
return v1;
@@ -628,7 +634,7 @@ static BME_Loop *BME_bevel_edge(BME_Mesh *bm, BME_Loop *l, float value, int UNUS
/* first, check to see if this edge was inset previously */
if ((l->prev->e->tflag1 & BME_BEVEL_ORIG) == 0
&& (l->v->tflag1 & BME_BEVEL_NONMAN) == 0) {
- kl = l->prev->radial.next->data;
+ kl = l->prev->radial_next;
if (kl->v == l->v) kl = kl->prev;
else kl = kl->next;
kv = l->v;
@@ -648,14 +654,14 @@ static BME_Loop *BME_bevel_edge(BME_Mesh *bm, BME_Loop *l, float value, int UNUS
l = l->next;
if (kl->v == kv) {
BME_split_face(bm,kl->f,kl->prev->v,kl->next->v,&nl,kl->prev->e);
- BME_JFKE(bm,((BME_Loop*)kl->prev->radial.next->data)->f,kl->f,kl->prev->e);
+ BME_JFKE(bm,((BME_Loop*)kl->prev->radial_next)->f,kl->f,kl->prev->e);
BME_collapse_vert(bm, kl->e, kv, 1.0);
//BME_JEKV(bm,kl->e,kv);
}
else {
BME_split_face(bm,kl->f,kl->next->next->v,kl->v,&nl,kl->next->e);
- BME_JFKE(bm,((BME_Loop*)kl->next->radial.next->data)->f,kl->f,kl->next->e);
+ BME_JFKE(bm,((BME_Loop*)kl->next->radial_next)->f,kl->f,kl->next->e);
BME_collapse_vert(bm, kl->e, kv, 1.0);
//BME_JEKV(bm,kl->e,kv);
}
@@ -666,7 +672,7 @@ static BME_Loop *BME_bevel_edge(BME_Mesh *bm, BME_Loop *l, float value, int UNUS
/* first, check to see if this edge was inset previously */
if ((l->next->e->tflag1 & BME_BEVEL_ORIG) == 0
&& (l->next->v->tflag1 & BME_BEVEL_NONMAN) == 0) {
- kl = l->next->radial.next->data;
+ kl = l->next->radial_next;
if (kl->v == l->next->v) kl = kl->prev;
else kl = kl->next;
kv = l->next->v;
@@ -685,13 +691,13 @@ static BME_Loop *BME_bevel_edge(BME_Mesh *bm, BME_Loop *l, float value, int UNUS
if (kv) {
if (kl->v == kv) {
BME_split_face(bm,kl->f,kl->prev->v,kl->next->v,&nl,kl->prev->e);
- BME_JFKE(bm,((BME_Loop*)kl->prev->radial.next->data)->f,kl->f,kl->prev->e);
+ BME_JFKE(bm,((BME_Loop*)kl->prev->radial_next)->f,kl->f,kl->prev->e);
BME_collapse_vert(bm, kl->e, kv, 1.0);
//BME_JEKV(bm,kl->e,kv);
}
else {
BME_split_face(bm,kl->f,kl->next->next->v,kl->v,&nl,kl->next->e);
- BME_JFKE(bm,((BME_Loop*)kl->next->radial.next->data)->f,kl->f,kl->next->e);
+ BME_JFKE(bm,((BME_Loop*)kl->next->radial_next)->f,kl->f,kl->next->e);
BME_collapse_vert(bm, kl->e, kv, 1.0);
//BME_JEKV(bm,kl->e,kv);
}
@@ -700,7 +706,7 @@ static BME_Loop *BME_bevel_edge(BME_Mesh *bm, BME_Loop *l, float value, int UNUS
if ((v1->tflag1 & BME_BEVEL_NONMAN)==0 || (v2->tflag1 & BME_BEVEL_NONMAN)==0) {
BME_split_face(bm,f,v2,v1,&l,e);
l->e->tflag1 = BME_BEVEL_BEVEL;
- l = l->radial.next->data;
+ l = l->radial_next;
}
if (l->f != f){
@@ -866,8 +872,8 @@ static float BME_bevel_get_angle(BME_Mesh *UNUSED(bm), BME_Edge *e, BME_Vert *v)
BME_Loop *l1, *l2;
float vec1[3], vec2[3], vec3[3], vec4[3];
- l1 = e->loop;
- l2 = e->loop->radial.next->data;
+ l1 = e->l;
+ l2 = e->l->radial_next;
if (l1->v == v) {
v1 = l1->prev->v;
v2 = l1->next->v;
@@ -906,7 +912,7 @@ static int BME_face_sharededges(BME_Poly *f1, BME_Poly *f2){
do{
if(BME_radial_find_face(l->e,f2)) count++;
l = l->next;
- }while(l != f1->loopbase);
+ }while(l != f1->lbase);
return count;
}
@@ -951,11 +957,11 @@ static BME_Mesh *BME_bevel_initialize(BME_Mesh *bm, int options, int UNUSED(defg
*/
/* get disk cycle length */
- if (v->edge == NULL) {
+ if (v->e == NULL) {
len = 0;
}
else {
- len = BME_cycle_length(BME_disk_getpointer(v->edge,v));
+ len = BME_cycle_length(BME_disk_getpointer(v->e,v));
/* we'll assign a default transform data to every vert (except the loose ones) */
vtd = BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 0, -1, -1, NULL);
}
@@ -1022,13 +1028,13 @@ static BME_Mesh *BME_bevel_initialize(BME_Mesh *bm, int options, int UNUSED(defg
* i.e. the vert's weight is the average of the weights of its weighted edges
*/
- if (e->loop == NULL) {
+ if (e->l == NULL) {
len = 0;
e->v1->tflag1 |= BME_BEVEL_NONMAN;
e->v2->tflag1 |= BME_BEVEL_NONMAN;
}
else {
- len = BME_cycle_length(&(e->loop->radial));
+ len = BME_cycle_length(&(e->l->radial));
}
if (len > 2) {
@@ -1092,7 +1098,7 @@ static BME_Mesh *BME_bevel_initialize(BME_Mesh *bm, int options, int UNUSED(defg
for (e=bm->edges.first; e; e=e->next){
if(e->tflag1 & BME_BEVEL_BEVEL){
int count = 0;
- count = BME_face_sharededges(e->loop->f, ((BME_Loop*)e->loop->radial.next->data)->f);
+ count = BME_face_sharededges(e->l->f, ((BME_Loop*)e->l->radial_next)->f);
if(count > 1){
e->tflag1 &= ~BME_BEVEL_BEVEL;
}
@@ -1142,26 +1148,26 @@ static void bmesh_dissolve_disk(BME_Mesh *bm, BME_Vert *v){
BME_Edge *e;
int done, len;
- if(v->edge){
+ if(v->e){
done = 0;
while(!done){
done = 1;
- e = v->edge; /*loop the edge looking for a edge to dissolve*/
+ e = v->e; /*loop the edge looking for a edge to dissolve*/
do{
f = NULL;
- len = BME_cycle_length(&(e->loop->radial));
+ len = BME_cycle_length(&(e->l->radial));
if(len == 2){
- f = BME_JFKE_safe(bm,e->loop->f, ((BME_Loop*)(e->loop->radial.next->data))->f, e);
+ f = BME_JFKE_safe(bm,e->l->f, ((BME_Loop*)(e->l->radial_next))->f, e);
}
if(f){
done = 0;
break;
}
e = BME_disk_nextedge(e,v);
- }while(e != v->edge);
+ }while(e != v->e);
}
- BME_collapse_vert(bm, v->edge, v, 1.0);
- //BME_JEKV(bm,v->edge,v);
+ BME_collapse_vert(bm, v->e, v, 1.0);
+ //BME_JEKV(bm,v->e,v);
}
}
static BME_Mesh *BME_bevel_mesh(BME_Mesh *bm, float value, int res, int options, int UNUSED(defgrp_index), BME_TransData_Head *td) {
@@ -1187,7 +1193,7 @@ static BME_Mesh *BME_bevel_mesh(BME_Mesh *bm, float value, int res, int options,
else if (res && ((v->tflag1 & BME_BEVEL_BEVEL) && (v->tflag1 & BME_BEVEL_ORIG))) {
int count = 0;
/* first, make sure we're not sitting on an edge to be removed */
- oe = v->edge;
+ oe = v->e;
e = BME_disk_nextedge(oe,v);
while ((e->tflag1 & BME_BEVEL_BEVEL) && (e->tflag1 & BME_BEVEL_ORIG)) {
e = BME_disk_nextedge(e,v);
@@ -1201,7 +1207,7 @@ static BME_Mesh *BME_bevel_mesh(BME_Mesh *bm, float value, int res, int options,
while ( (e = BME_disk_next_edgeflag(oe, v, 0, BME_BEVEL_ORIG | BME_BEVEL_BEVEL)) ) {
count++;
/* join the faces (we'll split them later) */
- f = BME_JFKE_safe(bm,e->loop->f,((BME_Loop*)e->loop->radial.next->data)->f,e);
+ f = BME_JFKE_safe(bm,e->l->f,((BME_Loop*)e->l->radial_next)->f,e);
if (!f){
//printf("Non-manifold geometry not getting tagged right?\n");
}
@@ -1212,10 +1218,10 @@ static BME_Mesh *BME_bevel_mesh(BME_Mesh *bm, float value, int res, int options,
/* all original edges marked to be beveled have been removed;
* now we need to link up the edges for this "corner" */
- len = BME_cycle_length(BME_disk_getpointer(v->edge, v));
- for (i=0,e=v->edge; i < len; i++,e=BME_disk_nextedge(e,v)) {
- l = e->loop;
- l2 = l->radial.next->data;
+ len = BME_cycle_length(BME_disk_getpointer(v->e, v));
+ for (i=0,e=v->e; i < len; i++,e=BME_disk_nextedge(e,v)) {
+ l = e->l;
+ l2 = l->radial_next;
if (l->v != v) l = l->next;
if (l2->v != v) l2 = l2->next;
/* look for faces that have had the original edges removed via JFKE */
@@ -1321,3 +1327,4 @@ BME_Mesh *BME_bevel(BME_Mesh *bm, float value, int res, int options, int defgrp_
BME_free_transdata(td);
return bm;
}
+#endif
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index ed636e95b96..05c06e86cd0 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -42,6 +42,7 @@
#include "BLI_editVert.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
+#include "BLI_array.h"
#include "BLI_pbvh.h"
#include "BLI_utildefines.h"
@@ -54,6 +55,9 @@
#include "BKE_paint.h"
#include "BKE_texture.h"
#include "BKE_multires.h"
+#include "BKE_particle.h"
+#include "BKE_tessmesh.h"
+#include "BKE_bvhutils.h"
#include "BLO_sys_types.h" // for intptr_t support
@@ -105,9 +109,9 @@ static MFace *dm_getFaceArray(DerivedMesh *dm)
if (!mface) {
mface = CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL,
- dm->getNumFaces(dm));
+ dm->getNumTessFaces(dm));
CustomData_set_layer_flag(&dm->faceData, CD_MFACE, CD_FLAG_TEMPORARY);
- dm->copyFaceArray(dm, mface);
+ dm->copyTessFaceArray(dm, mface);
}
return mface;
@@ -135,41 +139,74 @@ static MEdge *dm_dupEdgeArray(DerivedMesh *dm)
static MFace *dm_dupFaceArray(DerivedMesh *dm)
{
- MFace *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumFaces(dm),
+ MFace *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumTessFaces(dm),
"dm_dupFaceArray tmp");
- if(tmp) dm->copyFaceArray(dm, tmp);
+ if(tmp) dm->copyTessFaceArray(dm, tmp);
return tmp;
}
+CustomData *dm_getVertCData(DerivedMesh *dm)
+{
+ return &dm->vertData;
+}
+
+CustomData *dm_getEdgeCData(DerivedMesh *dm)
+{
+ return &dm->edgeData;
+}
+
+CustomData *dm_getFaceCData(DerivedMesh *dm)
+{
+ return &dm->faceData;
+}
+
+CustomData *dm_getLoopCData(DerivedMesh *dm)
+{
+ return &dm->loopData;
+}
+
+CustomData *dm_getPolyCData(DerivedMesh *dm)
+{
+ return &dm->polyData;
+}
+
void DM_init_funcs(DerivedMesh *dm)
{
/* default function implementations */
dm->getVertArray = dm_getVertArray;
dm->getEdgeArray = dm_getEdgeArray;
- dm->getFaceArray = dm_getFaceArray;
+ dm->getTessFaceArray = dm_getFaceArray;
dm->dupVertArray = dm_dupVertArray;
dm->dupEdgeArray = dm_dupEdgeArray;
- dm->dupFaceArray = dm_dupFaceArray;
+ dm->dupTessFaceArray = dm_dupFaceArray;
+
+ dm->getVertDataLayout = dm_getVertCData;
+ dm->getEdgeDataLayout = dm_getEdgeCData;
+ dm->getTessFaceDataLayout = dm_getFaceCData;
+ dm->getLoopDataLayout = dm_getLoopCData;
+ dm->getFaceDataLayout = dm_getPolyCData;
dm->getVertData = DM_get_vert_data;
dm->getEdgeData = DM_get_edge_data;
- dm->getFaceData = DM_get_face_data;
+ dm->getTessFaceData = DM_get_face_data;
dm->getVertDataArray = DM_get_vert_data_layer;
dm->getEdgeDataArray = DM_get_edge_data_layer;
- dm->getFaceDataArray = DM_get_face_data_layer;
+ dm->getTessFaceDataArray = DM_get_tessface_data_layer;
bvhcache_init(&dm->bvhCache);
}
-void DM_init(DerivedMesh *dm, DerivedMeshType type,
- int numVerts, int numEdges, int numFaces)
+void DM_init(DerivedMesh *dm, DerivedMeshType type, int numVerts, int numEdges,
+ int numFaces, int numLoops, int numPoly)
{
dm->type = type;
dm->numVertData = numVerts;
dm->numEdgeData = numEdges;
dm->numFaceData = numFaces;
+ dm->numLoopData = numLoops;
+ dm->numPolyData = numPoly;
DM_init_funcs(dm);
@@ -177,7 +214,8 @@ void DM_init(DerivedMesh *dm, DerivedMeshType type,
}
void DM_from_template(DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type,
- int numVerts, int numEdges, int numFaces)
+ int numVerts, int numEdges, int numFaces,
+ int numLoops, int numPolys)
{
CustomData_copy(&source->vertData, &dm->vertData, CD_MASK_DERIVEDMESH,
CD_CALLOC, numVerts);
@@ -185,11 +223,17 @@ void DM_from_template(DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type
CD_CALLOC, numEdges);
CustomData_copy(&source->faceData, &dm->faceData, CD_MASK_DERIVEDMESH,
CD_CALLOC, numFaces);
+ CustomData_copy(&source->loopData, &dm->loopData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, numLoops);
+ CustomData_copy(&source->polyData, &dm->polyData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, numPolys);
dm->type = type;
dm->numVertData = numVerts;
dm->numEdgeData = numEdges;
dm->numFaceData = numFaces;
+ dm->numLoopData = numLoops;
+ dm->numPolyData = numPolys;
DM_init_funcs(dm);
@@ -204,6 +248,8 @@ int DM_release(DerivedMesh *dm)
CustomData_free(&dm->vertData, dm->numVertData);
CustomData_free(&dm->edgeData, dm->numEdgeData);
CustomData_free(&dm->faceData, dm->numFaceData);
+ CustomData_free(&dm->loopData, dm->numLoopData);
+ CustomData_free(&dm->polyData, dm->numPolyData);
return 1;
}
@@ -211,28 +257,139 @@ int DM_release(DerivedMesh *dm)
CustomData_free_temporary(&dm->vertData, dm->numVertData);
CustomData_free_temporary(&dm->edgeData, dm->numEdgeData);
CustomData_free_temporary(&dm->faceData, dm->numFaceData);
+ CustomData_free_temporary(&dm->loopData, dm->numLoopData);
+ CustomData_free_temporary(&dm->polyData, dm->numPolyData);
return 0;
}
}
+void dm_add_polys_from_iter(CustomData *ldata, CustomData *pdata, DerivedMesh *dm, int totloop)
+{
+ DMFaceIter *iter = dm->newFaceIter(dm);
+ DMLoopIter *liter;
+ CustomData *oldata, *opdata;
+ MPoly *mpoly;
+ MLoop *mloop;
+ int p, l, i, j, lasttype;
+
+ oldata = dm->getLoopDataLayout(dm);
+ opdata = dm->getFaceDataLayout(dm);
+
+ CustomData_copy(oldata, ldata, CD_MASK_DERIVEDMESH, CD_CALLOC, totloop);
+ CustomData_copy(opdata, pdata, CD_MASK_DERIVEDMESH, CD_CALLOC, dm->getNumFaces(dm));
+
+ mloop = MEM_callocN(sizeof(MLoop)*totloop, "MLoop from dm_add_polys_from_iter");
+ CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop);
+ mpoly = MEM_callocN(sizeof(MPoly)*dm->getNumFaces(dm), "MPoly from dm_add_polys_from_iter");
+ CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, dm->getNumFaces(dm));
+
+ l = 0;
+ for (p=0; !iter->done; iter->step(iter), mpoly++, p++) {
+ mpoly->flag = iter->flags;
+ mpoly->loopstart = l;
+ mpoly->totloop = iter->len;
+ mpoly->mat_nr = iter->mat_nr;
+
+ j = 0;
+ lasttype = -1;
+ for (i=0; i<opdata->totlayer; i++) {
+ void *e1, *e2;
+
+ if (opdata->layers[i].type == lasttype)
+ j++;
+ else
+ j = 0;
+
+ if (opdata->layers[i].type == CD_MPOLY)
+ continue;
+
+ e1 = iter->getCDData(iter, opdata->layers[i].type, j);
+ e2 = (char*)CustomData_get_n(pdata, opdata->layers[i].type, p, j);
+
+ if (!e2)
+ continue;
+
+ CustomData_copy_elements(opdata->layers[i].type, e1, e2, 1);
+
+ lasttype = opdata->layers[i].type;
+ }
+
+ liter = iter->getLoopsIter(iter);
+ for (; !liter->done; liter->step(liter), mloop++, l++) {
+ mloop->v = liter->vindex;
+ mloop->e = liter->eindex;
+
+ j = 0;
+ lasttype = -1;
+ for (i=0; i<oldata->totlayer; i++) {
+ void *e1, *e2;
+
+ if (oldata->layers[i].type == CD_MLOOP)
+ continue;
+
+ if (oldata->layers[i].type == lasttype)
+ j++;
+ else
+ j = 0;
+
+ e1 = liter->getLoopCDData(liter, oldata->layers[i].type, j);
+ e2 = CustomData_get_n(ldata, oldata->layers[i].type, l, j);
+
+ if (!e2)
+ continue;
+
+ CustomData_copy_elements(oldata->layers[i].type, e1, e2, 1);
+ lasttype = oldata->layers[i].type;
+ }
+ }
+ }
+ iter->free(iter);
+}
+
+void DM_DupPolys(DerivedMesh *source, DerivedMesh *target)
+{
+ DMFaceIter *iter = source->newFaceIter(source);
+ DMLoopIter *liter;
+ int totloop = source->numLoopData;
+
+ dm_add_polys_from_iter(&target->loopData, &target->polyData, source, totloop);
+
+ target->numLoopData = totloop;
+ target->numPolyData = source->getNumFaces(source);
+}
+
void DM_to_mesh(DerivedMesh *dm, Mesh *me)
{
/* dm might depend on me, so we need to do everything with a local copy */
Mesh tmp = *me;
- int totvert, totedge, totface;
+ DMFaceIter *iter;
+ int totvert, totedge, totface, totloop, totpoly;
memset(&tmp.vdata, 0, sizeof(tmp.vdata));
memset(&tmp.edata, 0, sizeof(tmp.edata));
memset(&tmp.fdata, 0, sizeof(tmp.fdata));
+ memset(&tmp.ldata, 0, sizeof(tmp.ldata));
+ memset(&tmp.pdata, 0, sizeof(tmp.pdata));
totvert = tmp.totvert = dm->getNumVerts(dm);
totedge = tmp.totedge = dm->getNumEdges(dm);
- totface = tmp.totface = dm->getNumFaces(dm);
+ totface = tmp.totface = dm->getNumTessFaces(dm);
+ totpoly = tmp.totpoly = dm->getNumFaces(dm);
+
+ totloop = 0;
+ for (iter=dm->newFaceIter(dm); !iter->done; iter->step(iter)) {
+ totloop += iter->len;
+ }
+ iter->free(iter);
+
+ tmp.totloop = totloop;
CustomData_copy(&dm->vertData, &tmp.vdata, CD_MASK_MESH, CD_DUPLICATE, totvert);
CustomData_copy(&dm->edgeData, &tmp.edata, CD_MASK_MESH, CD_DUPLICATE, totedge);
CustomData_copy(&dm->faceData, &tmp.fdata, CD_MASK_MESH, CD_DUPLICATE, totface);
+ CustomData_copy(&dm->loopData, &tmp.ldata, CD_MASK_MESH, CD_DUPLICATE, totloop);
+ CustomData_copy(&dm->polyData, &tmp.pdata, CD_MASK_MESH, CD_DUPLICATE, totpoly);
/* not all DerivedMeshes store their verts/edges/faces in CustomData, so
we set them here in case they are missing */
@@ -241,7 +398,9 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me)
if(!CustomData_has_layer(&tmp.edata, CD_MEDGE))
CustomData_add_layer(&tmp.edata, CD_MEDGE, CD_ASSIGN, dm->dupEdgeArray(dm), totedge);
if(!CustomData_has_layer(&tmp.fdata, CD_MFACE))
- CustomData_add_layer(&tmp.fdata, CD_MFACE, CD_ASSIGN, dm->dupFaceArray(dm), totface);
+ CustomData_add_layer(&tmp.fdata, CD_MFACE, CD_ASSIGN, dm->dupTessFaceArray(dm), totface);
+ if(!CustomData_has_layer(&tmp.pdata, CD_MPOLY))
+ dm_add_polys_from_iter(&tmp.ldata, &tmp.pdata, dm, totloop);
/* object had got displacement layer, should copy this layer to save sculpted data */
/* NOTE: maybe some other layers should be copied? nazgul */
@@ -257,9 +416,14 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me)
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
- /* if the number of verts has changed, remove invalid data */
+ /* BMESH_TODO/XXX: ok, this should use new CD shapekey data,
+ which shouuld be fed through the modifier
+ stack*/
if(tmp.totvert != me->totvert) {
+ printf("YEEK! this should be recoded! Shape key loss!!!\n");
if(tmp.key) tmp.key->id.us--;
tmp.key = NULL;
}
@@ -304,11 +468,21 @@ void DM_add_edge_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
CustomData_add_layer(&dm->edgeData, type, alloctype, layer, dm->numEdgeData);
}
-void DM_add_face_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+void DM_add_tessface_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
{
CustomData_add_layer(&dm->faceData, type, alloctype, layer, dm->numFaceData);
}
+void DM_add_loop_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+{
+ CustomData_add_layer(&dm->loopData, type, alloctype, layer, dm->numLoopData);
+}
+
+void DM_add_face_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+{
+ CustomData_add_layer(&dm->polyData, type, alloctype, layer, dm->numPolyData);
+}
+
void *DM_get_vert_data(DerivedMesh *dm, int index, int type)
{
return CustomData_get(&dm->vertData, index, type);
@@ -340,14 +514,19 @@ void *DM_get_edge_data_layer(DerivedMesh *dm, int type)
return CustomData_get_layer(&dm->edgeData, type);
}
-void *DM_get_face_data_layer(DerivedMesh *dm, int type)
+void *DM_get_tessface_data_layer(DerivedMesh *dm, int type)
{
if(type == CD_MFACE)
- return dm->getFaceArray(dm);
+ return dm->getTessFaceArray(dm);
return CustomData_get_layer(&dm->faceData, type);
}
+void *DM_get_face_data_layer(DerivedMesh *dm, int type)
+{
+ return CustomData_get_layer(&dm->polyData, type);
+}
+
void DM_set_vert_data(DerivedMesh *dm, int index, int type, void *data)
{
CustomData_set(&dm->vertData, index, type, data);
@@ -377,13 +556,27 @@ void DM_copy_edge_data(DerivedMesh *source, DerivedMesh *dest,
source_index, dest_index, count);
}
-void DM_copy_face_data(DerivedMesh *source, DerivedMesh *dest,
+void DM_copy_tessface_data(DerivedMesh *source, DerivedMesh *dest,
int source_index, int dest_index, int count)
{
CustomData_copy_data(&source->faceData, &dest->faceData,
source_index, dest_index, count);
}
+void DM_copy_loop_data(DerivedMesh *source, DerivedMesh *dest,
+ int source_index, int dest_index, int count)
+{
+ CustomData_copy_data(&source->loopData, &dest->loopData,
+ source_index, dest_index, count);
+}
+
+void DM_copy_face_data(DerivedMesh *source, DerivedMesh *dest,
+ int source_index, int dest_index, int count)
+{
+ CustomData_copy_data(&source->polyData, &dest->polyData,
+ source_index, dest_index, count);
+}
+
void DM_free_vert_data(struct DerivedMesh *dm, int index, int count)
{
CustomData_free_elem(&dm->vertData, index, count);
@@ -394,11 +587,21 @@ void DM_free_edge_data(struct DerivedMesh *dm, int index, int count)
CustomData_free_elem(&dm->edgeData, index, count);
}
-void DM_free_face_data(struct DerivedMesh *dm, int index, int count)
+void DM_free_tessface_data(struct DerivedMesh *dm, int index, int count)
{
CustomData_free_elem(&dm->faceData, index, count);
}
+void DM_free_loop_data(struct DerivedMesh *dm, int index, int count)
+{
+ CustomData_free_elem(&dm->loopData, index, count);
+}
+
+void DM_free_face_data(struct DerivedMesh *dm, int index, int count)
+{
+ CustomData_free_elem(&dm->polyData, index, count);
+}
+
void DM_interp_vert_data(DerivedMesh *source, DerivedMesh *dest,
int *src_indices, float *weights,
int count, int dest_index)
@@ -416,7 +619,7 @@ void DM_interp_edge_data(DerivedMesh *source, DerivedMesh *dest,
weights, (float*)vert_weights, count, dest_index);
}
-void DM_interp_face_data(DerivedMesh *source, DerivedMesh *dest,
+void DM_interp_tessface_data(DerivedMesh *source, DerivedMesh *dest,
int *src_indices,
float *weights, FaceVertWeight *vert_weights,
int count, int dest_index)
@@ -425,13 +628,28 @@ void DM_interp_face_data(DerivedMesh *source, DerivedMesh *dest,
weights, (float*)vert_weights, count, dest_index);
}
-void DM_swap_face_data(DerivedMesh *dm, int index, const int *corner_indices)
+void DM_swap_tessface_data(DerivedMesh *dm, int index, const int *corner_indices)
{
CustomData_swap(&dm->faceData, index, corner_indices);
}
-///
+void DM_interp_loop_data(DerivedMesh *source, DerivedMesh *dest,
+ int *src_indices,
+ float *weights, int count, int dest_index)
+{
+ CustomData_interp(&source->loopData, &dest->loopData, src_indices,
+ weights, NULL, count, dest_index);
+}
+void DM_interp_face_data(DerivedMesh *source, DerivedMesh *dest,
+ int *src_indices,
+ float *weights, int count, int dest_index)
+{
+ CustomData_interp(&source->polyData, &dest->polyData, src_indices,
+ weights, NULL, count, dest_index);
+}
+
+///
DerivedMesh *mesh_create_derived(Mesh *me, Object *ob, float (*vertCos)[3])
{
DerivedMesh *dm = CDDM_from_mesh(me, ob);
@@ -447,988 +665,6 @@ DerivedMesh *mesh_create_derived(Mesh *me, Object *ob, float (*vertCos)[3])
return dm;
}
-///
-
-typedef struct {
- DerivedMesh dm;
-
- EditMesh *em;
- float (*vertexCos)[3];
- float (*vertexNos)[3];
- float (*faceNos)[3];
-} EditMeshDerivedMesh;
-
-static void emDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData)
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditVert *eve;
- int i;
-
- for (i=0,eve= emdm->em->verts.first; eve; i++,eve=eve->next) {
- if (emdm->vertexCos) {
- func(userData, i, emdm->vertexCos[i], emdm->vertexNos[i], NULL);
- } else {
- func(userData, i, eve->co, eve->no, NULL);
- }
- }
-}
-static void emDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData)
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditEdge *eed;
- int i;
-
- if (emdm->vertexCos) {
- EditVert *eve;
-
- for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
- eve->tmp.l = (intptr_t) i++;
- for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next)
- func(userData, i, emdm->vertexCos[(int) eed->v1->tmp.l], emdm->vertexCos[(int) eed->v2->tmp.l]);
- } else {
- for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next)
- func(userData, i, eed->v1->co, eed->v2->co);
- }
-}
-static void emDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditEdge *eed;
- int i;
-
- if (emdm->vertexCos) {
- EditVert *eve;
-
- for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
- eve->tmp.l = (intptr_t) i++;
-
- glBegin(GL_LINES);
- for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
- if(!setDrawOptions || setDrawOptions(userData, i)) {
- glVertex3fv(emdm->vertexCos[(int) eed->v1->tmp.l]);
- glVertex3fv(emdm->vertexCos[(int) eed->v2->tmp.l]);
- }
- }
- glEnd();
- } else {
- glBegin(GL_LINES);
- for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
- if(!setDrawOptions || setDrawOptions(userData, i)) {
- glVertex3fv(eed->v1->co);
- glVertex3fv(eed->v2->co);
- }
- }
- glEnd();
- }
-}
-static void emDM_drawEdges(DerivedMesh *dm, int UNUSED(drawLooseEdges), int UNUSED(drawAllEdges))
-{
- emDM_drawMappedEdges(dm, NULL, NULL);
-}
-static void emDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData)
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditEdge *eed;
- int i;
-
- if (emdm->vertexCos) {
- EditVert *eve;
-
- for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
- eve->tmp.l = (intptr_t) i++;
-
- glBegin(GL_LINES);
- for (i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
- if(!setDrawOptions || setDrawOptions(userData, i)) {
- setDrawInterpOptions(userData, i, 0.0);
- glVertex3fv(emdm->vertexCos[(int) eed->v1->tmp.l]);
- setDrawInterpOptions(userData, i, 1.0);
- glVertex3fv(emdm->vertexCos[(int) eed->v2->tmp.l]);
- }
- }
- glEnd();
- } else {
- glBegin(GL_LINES);
- for (i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
- if(!setDrawOptions || setDrawOptions(userData, i)) {
- setDrawInterpOptions(userData, i, 0.0);
- glVertex3fv(eed->v1->co);
- setDrawInterpOptions(userData, i, 1.0);
- glVertex3fv(eed->v2->co);
- }
- }
- glEnd();
- }
-}
-
-static void emDM_drawUVEdges(DerivedMesh *dm)
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditFace *efa;
- MTFace *tf;
-
- glBegin(GL_LINES);
- for(efa= emdm->em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&emdm->em->fdata, efa->data, CD_MTFACE);
-
- if(tf && !(efa->h)) {
- glVertex2fv(tf->uv[0]);
- glVertex2fv(tf->uv[1]);
-
- glVertex2fv(tf->uv[1]);
- glVertex2fv(tf->uv[2]);
-
- if (!efa->v4) {
- glVertex2fv(tf->uv[2]);
- glVertex2fv(tf->uv[0]);
- } else {
- glVertex2fv(tf->uv[2]);
- glVertex2fv(tf->uv[3]);
- glVertex2fv(tf->uv[3]);
- glVertex2fv(tf->uv[0]);
- }
- }
- }
- glEnd();
-}
-
-static void emDM__calcFaceCent(EditFace *efa, float cent[3], float (*vertexCos)[3])
-{
- if (vertexCos) {
- VECCOPY(cent, vertexCos[(int) efa->v1->tmp.l]);
- add_v3_v3(cent, vertexCos[(int) efa->v2->tmp.l]);
- add_v3_v3(cent, vertexCos[(int) efa->v3->tmp.l]);
- if (efa->v4) add_v3_v3(cent, vertexCos[(int) efa->v4->tmp.l]);
- } else {
- VECCOPY(cent, efa->v1->co);
- add_v3_v3(cent, efa->v2->co);
- add_v3_v3(cent, efa->v3->co);
- if (efa->v4) add_v3_v3(cent, efa->v4->co);
- }
-
- if (efa->v4) {
- mul_v3_fl(cent, 0.25f);
- } else {
- mul_v3_fl(cent, 0.33333333333f);
- }
-}
-static void emDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData)
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditVert *eve;
- EditFace *efa;
- float cent[3];
- int i;
-
- if (emdm->vertexCos) {
- for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
- eve->tmp.l = (intptr_t) i++;
- }
-
- for(i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) {
- emDM__calcFaceCent(efa, cent, emdm->vertexCos);
- func(userData, i, cent, emdm->vertexCos?emdm->faceNos[i]:efa->n);
- }
-}
-
-/* note, material function is ignored for now. */
-static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int UNUSED(useColors), int (*setMaterial)(int, void *attribs))
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditFace *efa;
- int i, draw;
-
- (void)setMaterial; /* unused */
-
- if (emdm->vertexCos) {
- EditVert *eve;
-
- for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
- eve->tmp.l = (intptr_t) i++;
-
- for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) {
- int drawSmooth = (efa->flag & ME_SMOOTH);
- draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, i, &drawSmooth);
- if(draw) {
- if (draw==2) { /* enabled with stipple */
- glEnable(GL_POLYGON_STIPPLE);
- glPolygonStipple(stipple_quarttone);
- }
-
- glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
-
- glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
- if (!drawSmooth) {
- glNormal3fv(emdm->faceNos[i]);
- glVertex3fv(emdm->vertexCos[(int) efa->v1->tmp.l]);
- glVertex3fv(emdm->vertexCos[(int) efa->v2->tmp.l]);
- glVertex3fv(emdm->vertexCos[(int) efa->v3->tmp.l]);
- if(efa->v4) glVertex3fv(emdm->vertexCos[(int) efa->v4->tmp.l]);
- } else {
- glNormal3fv(emdm->vertexNos[(int) efa->v1->tmp.l]);
- glVertex3fv(emdm->vertexCos[(int) efa->v1->tmp.l]);
- glNormal3fv(emdm->vertexNos[(int) efa->v2->tmp.l]);
- glVertex3fv(emdm->vertexCos[(int) efa->v2->tmp.l]);
- glNormal3fv(emdm->vertexNos[(int) efa->v3->tmp.l]);
- glVertex3fv(emdm->vertexCos[(int) efa->v3->tmp.l]);
- if(efa->v4) {
- glNormal3fv(emdm->vertexNos[(int) efa->v4->tmp.l]);
- glVertex3fv(emdm->vertexCos[(int) efa->v4->tmp.l]);
- }
- }
- glEnd();
-
- if (draw==2)
- glDisable(GL_POLYGON_STIPPLE);
- }
- }
- } else {
- for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) {
- int drawSmooth = (efa->flag & ME_SMOOTH);
- draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, i, &drawSmooth);
- if(draw) {
- if (draw==2) { /* enabled with stipple */
- glEnable(GL_POLYGON_STIPPLE);
- glPolygonStipple(stipple_quarttone);
- }
- glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
-
- glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
- if (!drawSmooth) {
- glNormal3fv(efa->n);
- glVertex3fv(efa->v1->co);
- glVertex3fv(efa->v2->co);
- glVertex3fv(efa->v3->co);
- if(efa->v4) glVertex3fv(efa->v4->co);
- } else {
- glNormal3fv(efa->v1->no);
- glVertex3fv(efa->v1->co);
- glNormal3fv(efa->v2->no);
- glVertex3fv(efa->v2->co);
- glNormal3fv(efa->v3->no);
- glVertex3fv(efa->v3->co);
- if(efa->v4) {
- glNormal3fv(efa->v4->no);
- glVertex3fv(efa->v4->co);
- }
- }
- glEnd();
-
- if (draw==2)
- glDisable(GL_POLYGON_STIPPLE);
- }
- }
- }
-}
-
-static void emDM_drawFacesTex_common(DerivedMesh *dm,
- int (*drawParams)(MTFace *tface, MCol *mcol, int matnr),
- int (*drawParamsMapped)(void *userData, int index),
- void *userData)
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditMesh *em= emdm->em;
- float (*vertexCos)[3]= emdm->vertexCos;
- float (*vertexNos)[3]= emdm->vertexNos;
- EditFace *efa;
- int i;
-
- /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
- glShadeModel(GL_SMOOTH);
-
- if (vertexCos) {
- EditVert *eve;
-
- for (i=0,eve=em->verts.first; eve; eve= eve->next)
- eve->tmp.l = (intptr_t) i++;
-
- for (i=0,efa= em->faces.first; efa; i++,efa= efa->next) {
- MTFace *tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- MCol *mcol= CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
- unsigned char *cp= NULL;
- int drawSmooth= (efa->flag & ME_SMOOTH);
- int flag;
-
- if(drawParams)
- flag= drawParams(tf, mcol, efa->mat_nr);
- else if(drawParamsMapped)
- flag= drawParamsMapped(userData, i);
- else
- flag= 1;
-
- if(flag != 0) { /* flag 0 == the face is hidden or invisible */
-
- /* we always want smooth here since otherwise vertex colors dont interpolate */
- if (mcol) {
- if (flag==1) {
- cp= (unsigned char*)mcol;
- }
- } else {
- glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
- }
-
- glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
- if (!drawSmooth) {
- glNormal3fv(emdm->faceNos[i]);
-
- if(tf) glTexCoord2fv(tf->uv[0]);
- if(cp) glColor3ub(cp[3], cp[2], cp[1]);
- glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
-
- if(tf) glTexCoord2fv(tf->uv[1]);
- if(cp) glColor3ub(cp[7], cp[6], cp[5]);
- glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
-
- if(tf) glTexCoord2fv(tf->uv[2]);
- if(cp) glColor3ub(cp[11], cp[10], cp[9]);
- glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
-
- if(efa->v4) {
- if(tf) glTexCoord2fv(tf->uv[3]);
- if(cp) glColor3ub(cp[15], cp[14], cp[13]);
- glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
- }
- } else {
- if(tf) glTexCoord2fv(tf->uv[0]);
- if(cp) glColor3ub(cp[3], cp[2], cp[1]);
- glNormal3fv(vertexNos[(int) efa->v1->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
-
- if(tf) glTexCoord2fv(tf->uv[1]);
- if(cp) glColor3ub(cp[7], cp[6], cp[5]);
- glNormal3fv(vertexNos[(int) efa->v2->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
-
- if(tf) glTexCoord2fv(tf->uv[2]);
- if(cp) glColor3ub(cp[11], cp[10], cp[9]);
- glNormal3fv(vertexNos[(int) efa->v3->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
-
- if(efa->v4) {
- if(tf) glTexCoord2fv(tf->uv[3]);
- if(cp) glColor3ub(cp[15], cp[14], cp[13]);
- glNormal3fv(vertexNos[(int) efa->v4->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
- }
- }
- glEnd();
- }
- }
- } else {
- for (i=0,efa= em->faces.first; efa; i++,efa= efa->next) {
- MTFace *tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- MCol *mcol= CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
- unsigned char *cp= NULL;
- int drawSmooth= (efa->flag & ME_SMOOTH);
- int flag;
-
- if(drawParams)
- flag= drawParams(tf, mcol, efa->mat_nr);
- else if(drawParamsMapped)
- flag= drawParamsMapped(userData, i);
- else
- flag= 1;
-
- if(flag != 0) { /* flag 0 == the face is hidden or invisible */
- /* we always want smooth here since otherwise vertex colors dont interpolate */
- if (mcol) {
- if (flag==1) {
- cp= (unsigned char*)mcol;
- }
- } else {
- glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
- }
-
- glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
- if (!drawSmooth) {
- glNormal3fv(efa->n);
-
- if(tf) glTexCoord2fv(tf->uv[0]);
- if(cp) glColor3ub(cp[3], cp[2], cp[1]);
- glVertex3fv(efa->v1->co);
-
- if(tf) glTexCoord2fv(tf->uv[1]);
- if(cp) glColor3ub(cp[7], cp[6], cp[5]);
- glVertex3fv(efa->v2->co);
-
- if(tf) glTexCoord2fv(tf->uv[2]);
- if(cp) glColor3ub(cp[11], cp[10], cp[9]);
- glVertex3fv(efa->v3->co);
-
- if(efa->v4) {
- if(tf) glTexCoord2fv(tf->uv[3]);
- if(cp) glColor3ub(cp[15], cp[14], cp[13]);
- glVertex3fv(efa->v4->co);
- }
- } else {
- if(tf) glTexCoord2fv(tf->uv[0]);
- if(cp) glColor3ub(cp[3], cp[2], cp[1]);
- glNormal3fv(efa->v1->no);
- glVertex3fv(efa->v1->co);
-
- if(tf) glTexCoord2fv(tf->uv[1]);
- if(cp) glColor3ub(cp[7], cp[6], cp[5]);
- glNormal3fv(efa->v2->no);
- glVertex3fv(efa->v2->co);
-
- if(tf) glTexCoord2fv(tf->uv[2]);
- if(cp) glColor3ub(cp[11], cp[10], cp[9]);
- glNormal3fv(efa->v3->no);
- glVertex3fv(efa->v3->co);
-
- if(efa->v4) {
- if(tf) glTexCoord2fv(tf->uv[3]);
- if(cp) glColor3ub(cp[15], cp[14], cp[13]);
- glNormal3fv(efa->v4->no);
- glVertex3fv(efa->v4->co);
- }
- }
- glEnd();
- }
- }
- }
-}
-
-static void emDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
-{
- emDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
-}
-
-static void emDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
-{
- emDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
-}
-
-static void emDM_drawMappedFacesGLSL(DerivedMesh *dm,
- int (*setMaterial)(int, void *attribs),
- int (*setDrawOptions)(void *userData, int index), void *userData)
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditMesh *em= emdm->em;
- float (*vertexCos)[3]= emdm->vertexCos;
- float (*vertexNos)[3]= emdm->vertexNos;
- EditVert *eve;
- EditFace *efa;
- DMVertexAttribs attribs;
- GPUVertexAttribs gattribs;
- MTFace *tf;
- int transp, new_transp, orig_transp, tfoffset;
- int i, b, matnr, new_matnr, dodraw, layer;
-
- dodraw = 0;
- matnr = -1;
-
- transp = GPU_get_material_blend_mode();
- orig_transp = transp;
- layer = CustomData_get_layer_index(&em->fdata, CD_MTFACE);
- tfoffset = (layer == -1)? -1: em->fdata.layers[layer].offset;
-
- memset(&attribs, 0, sizeof(attribs));
-
- /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
- glShadeModel(GL_SMOOTH);
-
- for (i=0,eve=em->verts.first; eve; eve= eve->next)
- eve->tmp.l = (intptr_t) i++;
-
-#define PASSATTRIB(efa, eve, vert) { \
- if(attribs.totorco) { \
- float *orco = attribs.orco.array[eve->tmp.l]; \
- glVertexAttrib3fvARB(attribs.orco.glIndex, orco); \
- } \
- for(b = 0; b < attribs.tottface; b++) { \
- MTFace *_tf = (MTFace*)((char*)efa->data + attribs.tface[b].emOffset); \
- glVertexAttrib2fvARB(attribs.tface[b].glIndex, _tf->uv[vert]); \
- } \
- for(b = 0; b < attribs.totmcol; b++) { \
- MCol *cp = (MCol*)((char*)efa->data + attribs.mcol[b].emOffset); \
- GLubyte col[4]; \
- col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a; \
- glVertexAttrib4ubvARB(attribs.mcol[b].glIndex, col); \
- } \
- if(attribs.tottang) { \
- float *tang = attribs.tang.array[i*4 + vert]; \
- glVertexAttrib4fvARB(attribs.tang.glIndex, tang); \
- } \
-}
-
- for (i=0,efa= em->faces.first; efa; i++,efa= efa->next) {
- int drawSmooth= (efa->flag & ME_SMOOTH);
-
- if(setDrawOptions && !setDrawOptions(userData, i))
- continue;
-
- new_matnr = efa->mat_nr + 1;
- if(new_matnr != matnr) {
- dodraw = setMaterial(matnr = new_matnr, &gattribs);
- if(dodraw)
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- }
-
- if(tfoffset != -1) {
- tf = (MTFace*)((char*)efa->data)+tfoffset;
- new_transp = tf->transp;
-
- if(new_transp != transp) {
- if(new_transp == GPU_BLEND_SOLID && orig_transp != GPU_BLEND_SOLID)
- GPU_set_material_blend_mode(orig_transp);
- else
- GPU_set_material_blend_mode(new_transp);
- transp = new_transp;
- }
- }
-
- if(dodraw) {
- glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
- if (!drawSmooth) {
- if(vertexCos) glNormal3fv(emdm->faceNos[i]);
- else glNormal3fv(efa->n);
-
- PASSATTRIB(efa, efa->v1, 0);
- if(vertexCos) glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
- else glVertex3fv(efa->v1->co);
-
- PASSATTRIB(efa, efa->v2, 1);
- if(vertexCos) glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
- else glVertex3fv(efa->v2->co);
-
- PASSATTRIB(efa, efa->v3, 2);
- if(vertexCos) glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
- else glVertex3fv(efa->v3->co);
-
- if(efa->v4) {
- PASSATTRIB(efa, efa->v4, 3);
- if(vertexCos) glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
- else glVertex3fv(efa->v4->co);
- }
- } else {
- PASSATTRIB(efa, efa->v1, 0);
- if(vertexCos) {
- glNormal3fv(vertexNos[(int) efa->v1->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
- }
- else {
- glNormal3fv(efa->v1->no);
- glVertex3fv(efa->v1->co);
- }
-
- PASSATTRIB(efa, efa->v2, 1);
- if(vertexCos) {
- glNormal3fv(vertexNos[(int) efa->v2->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
- }
- else {
- glNormal3fv(efa->v2->no);
- glVertex3fv(efa->v2->co);
- }
-
- PASSATTRIB(efa, efa->v3, 2);
- if(vertexCos) {
- glNormal3fv(vertexNos[(int) efa->v3->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
- }
- else {
- glNormal3fv(efa->v3->no);
- glVertex3fv(efa->v3->co);
- }
-
- if(efa->v4) {
- PASSATTRIB(efa, efa->v4, 3);
- if(vertexCos) {
- glNormal3fv(vertexNos[(int) efa->v4->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
- }
- else {
- glNormal3fv(efa->v4->no);
- glVertex3fv(efa->v4->co);
- }
- }
- }
- glEnd();
- }
- }
-}
-
-static void emDM_drawFacesGLSL(DerivedMesh *dm,
- int (*setMaterial)(int, void *attribs))
-{
- dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
-}
-
-static void emDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditVert *eve;
- int i;
-
- if (emdm->em->verts.first) {
- for (i=0,eve= emdm->em->verts.first; eve; i++,eve= eve->next) {
- if (emdm->vertexCos) {
- DO_MINMAX(emdm->vertexCos[i], min_r, max_r);
- } else {
- DO_MINMAX(eve->co, min_r, max_r);
- }
- }
- } else {
- min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
- }
-}
-static int emDM_getNumVerts(DerivedMesh *dm)
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
-
- return BLI_countlist(&emdm->em->verts);
-}
-
-static int emDM_getNumEdges(DerivedMesh *dm)
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
-
- return BLI_countlist(&emdm->em->edges);
-}
-
-static int emDM_getNumFaces(DerivedMesh *dm)
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
-
- return BLI_countlist(&emdm->em->faces);
-}
-
-static void emDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3])
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditVert *eve;
- int i;
-
- for (i=0,eve= emdm->em->verts.first; eve; i++,eve=eve->next) {
- if (emdm->vertexCos) {
- copy_v3_v3(cos_r[i], emdm->vertexCos[i]);
- } else {
- copy_v3_v3(cos_r[i], eve->co);
- }
- }
-}
-
-static void emDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
-{
- EditVert *ev = ((EditMeshDerivedMesh *)dm)->em->verts.first;
- int i;
-
- for(i = 0; i < index; ++i) ev = ev->next;
-
- VECCOPY(vert_r->co, ev->co);
-
- vert_r->no[0] = ev->no[0] * 32767.0;
- vert_r->no[1] = ev->no[1] * 32767.0;
- vert_r->no[2] = ev->no[2] * 32767.0;
-
- /* TODO what to do with vert_r->flag? */
- vert_r->bweight = (unsigned char) (ev->bweight*255.0f);
-}
-
-static void emDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
-{
- EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
- EditEdge *ee = em->edges.first;
- EditVert *ev, *v1, *v2;
- int i;
-
- for(i = 0; i < index; ++i) ee = ee->next;
-
- edge_r->crease = (unsigned char) (ee->crease*255.0f);
- edge_r->bweight = (unsigned char) (ee->bweight*255.0f);
- /* TODO what to do with edge_r->flag? */
- edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
- if (ee->seam) edge_r->flag |= ME_SEAM;
- if (ee->sharp) edge_r->flag |= ME_SHARP;
-#if 0
- /* this needs setup of f2 field */
- if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
-#endif
-
- /* goddamn, we have to search all verts to find indices */
- v1 = ee->v1;
- v2 = ee->v2;
- for(i = 0, ev = em->verts.first; v1 || v2; i++, ev = ev->next) {
- if(ev == v1) {
- edge_r->v1 = i;
- v1 = NULL;
- }
- if(ev == v2) {
- edge_r->v2 = i;
- v2 = NULL;
- }
- }
-}
-
-static void emDM_getFace(DerivedMesh *dm, int index, MFace *face_r)
-{
- EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
- EditFace *ef = em->faces.first;
- EditVert *ev, *v1, *v2, *v3, *v4;
- int i;
-
- for(i = 0; i < index; ++i) ef = ef->next;
-
- face_r->mat_nr = ef->mat_nr;
- face_r->flag = ef->flag;
-
- /* goddamn, we have to search all verts to find indices */
- v1 = ef->v1;
- v2 = ef->v2;
- v3 = ef->v3;
- v4 = ef->v4;
- if(!v4) face_r->v4 = 0;
-
- for(i = 0, ev = em->verts.first; v1 || v2 || v3 || v4;
- i++, ev = ev->next) {
- if(ev == v1) {
- face_r->v1 = i;
- v1 = NULL;
- }
- if(ev == v2) {
- face_r->v2 = i;
- v2 = NULL;
- }
- if(ev == v3) {
- face_r->v3 = i;
- v3 = NULL;
- }
- if(ev == v4) {
- face_r->v4 = i;
- v4 = NULL;
- }
- }
-
- test_index_face(face_r, NULL, 0, ef->v4?4:3);
-}
-
-static void emDM_copyVertArray(DerivedMesh *dm, MVert *vert_r)
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditVert *ev = emdm->em->verts.first;
- int i;
-
- for(i=0; ev; ev = ev->next, ++vert_r, ++i) {
- if(emdm->vertexCos)
- copy_v3_v3(vert_r->co, emdm->vertexCos[i]);
- else
- copy_v3_v3(vert_r->co, ev->co);
-
- vert_r->no[0] = ev->no[0] * 32767.0;
- vert_r->no[1] = ev->no[1] * 32767.0;
- vert_r->no[2] = ev->no[2] * 32767.0;
-
- /* TODO what to do with vert_r->flag? */
- vert_r->flag = 0;
- vert_r->bweight = (unsigned char) (ev->bweight*255.0f);
- }
-}
-
-static void emDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
-{
- EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
- EditEdge *ee = em->edges.first;
- EditVert *ev;
- int i;
-
- /* store vertex indices in tmp union */
- for(ev = em->verts.first, i = 0; ev; ev = ev->next, ++i)
- ev->tmp.l = (intptr_t) i;
-
- for( ; ee; ee = ee->next, ++edge_r) {
- edge_r->crease = (unsigned char) (ee->crease*255.0f);
- edge_r->bweight = (unsigned char) (ee->bweight*255.0f);
- /* TODO what to do with edge_r->flag? */
- edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
- if (ee->seam) edge_r->flag |= ME_SEAM;
- if (ee->sharp) edge_r->flag |= ME_SHARP;
-#if 0
- /* this needs setup of f2 field */
- if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
-#endif
-
- edge_r->v1 = (int)ee->v1->tmp.l;
- edge_r->v2 = (int)ee->v2->tmp.l;
- }
-}
-
-static void emDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
-{
- EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
- EditFace *ef = em->faces.first;
- EditVert *ev;
- int i;
-
- /* store vertexes indices in tmp union */
- for(ev = em->verts.first, i = 0; ev; ev = ev->next, ++i)
- ev->tmp.l = (intptr_t) i;
-
- for( ; ef; ef = ef->next, ++face_r) {
- face_r->mat_nr = ef->mat_nr;
- face_r->flag = ef->flag;
-
- face_r->v1 = (int)ef->v1->tmp.l;
- face_r->v2 = (int)ef->v2->tmp.l;
- face_r->v3 = (int)ef->v3->tmp.l;
- if(ef->v4) face_r->v4 = (int)ef->v4->tmp.l;
- else face_r->v4 = 0;
-
- test_index_face(face_r, NULL, 0, ef->v4?4:3);
- }
-}
-
-static void *emDM_getFaceDataArray(DerivedMesh *dm, int type)
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditMesh *em= emdm->em;
- EditFace *efa;
- char *data, *emdata;
- void *datalayer;
- int index, size;
-
- datalayer = DM_get_face_data_layer(dm, type);
- if(datalayer)
- return datalayer;
-
- /* layers are store per face for editmesh, we convert to a temporary
- * data layer array in the derivedmesh when these are requested */
- if(type == CD_MTFACE || type == CD_MCOL) {
- index = CustomData_get_layer_index(&em->fdata, type);
-
- if(index != -1) {
- /* int offset = em->fdata.layers[index].offset; */ /* UNUSED */
- size = CustomData_sizeof(type);
-
- DM_add_face_layer(dm, type, CD_CALLOC, NULL);
- index = CustomData_get_layer_index(&dm->faceData, type);
- dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY;
-
- data = datalayer = DM_get_face_data_layer(dm, type);
- for(efa=em->faces.first; efa; efa=efa->next, data+=size) {
- emdata = CustomData_em_get(&em->fdata, efa->data, type);
- memcpy(data, emdata, size);
- }
- }
- }
-
- return datalayer;
-}
-
-static void emDM_release(DerivedMesh *dm)
-{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
-
- if (DM_release(dm)) {
- if (emdm->vertexCos) {
- MEM_freeN(emdm->vertexCos);
- MEM_freeN(emdm->vertexNos);
- MEM_freeN(emdm->faceNos);
- }
-
- MEM_freeN(emdm);
- }
-}
-
-DerivedMesh *editmesh_get_derived(EditMesh *em, float (*vertexCos)[3])
-{
- EditMeshDerivedMesh *emdm = MEM_callocN(sizeof(*emdm), "emdm");
-
- DM_init(&emdm->dm, DM_TYPE_EDITMESH, BLI_countlist(&em->verts),
- BLI_countlist(&em->edges), BLI_countlist(&em->faces));
-
- emdm->dm.getMinMax = emDM_getMinMax;
-
- emdm->dm.getNumVerts = emDM_getNumVerts;
- emdm->dm.getNumEdges = emDM_getNumEdges;
- emdm->dm.getNumFaces = emDM_getNumFaces;
-
- emdm->dm.getVertCos = emDM_getVertCos;
-
- emdm->dm.getVert = emDM_getVert;
- emdm->dm.getEdge = emDM_getEdge;
- emdm->dm.getFace = emDM_getFace;
- emdm->dm.copyVertArray = emDM_copyVertArray;
- emdm->dm.copyEdgeArray = emDM_copyEdgeArray;
- emdm->dm.copyFaceArray = emDM_copyFaceArray;
- emdm->dm.getFaceDataArray = emDM_getFaceDataArray;
-
- emdm->dm.foreachMappedVert = emDM_foreachMappedVert;
- emdm->dm.foreachMappedEdge = emDM_foreachMappedEdge;
- emdm->dm.foreachMappedFaceCenter = emDM_foreachMappedFaceCenter;
-
- emdm->dm.drawEdges = emDM_drawEdges;
- emdm->dm.drawMappedEdges = emDM_drawMappedEdges;
- emdm->dm.drawMappedEdgesInterp = emDM_drawMappedEdgesInterp;
- emdm->dm.drawMappedFaces = emDM_drawMappedFaces;
- emdm->dm.drawMappedFacesTex = emDM_drawMappedFacesTex;
- emdm->dm.drawMappedFacesGLSL = emDM_drawMappedFacesGLSL;
- emdm->dm.drawFacesTex = emDM_drawFacesTex;
- emdm->dm.drawFacesGLSL = emDM_drawFacesGLSL;
- emdm->dm.drawUVEdges = emDM_drawUVEdges;
-
- emdm->dm.release = emDM_release;
-
- emdm->em = em;
- emdm->vertexCos = vertexCos;
-
- if(CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
- EditVert *eve;
- int i;
-
- DM_add_vert_layer(&emdm->dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
-
- for(eve = em->verts.first, i = 0; eve; eve = eve->next, ++i)
- DM_set_vert_data(&emdm->dm, i, CD_MDEFORMVERT,
- CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT));
- }
-
- if(vertexCos) {
- EditVert *eve;
- EditFace *efa;
- int totface = BLI_countlist(&em->faces);
- int i;
-
- for (i=0,eve=em->verts.first; eve; eve= eve->next)
- eve->tmp.l = (intptr_t) i++;
-
- emdm->vertexNos = MEM_callocN(sizeof(*emdm->vertexNos)*i, "emdm_vno");
- emdm->faceNos = MEM_mallocN(sizeof(*emdm->faceNos)*totface, "emdm_vno");
-
- for(i=0, efa= em->faces.first; efa; i++, efa=efa->next) {
- float *v1 = vertexCos[(int) efa->v1->tmp.l];
- float *v2 = vertexCos[(int) efa->v2->tmp.l];
- float *v3 = vertexCos[(int) efa->v3->tmp.l];
- float *no = emdm->faceNos[i];
-
- if(efa->v4) {
- float *v4 = vertexCos[(int) efa->v4->tmp.l];
-
- normal_quad_v3( no,v1, v2, v3, v4);
- add_v3_v3(emdm->vertexNos[(int) efa->v4->tmp.l], no);
- }
- else {
- normal_tri_v3( no,v1, v2, v3);
- }
-
- add_v3_v3(emdm->vertexNos[(int) efa->v1->tmp.l], no);
- add_v3_v3(emdm->vertexNos[(int) efa->v2->tmp.l], no);
- add_v3_v3(emdm->vertexNos[(int) efa->v3->tmp.l], no);
- }
-
- for(i=0, eve= em->verts.first; eve; i++, eve=eve->next) {
- float *no = emdm->vertexNos[i];
- /* following Mesh convention; we use vertex coordinate itself
- * for normal in this case */
- if (normalize_v3(no)==0.0) {
- normalize_v3_v3(no, vertexCos[i]);
- }
- }
- }
-
- return (DerivedMesh*) emdm;
-}
-
/***/
DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob, ModifierData *md)
@@ -1460,30 +696,29 @@ DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob, Modifier
return dm;
}
-static float *get_editmesh_orco_verts(EditMesh *em)
+static float *get_editbmesh_orco_verts(BMEditMesh *em)
{
- EditVert *eve;
+ BMIter iter;
+ BMVert *eve;
float *orco;
int a, totvert;
/* these may not really be the orco's, but it's only for preview.
* could be solver better once, but isn't simple */
- totvert= 0;
- for(eve=em->verts.first; eve; eve=eve->next)
- totvert++;
+ totvert= em->bm->totvert;
orco = MEM_mallocN(sizeof(float)*3*totvert, "EditMesh Orco");
- for(a=0, eve=em->verts.first; eve; eve=eve->next, a+=3)
+ eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for (a=0; eve; eve=BMIter_Step(&iter), a+=3)
VECCOPY(orco+a, eve->co);
return orco;
}
/* orco custom data layer */
-
-static void *get_orco_coords_dm(Object *ob, EditMesh *em, int layer, int *free)
+static void *get_orco_coords_dm(Object *ob, BMEditMesh *em, int layer, int *free)
{
*free= 0;
@@ -1492,7 +727,7 @@ static void *get_orco_coords_dm(Object *ob, EditMesh *em, int layer, int *free)
*free= 1;
if(em)
- return (float(*)[3])get_editmesh_orco_verts(em);
+ return (float(*)[3])get_editbmesh_orco_verts(em);
else
return (float(*)[3])get_mesh_orco_verts(ob);
}
@@ -1513,13 +748,13 @@ static void *get_orco_coords_dm(Object *ob, EditMesh *em, int layer, int *free)
return NULL;
}
-static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, EditMesh *em, int layer)
+static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, BMEditMesh *em, int layer)
{
DerivedMesh *dm;
float (*orco)[3];
int free;
- if(em) dm= CDDM_from_editmesh(em, me);
+ if(em) dm= CDDM_from_BMEditMesh(em, me);
else dm= CDDM_from_mesh(me, ob);
orco= get_orco_coords_dm(ob, em, layer, &free);
@@ -1534,7 +769,8 @@ static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, EditMesh *em, int layer
return dm;
}
-static void add_orco_dm(Object *ob, EditMesh *em, DerivedMesh *dm, DerivedMesh *orcodm, int layer)
+static void add_orco_dm(Object *ob, BMEditMesh *em, DerivedMesh *dm,
+ DerivedMesh *orcodm, int layer)
{
float (*orco)[3], (*layerorco)[3];
int totvert, free;
@@ -1638,15 +874,21 @@ void vDM_ColorBand_store(ColorBand *coba)
static void add_weight_mcol_dm(Object *ob, DerivedMesh *dm)
{
Mesh *me = ob->data;
- MFace *mf = me->mface;
+ MFace *mf = dm->getTessFaceArray(dm);
+ DMFaceIter *dfiter;
+ DMLoopIter *dliter;
ColorBand *coba= stored_cb; /* warning, not a local var */
unsigned char *wtcol;
- int i;
+ unsigned char(*wlcol)[4] = NULL;
+ BLI_array_declare(wlcol);
+ int i, totface=dm->getNumTessFaces(dm), totpoly=dm->getNumFaces, totloop;
+ int *origIndex = dm->getVertDataArray(dm, CD_ORIGINDEX);
- wtcol = MEM_callocN (sizeof (unsigned char) * me->totface*4*4, "weightmap");
+ wtcol = MEM_callocN (sizeof (unsigned char) * totface*4*4, "weightmap");
- memset(wtcol, 0x55, sizeof (unsigned char) * me->totface*4*4);
- for (i=0; i<me->totface; i++, mf++) {
+ /*first add colors to the tesselation faces*/
+ memset(wtcol, 0x55, sizeof (unsigned char) * totface*4*4);
+ for (i=0; i<totface; i++, mf++) {
calc_weightpaint_vert_color(ob, coba, mf->v1, &wtcol[(i*4 + 0)*4]);
calc_weightpaint_vert_color(ob, coba, mf->v2, &wtcol[(i*4 + 1)*4]);
calc_weightpaint_vert_color(ob, coba, mf->v3, &wtcol[(i*4 + 2)*4]);
@@ -1654,7 +896,23 @@ static void add_weight_mcol_dm(Object *ob, DerivedMesh *dm)
calc_weightpaint_vert_color(ob, coba, mf->v4, &wtcol[(i*4 + 3)*4]);
}
- CustomData_add_layer(&dm->faceData, CD_WEIGHT_MCOL, CD_ASSIGN, wtcol, dm->numFaceData);
+ CustomData_add_layer(&dm->faceData, CD_WEIGHT_MCOL, CD_ASSIGN, wtcol, totface);
+
+ /*now add to loops, so the data can be passed through the modifier stack*/
+ totloop = 0;
+ dfiter = dm->newFaceIter(dm);
+ for (; !dfiter->done; dfiter->step(dfiter)) {
+ dliter = dfiter->getLoopsIter(dfiter);
+ for (; !dliter->done; dliter->step(dliter), totloop++) {
+ BLI_array_growone(wlcol);
+ calc_weightpaint_vert_color(ob, coba, dliter->vindex, (unsigned
+char *)&wlcol[totloop]);
+ }
+ }
+
+ CustomData_add_layer(&dm->loopData, CD_WEIGHT_MLOOPCOL, CD_ASSIGN, wlcol, totloop);
+
+ dfiter->free(dfiter);
}
/* new value for useDeform -1 (hack for the gameengine):
@@ -1835,7 +1093,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
/* apply vertex coordinates or build a DerivedMesh as necessary */
if(dm) {
if(deformedVerts) {
- DerivedMesh *tdm = CDDM_copy(dm);
+ DerivedMesh *tdm = CDDM_copy(dm, 0);
dm->release(dm);
dm = tdm;
@@ -1861,14 +1119,19 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
* data by using generic DM_copy_vert_data() functions.
*/
if(needMapping || (nextmask & CD_MASK_ORIGINDEX)) {
+ int i, *orig;
+
/* calc */
DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
DM_add_face_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
- range_vni(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0);
- range_vni(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0);
- range_vni(DM_get_face_data_layer(dm, CD_ORIGINDEX), dm->numFaceData, 0);
+ orig = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
+ for(i=0; i<dm->numVertData; i++) *orig++= i;
+ orig = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
+ for(i=0; i<dm->numEdgeData; i++) *orig++= i;
+ orig = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+ for(i=0; i<dm->numPolyData; i++) *orig++= i;
}
}
@@ -1884,7 +1147,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
/* add an origspace layer if needed */
if(((CustomDataMask)GET_INT_FROM_POINTER(curr->link)) & CD_MASK_ORIGSPACE)
if(!CustomData_has_layer(&dm->faceData, CD_ORIGSPACE))
- DM_add_face_layer(dm, CD_ORIGSPACE, CD_DEFAULT, NULL);
+ DM_add_tessface_layer(dm, CD_ORIGSPACE, CD_DEFAULT, NULL);
ndm = mti->applyModifier(md, ob, dm, useRenderParams, useCache);
@@ -1953,7 +1216,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
* DerivedMesh then we need to build one.
*/
if(dm && deformedVerts) {
- finaldm = CDDM_copy(dm);
+ finaldm = CDDM_copy(dm, 0);
dm->release(dm);
@@ -1997,21 +1260,24 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
BLI_linklist_free(datamasks, NULL);
}
-float (*editmesh_get_vertex_cos(EditMesh *em, int *numVerts_r))[3]
+float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *numVerts_r))[3]
{
- int i, numVerts = *numVerts_r = BLI_countlist(&em->verts);
+ int i, numVerts = *numVerts_r = em->bm->totvert;
float (*cos)[3];
- EditVert *eve;
+ BMIter iter;
+ BMVert *eve;
cos = MEM_mallocN(sizeof(*cos)*numVerts, "vertexcos");
- for (i=0,eve=em->verts.first; i<numVerts; i++,eve=eve->next) {
+
+ eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++) {
VECCOPY(cos[i], eve->co);
}
return cos;
}
-int editmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *dm)
+int editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *dm)
{
ModifierTypeInfo *mti = modifierType_getInfo(md->type);
int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
@@ -2025,7 +1291,7 @@ int editmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *dm
return 1;
}
-static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, DerivedMesh **cage_r,
+static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, DerivedMesh **cage_r,
DerivedMesh **final_r,
CustomDataMask dataMask)
{
@@ -2040,7 +1306,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
modifiers_clearErrors(ob);
if(cage_r && cageIndex == -1) {
- *cage_r = editmesh_get_derived(em, NULL);
+ *cage_r = getEditDerivedBMesh(em, ob, NULL);
}
dm = NULL;
@@ -2054,7 +1320,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
md->scene= scene;
- if(!editmesh_modifier_is_enabled(scene, md, dm))
+ if(!editbmesh_modifier_is_enabled(scene, md, dm))
continue;
/* add an orco layer if needed by this modifier */
@@ -2082,7 +1348,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv");
dm->getVertCos(dm, deformedVerts);
} else {
- deformedVerts = editmesh_get_vertex_cos(em, &numVerts);
+ deformedVerts = editbmesh_get_vertex_cos(em, &numVerts);
}
}
@@ -2095,7 +1361,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
/* apply vertex coordinates or build a DerivedMesh as necessary */
if(dm) {
if(deformedVerts) {
- DerivedMesh *tdm = CDDM_copy(dm);
+ DerivedMesh *tdm = CDDM_copy(dm, 0);
if(!(cage_r && dm == *cage_r)) dm->release(dm);
dm = tdm;
@@ -2104,11 +1370,11 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
} else if(cage_r && dm == *cage_r) {
/* dm may be changed by this modifier, so we need to copy it
*/
- dm = CDDM_copy(dm);
+ dm = CDDM_copy(dm, 0);
}
} else {
- dm = CDDM_from_editmesh(em, ob->data);
+ dm = CDDM_from_BMEditMesh(em, ob->data);
if(deformedVerts) {
CDDM_apply_vert_coords(dm, deformedVerts);
@@ -2144,7 +1410,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
if(mask & CD_MASK_ORIGSPACE)
if(!CustomData_has_layer(&dm->faceData, CD_ORIGSPACE))
- DM_add_face_layer(dm, CD_ORIGSPACE, CD_DEFAULT, NULL);
+ DM_add_tessface_layer(dm, CD_ORIGSPACE, CD_DEFAULT, NULL);
if (mti->applyModifierEM)
ndm = mti->applyModifierEM(md, ob, em, dm);
@@ -2166,13 +1432,13 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
if(cage_r && i == cageIndex) {
if(dm && deformedVerts) {
- *cage_r = CDDM_copy(dm);
+ *cage_r = CDDM_copy(dm, 0);
CDDM_apply_vert_coords(*cage_r, deformedVerts);
} else if(dm) {
*cage_r = dm;
} else {
*cage_r =
- editmesh_get_derived(em,
+ getEditDerivedBMesh(em, ob,
deformedVerts ? MEM_dupallocN(deformedVerts) : NULL);
}
}
@@ -2185,7 +1451,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
* then we need to build one.
*/
if(dm && deformedVerts) {
- *final_r = CDDM_copy(dm);
+ *final_r = CDDM_copy(dm, 0);
if(!(cage_r && dm == *cage_r)) dm->release(dm);
@@ -2196,7 +1462,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
} else if (!deformedVerts && cage_r && *cage_r) {
*final_r = *cage_r;
} else {
- *final_r = editmesh_get_derived(em, deformedVerts);
+ *final_r = getEditDerivedBMesh(em, ob, deformedVerts);
deformedVerts = NULL;
}
@@ -2263,7 +1529,7 @@ static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask)
ob->lastDataMask = dataMask;
}
-static void editmesh_build_data(Scene *scene, Object *obedit, EditMesh *em, CustomDataMask dataMask)
+static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, CustomDataMask dataMask)
{
clear_mesh_caches(obedit);
@@ -2280,7 +1546,7 @@ static void editmesh_build_data(Scene *scene, Object *obedit, EditMesh *em, Cust
em->derivedCage = NULL;
}
- editmesh_calc_modifiers(scene, obedit, em, &em->derivedCage, &em->derivedFinal, dataMask);
+ editbmesh_calc_modifiers(scene, obedit, em, &em->derivedCage, &em->derivedFinal, dataMask);
DM_set_object_boundbox (obedit, em->derivedFinal);
em->lastDataMask = dataMask;
@@ -2288,10 +1554,10 @@ static void editmesh_build_data(Scene *scene, Object *obedit, EditMesh *em, Cust
em->derivedCage->needsFree = 0;
}
-void makeDerivedMesh(Scene *scene, Object *ob, EditMesh *em, CustomDataMask dataMask)
+void makeDerivedMesh(Scene *scene, Object *ob, BMEditMesh *em, CustomDataMask dataMask)
{
if (em) {
- editmesh_build_data(scene, ob, em, dataMask);
+ editbmesh_build_data(scene, ob, em, dataMask);
} else {
mesh_build_data(scene, ob, dataMask);
}
@@ -2391,7 +1657,7 @@ DerivedMesh *mesh_create_derived_no_deform_render(Scene *scene, Object *ob,
/***/
-DerivedMesh *editmesh_get_derived_cage_and_final(Scene *scene, Object *obedit, EditMesh *em, DerivedMesh **final_r,
+DerivedMesh *editbmesh_get_derived_cage_and_final(Scene *scene, Object *obedit, BMEditMesh *em, DerivedMesh **final_r,
CustomDataMask dataMask)
{
/* if there's no derived mesh or the last data mask used doesn't include
@@ -2399,27 +1665,27 @@ DerivedMesh *editmesh_get_derived_cage_and_final(Scene *scene, Object *obedit, E
*/
if(!em->derivedCage ||
(em->lastDataMask & dataMask) != dataMask)
- editmesh_build_data(scene, obedit, em, dataMask);
+ editbmesh_build_data(scene, obedit, em, dataMask);
*final_r = em->derivedFinal;
return em->derivedCage;
}
-DerivedMesh *editmesh_get_derived_cage(Scene *scene, Object *obedit, EditMesh *em, CustomDataMask dataMask)
+DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh *em, CustomDataMask dataMask)
{
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
if(!em->derivedCage ||
(em->lastDataMask & dataMask) != dataMask)
- editmesh_build_data(scene, obedit, em, dataMask);
+ editbmesh_build_data(scene, obedit, em, dataMask);
return em->derivedCage;
}
-DerivedMesh *editmesh_get_derived_base(Object *UNUSED(obedit), EditMesh *em)
+DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em)
{
- return editmesh_get_derived(em, NULL);
+ return getEditDerivedBMesh(em, obedit, NULL);
}
@@ -2603,15 +1869,15 @@ void DM_add_tangent_layer(DerivedMesh *dm)
if(CustomData_get_layer_index(&dm->faceData, CD_TANGENT) != -1)
return;
- nors = dm->getFaceDataArray(dm, CD_NORMAL);
+ nors = dm->getTessFaceDataArray(dm, CD_NORMAL);
/* check we have all the needed layers */
totvert= dm->getNumVerts(dm);
- totface= dm->getNumFaces(dm);
+ totface= dm->getNumTessFaces(dm);
mvert= dm->getVertArray(dm);
- mface= dm->getFaceArray(dm);
- mtface= dm->getFaceDataArray(dm, CD_MTFACE);
+ mface= dm->getTessFaceArray(dm);
+ mtface= dm->getTessFaceDataArray(dm, CD_MTFACE);
if(!mtface) {
orco= dm->getVertDataArray(dm, CD_ORCO);
@@ -2620,8 +1886,8 @@ void DM_add_tangent_layer(DerivedMesh *dm)
}
/* create tangent layer */
- DM_add_face_layer(dm, CD_TANGENT, CD_CALLOC, NULL);
- tangent= DM_get_face_data_layer(dm, CD_TANGENT);
+ DM_add_tessface_layer(dm, CD_TANGENT, CD_CALLOC, NULL);
+ tangent= DM_get_tessface_data_layer(dm, CD_TANGENT);
/* allocate some space */
arena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "tangent layer arena");
@@ -2747,15 +2013,8 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
memset(attribs, 0, sizeof(DMVertexAttribs));
vdata = &dm->vertData;
- fdata = &dm->faceData;
-
- /* ugly hack, editmesh derivedmesh doesn't copy face data, this way we
- * can use offsets instead */
- if(dm->release == emDM_release)
- tfdata = &((EditMeshDerivedMesh*)dm)->em->fdata;
- else
- tfdata = fdata;
-
+ fdata = tfdata = dm->getTessFaceDataLayout(dm);
+
/* add a tangent layer if necessary */
for(b = 0; b < gattribs->totlayer; b++)
if(gattribs->layer[b].type == CD_TANGENT)
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index a8c369a9b7b..5842197da48 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -47,6 +47,8 @@
#include "DNA_key_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_view3d_types.h"
#include "DNA_vfont_types.h"
#include "BKE_animsys.h"
@@ -64,6 +66,7 @@
#include "BKE_particle.h"
#include "BKE_scene.h"
#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
#include "BKE_depsgraph.h"
#include "BKE_anim.h"
@@ -880,7 +883,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl
Scene *sce = NULL;
Group *group = NULL;
GroupObject * go = NULL;
- EditMesh *em;
+ BMEditMesh *em;
float vec[3], no[3], pmat[4][4];
int totvert, a, oblay;
unsigned int lay;
@@ -890,11 +893,10 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl
/* simple preventing of too deep nested groups */
if(level>MAX_DUPLI_RECUR) return;
- em = BKE_mesh_get_editmesh(me);
+ em = me->edit_btmesh;
if(em) {
- dm= editmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
- BKE_mesh_end_editmesh(me, em);
+ dm= editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
} else
dm= mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH);
@@ -956,7 +958,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl
/* mballs have a different dupli handling */
if(ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */
- if(me->edit_mesh) {
+ if(me->edit_btmesh) {
dm->foreachMappedVert(dm, vertex_dupli__mapFunc, (void*) &vdd);
}
else {
@@ -1005,34 +1007,31 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
Scene *sce = NULL;
Group *group = NULL;
GroupObject *go = NULL;
- EditMesh *em;
+ BMEditMesh *em;
float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */
/* simple preventing of too deep nested groups */
if(level>MAX_DUPLI_RECUR) return;
copy_m4_m4(pmat, par->obmat);
-
- em = BKE_mesh_get_editmesh(me);
+ em = me->edit_btmesh;
+
if(em) {
int totvert;
+ dm= editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
- dm= editmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
-
- totface= dm->getNumFaces(dm);
+ totface= dm->getNumTessFaces(dm);
mface= MEM_mallocN(sizeof(MFace)*totface, "mface temp");
- dm->copyFaceArray(dm, mface);
+ dm->copyTessFaceArray(dm, mface);
totvert= dm->getNumVerts(dm);
mvert= MEM_mallocN(sizeof(MVert)*totvert, "mvert temp");
dm->copyVertArray(dm, mvert);
-
- BKE_mesh_end_editmesh(me, em);
}
else {
dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH);
- totface= dm->getNumFaces(dm);
- mface= dm->getFaceArray(dm);
+ totface= dm->getNumTessFaces(dm);
+ mface= dm->getTessFaceArray(dm);
mvert= dm->getVertArray(dm);
}
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 49c151947a4..b9ff4c2a30b 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -36,6 +36,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
+#include "BLI_cellalloc.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index e34b4bef8d4..0556acbdece 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -448,6 +448,8 @@ static int read_undosave(bContext *C, UndoElem *uel)
BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */
+ strcpy(mainstr, G.main->name); /* temporal store */
+
fileflags= G.fileflags;
G.fileflags |= G_FILE_NO_UI;
@@ -675,10 +677,18 @@ char *BKE_undo_menu_string(void)
/* saves quit.blend */
void BKE_undo_save_quit(void)
{
+ char str[FILE_MAXDIR+FILE_MAXFILE];
+
+ BLI_make_file_string("/", str, btempdir, "quit.blend");
+
+ BKE_undo_save(str);
+}
+
+void BKE_undo_save(char *fname)
+{
UndoElem *uel;
MemFileChunk *chunk;
int file;
- char str[FILE_MAXDIR+FILE_MAXFILE];
if( (U.uiflag & USER_GLOBALUNDO)==0) return;
@@ -691,9 +701,7 @@ void BKE_undo_save_quit(void)
/* no undo state to save */
if(undobase.first==undobase.last) return;
- BLI_make_file_string("/", str, btempdir, "quit.blend");
-
- file = open(str,O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666);
+ file = open(fname, O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666);
if(file == -1) {
//XXX error("Unable to save %s, check you have permissions", str);
return;
@@ -707,8 +715,8 @@ void BKE_undo_save_quit(void)
close(file);
- if(chunk) ; //XXX error("Unable to save %s, internal error", str);
- else printf("Saved session recovery to %s\n", str);
+ if(chunk) ; //XXX error("Unable to save %s, internal error", fname);
+ else printf("Saved session recovery to %s\n", fname);
}
/* sets curscene */
diff --git a/source/blender/blenkernel/intern/booleanops.c b/source/blender/blenkernel/intern/booleanops.c
new file mode 100644
index 00000000000..f9df0beca7c
--- /dev/null
+++ b/source/blender/blenkernel/intern/booleanops.c
@@ -0,0 +1,603 @@
+/**
+ * $Id$
+ *
+ * ***** 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) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * CSG operations.
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "CSG_BooleanOps.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+
+
+/**
+ * Here's the vertex iterator structure used to walk through
+ * the blender vertex structure.
+ */
+
+typedef struct {
+ DerivedMesh *dm;
+ Object *ob;
+ int pos;
+} VertexIt;
+
+/**
+ * Implementations of local vertex iterator functions.
+ * These describe a blender mesh to the CSG module.
+ */
+
+static void VertexIt_Destruct(CSG_VertexIteratorDescriptor * iterator)
+{
+ if (iterator->it) {
+ // deallocate memory for iterator
+ MEM_freeN(iterator->it);
+ iterator->it = 0;
+ }
+ iterator->Done = NULL;
+ iterator->Fill = NULL;
+ iterator->Reset = NULL;
+ iterator->Step = NULL;
+ iterator->num_elements = 0;
+
+}
+
+static int VertexIt_Done(CSG_IteratorPtr it)
+{
+ VertexIt * iterator = (VertexIt *)it;
+ return(iterator->pos >= iterator->dm->getNumVerts(iterator->dm));
+}
+
+static void VertexIt_Fill(CSG_IteratorPtr it, CSG_IVertex *vert)
+{
+ VertexIt * iterator = (VertexIt *)it;
+ MVert *verts = iterator->dm->getVertArray(iterator->dm);
+
+ float global_pos[3];
+
+ /* boolean happens in global space, transform both with obmat */
+ mul_v3_m4v3(
+ global_pos,
+ iterator->ob->obmat,
+ verts[iterator->pos].co
+ );
+
+ vert->position[0] = global_pos[0];
+ vert->position[1] = global_pos[1];
+ vert->position[2] = global_pos[2];
+}
+
+static void VertexIt_Step(CSG_IteratorPtr it)
+{
+ VertexIt * iterator = (VertexIt *)it;
+ iterator->pos ++;
+}
+
+static void VertexIt_Reset(CSG_IteratorPtr it)
+{
+ VertexIt * iterator = (VertexIt *)it;
+ iterator->pos = 0;
+}
+
+static void VertexIt_Construct(CSG_VertexIteratorDescriptor *output, DerivedMesh *dm, Object *ob)
+{
+
+ VertexIt *it;
+ if (output == 0) return;
+
+ // allocate some memory for blender iterator
+ it = (VertexIt *)(MEM_mallocN(sizeof(VertexIt),"Boolean_VIt"));
+ if (it == 0) {
+ return;
+ }
+ // assign blender specific variables
+ it->dm = dm;
+ it->ob = ob; // needed for obmat transformations
+
+ it->pos = 0;
+
+ // assign iterator function pointers.
+ output->Step = VertexIt_Step;
+ output->Fill = VertexIt_Fill;
+ output->Done = VertexIt_Done;
+ output->Reset = VertexIt_Reset;
+ output->num_elements = it->dm->getNumVerts(it->dm);
+ output->it = it;
+}
+
+/**
+ * Blender Face iterator
+ */
+
+typedef struct {
+ DerivedMesh *dm;
+ int pos;
+ int offset;
+ int flip;
+} FaceIt;
+
+static void FaceIt_Destruct(CSG_FaceIteratorDescriptor * iterator)
+{
+ MEM_freeN(iterator->it);
+ iterator->Done = NULL;
+ iterator->Fill = NULL;
+ iterator->Reset = NULL;
+ iterator->Step = NULL;
+ iterator->num_elements = 0;
+}
+
+static int FaceIt_Done(CSG_IteratorPtr it)
+{
+ // assume CSG_IteratorPtr is of the correct type.
+ FaceIt * iterator = (FaceIt *)it;
+ return(iterator->pos >= iterator->dm->getNumTessFaces(iterator->dm));
+}
+
+static void FaceIt_Fill(CSG_IteratorPtr it, CSG_IFace *face)
+{
+ // assume CSG_IteratorPtr is of the correct type.
+ FaceIt *face_it = (FaceIt *)it;
+ MFace *mfaces = face_it->dm->getTessFaceArray(face_it->dm);
+ MFace *mface = &mfaces[face_it->pos];
+
+ /* reverse face vertices if necessary */
+ face->vertex_index[1] = mface->v2;
+ if( face_it->flip == 0 ) {
+ face->vertex_index[0] = mface->v1;
+ face->vertex_index[2] = mface->v3;
+ } else {
+ face->vertex_index[2] = mface->v1;
+ face->vertex_index[0] = mface->v3;
+ }
+ if (mface->v4) {
+ face->vertex_index[3] = mface->v4;
+ face->vertex_number = 4;
+ } else {
+ face->vertex_number = 3;
+ }
+
+ face->orig_face = face_it->offset + face_it->pos;
+}
+
+static void FaceIt_Step(CSG_IteratorPtr it)
+{
+ FaceIt * face_it = (FaceIt *)it;
+ face_it->pos ++;
+}
+
+static void FaceIt_Reset(CSG_IteratorPtr it)
+{
+ FaceIt * face_it = (FaceIt *)it;
+ face_it->pos = 0;
+}
+
+static void FaceIt_Construct(
+ CSG_FaceIteratorDescriptor *output, DerivedMesh *dm, int offset, Object *ob)
+{
+ FaceIt *it;
+ if (output == 0) return;
+
+ // allocate some memory for blender iterator
+ it = (FaceIt *)(MEM_mallocN(sizeof(FaceIt),"Boolean_FIt"));
+ if (it == 0) {
+ return ;
+ }
+ // assign blender specific variables
+ it->dm = dm;
+ it->offset = offset;
+ it->pos = 0;
+
+ /* determine if we will need to reverse order of face vertices */
+ if (ob->size[0] < 0.0f) {
+ if (ob->size[1] < 0.0f && ob->size[2] < 0.0f) {
+ it->flip = 1;
+ } else if (ob->size[1] >= 0.0f && ob->size[2] >= 0.0f) {
+ it->flip = 1;
+ } else {
+ it->flip = 0;
+ }
+ } else {
+ if (ob->size[1] < 0.0f && ob->size[2] < 0.0f) {
+ it->flip = 0;
+ } else if (ob->size[1] >= 0.0f && ob->size[2] >= 0.0f) {
+ it->flip = 0;
+ } else {
+ it->flip = 1;
+ }
+ }
+
+ // assign iterator function pointers.
+ output->Step = FaceIt_Step;
+ output->Fill = FaceIt_Fill;
+ output->Done = FaceIt_Done;
+ output->Reset = FaceIt_Reset;
+ output->num_elements = it->dm->getNumTessFaces(it->dm);
+ output->it = it;
+}
+
+static Object *AddNewBlenderMesh(Scene *scene, Base *base)
+{
+ // This little function adds a new mesh object to the blender object list
+ // It uses ob to duplicate data as this seems to be easier than creating
+ // a new one. This new oject contains no faces nor vertices.
+ Mesh *old_me;
+ Base *basen;
+ Object *ob_new;
+
+ // now create a new blender object.
+ // duplicating all the settings from the previous object
+ // to the new one.
+ ob_new= copy_object(base->object);
+
+ // Ok we don't want to use the actual data from the
+ // last object, the above function incremented the
+ // number of users, so decrement it here.
+ old_me= ob_new->data;
+ old_me->id.us--;
+
+ // Now create a new base to add into the linked list of
+ // vase objects.
+
+ basen= MEM_mallocN(sizeof(Base), "duplibase");
+ *basen= *base;
+ BLI_addhead(&scene->base, basen); /* addhead: anders oneindige lus */
+ basen->object= ob_new;
+ basen->flag &= ~SELECT;
+
+ // Initialize the mesh data associated with this object.
+ ob_new->data= add_mesh("Mesh");
+
+ // Finally assign the object type.
+ ob_new->type= OB_MESH;
+
+ return ob_new;
+}
+
+static void InterpCSGFace(
+ DerivedMesh *dm, DerivedMesh *orig_dm, int index, int orig_index, int nr,
+ float mapmat[][4])
+{
+ float obco[3], *co[4], *orig_co[4], w[4][4];
+ MFace *mface, *orig_mface;
+ int j;
+
+ mface = CDDM_get_tessface(dm, index);
+ orig_mface = orig_dm->getTessFaceArray(orig_dm) + orig_index;
+
+ // get the vertex coordinates from the original mesh
+ orig_co[0] = (orig_dm->getVertArray(orig_dm) + orig_mface->v1)->co;
+ orig_co[1] = (orig_dm->getVertArray(orig_dm) + orig_mface->v2)->co;
+ orig_co[2] = (orig_dm->getVertArray(orig_dm) + orig_mface->v3)->co;
+ orig_co[3] = (orig_mface->v4)? (orig_dm->getVertArray(orig_dm) + orig_mface->v4)->co: NULL;
+
+ // get the vertex coordinates from the new derivedmesh
+ co[0] = CDDM_get_vert(dm, mface->v1)->co;
+ co[1] = CDDM_get_vert(dm, mface->v2)->co;
+ co[2] = CDDM_get_vert(dm, mface->v3)->co;
+ co[3] = (nr == 4)? CDDM_get_vert(dm, mface->v4)->co: NULL;
+
+ for (j = 0; j < nr; j++) {
+ // get coordinate into the space of the original mesh
+ if (mapmat)
+ mul_v3_m4v3(obco, mapmat, co[j]);
+ else
+ copy_v3_v3(obco, co[j]);
+
+ interp_weights_face_v3( w[j],orig_co[0], orig_co[1], orig_co[2], orig_co[3], obco);
+ }
+
+ CustomData_interp(&orig_dm->faceData, &dm->faceData, &orig_index, NULL, (float*)w, 1, index);
+}
+
+/* Iterate over the CSG Output Descriptors and create a new DerivedMesh
+ from them */
+static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh(
+ CSG_FaceIteratorDescriptor *face_it,
+ CSG_VertexIteratorDescriptor *vertex_it,
+ float parinv[][4],
+ float mapmat[][4],
+ Material **mat,
+ int *totmat,
+ DerivedMesh *dm1,
+ Object *ob1,
+ DerivedMesh *dm2,
+ Object *ob2)
+{
+ DerivedMesh *result, *orig_dm;
+ GHash *material_hash = NULL;
+ Mesh *me1= (Mesh*)ob1->data;
+ Mesh *me2= (Mesh*)ob2->data;
+ int i;
+
+ // create a new DerivedMesh
+ result = CDDM_new(vertex_it->num_elements, 0, face_it->num_elements, 0, 0);
+ CustomData_merge(&dm1->faceData, &result->faceData, CD_MASK_DERIVEDMESH,
+ CD_DEFAULT, face_it->num_elements);
+ CustomData_merge(&dm2->faceData, &result->faceData, CD_MASK_DERIVEDMESH,
+ CD_DEFAULT, face_it->num_elements);
+
+ // step through the vertex iterators:
+ for (i = 0; !vertex_it->Done(vertex_it->it); i++) {
+ CSG_IVertex csgvert;
+ MVert *mvert = CDDM_get_vert(result, i);
+
+ // retrieve a csg vertex from the boolean module
+ vertex_it->Fill(vertex_it->it, &csgvert);
+ vertex_it->Step(vertex_it->it);
+
+ // we have to map the vertex coordinates back in the coordinate frame
+ // of the resulting object, since it was computed in world space
+ mul_v3_m4v3(mvert->co, parinv, csgvert.position);
+ }
+
+ // a hash table to remap materials to indices
+ if (mat) {
+ material_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "booleanops.c");
+ *totmat = 0;
+ }
+
+ // step through the face iterators
+ for(i = 0; !face_it->Done(face_it->it); i++) {
+ Mesh *orig_me;
+ Object *orig_ob;
+ Material *orig_mat;
+ CSG_IFace csgface;
+ MFace *mface;
+ int orig_index, mat_nr;
+
+ // retrieve a csg face from the boolean module
+ face_it->Fill(face_it->it, &csgface);
+ face_it->Step(face_it->it);
+
+ // find the original mesh and data
+ orig_ob = (csgface.orig_face < dm1->getNumTessFaces(dm1))? ob1: ob2;
+ orig_dm = (csgface.orig_face < dm1->getNumTessFaces(dm1))? dm1: dm2;
+ orig_me = (orig_ob == ob1)? me1: me2;
+ orig_index = (orig_ob == ob1)? csgface.orig_face: csgface.orig_face - dm1->getNumTessFaces(dm1);
+
+ // copy all face layers, including mface
+ CustomData_copy_data(&orig_dm->faceData, &result->faceData, orig_index, i, 1);
+
+ // set mface
+ mface = CDDM_get_tessface(result, i);
+ mface->v1 = csgface.vertex_index[0];
+ mface->v2 = csgface.vertex_index[1];
+ mface->v3 = csgface.vertex_index[2];
+ mface->v4 = (csgface.vertex_number == 4)? csgface.vertex_index[3]: 0;
+
+ // set material, based on lookup in hash table
+ orig_mat= give_current_material(orig_ob, mface->mat_nr+1);
+
+ if (mat && orig_mat) {
+ if (!BLI_ghash_haskey(material_hash, orig_mat)) {
+ mat[*totmat] = orig_mat;
+ mat_nr = mface->mat_nr = (*totmat)++;
+ BLI_ghash_insert(material_hash, orig_mat, SET_INT_IN_POINTER(mat_nr));
+ }
+ else
+ mface->mat_nr = GET_INT_FROM_POINTER(BLI_ghash_lookup(material_hash, orig_mat));
+ }
+ else
+ mface->mat_nr = 0;
+
+ InterpCSGFace(result, orig_dm, i, orig_index, csgface.vertex_number,
+ (orig_me == me2)? mapmat: NULL);
+
+ test_index_face(mface, &result->faceData, i, csgface.vertex_number);
+ }
+
+ if (material_hash)
+ BLI_ghash_free(material_hash, NULL, NULL);
+
+ CDDM_calc_edges(result);
+ CDDM_calc_normals(result);
+
+ CDDM_tessfaces_to_faces(result);
+
+ return result;
+}
+
+static void BuildMeshDescriptors(
+ struct DerivedMesh *dm,
+ struct Object *ob,
+ int face_offset,
+ struct CSG_FaceIteratorDescriptor * face_it,
+ struct CSG_VertexIteratorDescriptor * vertex_it)
+{
+ VertexIt_Construct(vertex_it,dm, ob);
+ FaceIt_Construct(face_it,dm,face_offset,ob);
+}
+
+static void FreeMeshDescriptors(
+ struct CSG_FaceIteratorDescriptor *face_it,
+ struct CSG_VertexIteratorDescriptor *vertex_it)
+{
+ VertexIt_Destruct(vertex_it);
+ FaceIt_Destruct(face_it);
+}
+
+DerivedMesh *NewBooleanDerivedMesh_intern(
+ DerivedMesh *dm, struct Object *ob, DerivedMesh *dm_select, struct Object *ob_select,
+ int int_op_type, Material **mat, int *totmat)
+{
+
+ float inv_mat[4][4];
+ float map_mat[4][4];
+
+ DerivedMesh *result = NULL;
+
+ if (dm == NULL || dm_select == NULL) return 0;
+ if (!dm->getNumTessFaces(dm) || !dm_select->getNumTessFaces(dm_select)) return 0;
+
+ // we map the final object back into ob's local coordinate space. For this
+ // we need to compute the inverse transform from global to ob (inv_mat),
+ // and the transform from ob to ob_select for use in interpolation (map_mat)
+ invert_m4_m4(inv_mat, ob->obmat);
+ mul_m4_m4m4(map_mat, ob_select->obmat, inv_mat);
+ invert_m4_m4(inv_mat, ob_select->obmat);
+
+ {
+ // interface with the boolean module:
+ //
+ // the idea is, we pass the boolean module verts and faces using the
+ // provided descriptors. once the boolean operation is performed, we
+ // get back output descriptors, from which we then build a DerivedMesh
+
+ CSG_VertexIteratorDescriptor vd_1, vd_2;
+ CSG_FaceIteratorDescriptor fd_1, fd_2;
+ CSG_OperationType op_type;
+ CSG_BooleanOperation *bool_op;
+
+ // work out the operation they chose and pick the appropriate
+ // enum from the csg module.
+ switch (int_op_type) {
+ case 1 : op_type = e_csg_intersection; break;
+ case 2 : op_type = e_csg_union; break;
+ case 3 : op_type = e_csg_difference; break;
+ case 4 : op_type = e_csg_classify; break;
+ default : op_type = e_csg_intersection;
+ }
+
+ BuildMeshDescriptors(dm_select, ob_select, 0, &fd_1, &vd_1);
+ BuildMeshDescriptors(dm, ob, dm_select->getNumTessFaces(dm_select) , &fd_2, &vd_2);
+
+ bool_op = CSG_NewBooleanFunction();
+
+ // perform the operation
+ if (CSG_PerformBooleanOperation(bool_op, op_type, fd_1, vd_1, fd_2, vd_2)) {
+ CSG_VertexIteratorDescriptor vd_o;
+ CSG_FaceIteratorDescriptor fd_o;
+
+ CSG_OutputFaceDescriptor(bool_op, &fd_o);
+ CSG_OutputVertexDescriptor(bool_op, &vd_o);
+
+ // iterate through results of operation and insert
+ // into new object
+ result = ConvertCSGDescriptorsToDerivedMesh(
+ &fd_o, &vd_o, inv_mat, map_mat, mat, totmat, dm_select, ob_select, dm, ob);
+
+ // free up the memory
+ CSG_FreeVertexDescriptor(&vd_o);
+ CSG_FreeFaceDescriptor(&fd_o);
+ }
+ else
+ printf("Unknown internal error in boolean");
+
+ CSG_FreeBooleanOperation(bool_op);
+
+ FreeMeshDescriptors(&fd_1, &vd_1);
+ FreeMeshDescriptors(&fd_2, &vd_2);
+ }
+
+ return result;
+}
+
+int NewBooleanMesh(Scene *scene, Base *base, Base *base_select, int int_op_type)
+{
+ Mesh *me_new;
+ int a, maxmat, totmat= 0;
+ Object *ob_new, *ob, *ob_select;
+ Material **mat;
+ DerivedMesh *result;
+ DerivedMesh *dm_select;
+ DerivedMesh *dm;
+
+ ob= base->object;
+ ob_select= base_select->object;
+
+ dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ dm_select = mesh_create_derived_view(scene, ob_select, 0); // no modifiers in editmode ??
+
+ maxmat= ob->totcol + ob_select->totcol;
+ mat= (Material**)MEM_mallocN(sizeof(Material*)*maxmat, "NewBooleanMeshMat");
+
+ /* put some checks in for nice user feedback */
+ if (dm == NULL || dm_select == NULL) return 0;
+ if (!dm->getNumTessFaces(dm) || !dm_select->getNumTessFaces(dm_select))
+ {
+ MEM_freeN(mat);
+ return -1;
+ }
+
+ result= NewBooleanDerivedMesh_intern(dm, ob, dm_select, ob_select, int_op_type, mat, &totmat);
+
+ if (result == NULL) {
+ MEM_freeN(mat);
+ return 0;
+ }
+
+ /* create a new blender mesh object - using 'base' as a template */
+ ob_new= AddNewBlenderMesh(scene, base_select);
+ me_new= ob_new->data;
+
+ DM_to_mesh(result, me_new);
+ result->release(result);
+
+ dm->release(dm);
+ dm_select->release(dm_select);
+
+ /* add materials to object */
+ for (a = 0; a < totmat; a++)
+ assign_material(ob_new, mat[a], a+1);
+
+ MEM_freeN(mat);
+
+ /* update dag */
+ DAG_id_flush_update(&ob_new->id, OB_RECALC_DATA);
+
+ return 1;
+}
+
+DerivedMesh *NewBooleanDerivedMesh(DerivedMesh *dm, struct Object *ob, DerivedMesh *dm_select, struct Object *ob_select,
+ int int_op_type)
+{
+ return NewBooleanDerivedMesh_intern(dm, ob, dm_select, ob_select, int_op_type, NULL, NULL);
+}
+
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index 949be31354c..7a3c4bd5928 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -553,7 +553,7 @@ BVHTree* bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *mesh, float
data->mesh = mesh;
data->vert = mesh->getVertDataArray(mesh, CD_MVERT);
- data->face = mesh->getFaceDataArray(mesh, CD_MFACE);
+ data->face = mesh->getTessFaceDataArray(mesh, CD_MFACE);
data->sphere_radius = epsilon;
}
@@ -570,9 +570,9 @@ BVHTree* bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float
if(tree == NULL)
{
int i;
- int numFaces= mesh->getNumFaces(mesh);
+ int numFaces= mesh->getNumTessFaces(mesh);
MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT);
- MFace *face = mesh->getFaceDataArray(mesh, CD_MFACE);
+ MFace *face = mesh->getTessFaceDataArray(mesh, CD_MFACE);
if(vert != NULL && face != NULL)
{
@@ -636,7 +636,7 @@ BVHTree* bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float
data->mesh = mesh;
data->vert = mesh->getVertDataArray(mesh, CD_MVERT);
- data->face = mesh->getFaceDataArray(mesh, CD_MFACE);
+ data->face = mesh->getTessFaceDataArray(mesh, CD_MFACE);
data->sphere_radius = epsilon;
}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 9a04c75db07..368e84cce30 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -1,4 +1,4 @@
-/*
+ /*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -36,11 +36,23 @@
#include <string.h>
#include "BIF_gl.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_paint.h"
+#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
+
+#include "BLI_editVert.h"
+#include "BLI_scanfill.h"
+#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_edgehash.h"
#include "BLI_editVert.h"
#include "BLI_math.h"
#include "BLI_pbvh.h"
+#include "BLI_array.h"
+#include "BLI_smallhash.h"
#include "BLI_utildefines.h"
#include "BKE_cdderivedmesh.h"
@@ -72,6 +84,8 @@ typedef struct {
MVert *mvert;
MEdge *medge;
MFace *mface;
+ MLoop *mloop;
+ MPoly *mpoly;
/* Cached */
struct PBVH *pbvh;
@@ -82,6 +96,8 @@ typedef struct {
struct IndexNode *fmap_mem;
} CDDerivedMesh;
+DMFaceIter *cdDM_newFaceIter(DerivedMesh *source);
+
/**************** DerivedMesh interface functions ****************/
static int cdDM_getNumVerts(DerivedMesh *dm)
{
@@ -93,11 +109,16 @@ static int cdDM_getNumEdges(DerivedMesh *dm)
return dm->numEdgeData;
}
-static int cdDM_getNumFaces(DerivedMesh *dm)
+static int cdDM_getNumTessFaces(DerivedMesh *dm)
{
return dm->numFaceData;
}
+static int cdDM_getNumFaces(DerivedMesh *dm)
+{
+ return dm->numPolyData;
+}
+
static void cdDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
{
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
@@ -280,7 +301,7 @@ static void cdDM_drawUVEdges(DerivedMesh *dm)
{
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
MFace *mf = cddm->mface;
- MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
+ MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
int i;
if(mf) {
@@ -451,7 +472,7 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm,
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
MVert *mvert = cddm->mvert;
MFace *mface = cddm->mface;
- float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
+ float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
int a, glmode = -1, shademodel = -1, matnr = -1, drawCurrentMat = 1;
#define PASSVERT(index) { \
@@ -631,21 +652,21 @@ static void cdDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned cha
}
static void cdDM_drawFacesTex_common(DerivedMesh *dm,
- int (*drawParams)(MTFace *tface, MCol *mcol, int matnr),
- int (*drawParamsMapped)(void *userData, int index),
- void *userData)
+ int (*drawParams)(MTFace *tface, int has_vcol, int matnr),
+ int (*drawParamsMapped)(void *userData, int index),
+ void *userData)
{
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
MVert *mv = cddm->mvert;
- MFace *mf = DM_get_face_data_layer(dm, CD_MFACE);
- MCol *realcol = dm->getFaceDataArray(dm, CD_TEXTURE_MCOL);
- float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
- MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
- int i, j, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+ MFace *mf = DM_get_tessface_data_layer(dm, CD_MFACE);
+ MCol *realcol = dm->getTessFaceDataArray(dm, CD_TEXTURE_MCOL);
+ float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
+ MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
+ int i, j, orig, *index = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
int startFace = 0, lastFlag = 0xdeadbeef;
- MCol *mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL);
+ MCol *mcol = dm->getTessFaceDataArray(dm, CD_WEIGHT_MCOL);
if(!mcol)
- mcol = dm->getFaceDataArray(dm, CD_MCOL);
+ mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
cdDM_update_normals_from_pbvh(dm);
@@ -657,7 +678,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
unsigned char *cp = NULL;
if(drawParams) {
- flag = drawParams(tf? &tf[i]: NULL, mcol? &mcol[i*4]: NULL, mf->mat_nr);
+ flag = drawParams(tf? &tf[i]: NULL, mcol!=NULL, mf->mat_nr);
}
else {
if(index) {
@@ -737,8 +758,8 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
}
if( col != 0 ) {*/
- unsigned char *colors = MEM_mallocN(dm->getNumFaces(dm)*4*3*sizeof(unsigned char), "cdDM_drawFacesTex_common");
- for( i=0; i < dm->getNumFaces(dm); i++ ) {
+ unsigned char *colors = MEM_mallocN(dm->getNumTessFaces(dm)*4*3*sizeof(unsigned char), "cdDM_drawFacesTex_common");
+ for( i=0; i < dm->getNumTessFaces(dm); i++ ) {
for( j=0; j < 4; j++ ) {
colors[i*12+j*3] = col[i*4+j].r;
colors[i*12+j*3+1] = col[i*4+j].g;
@@ -763,7 +784,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
int flag = 1;
if(drawParams) {
- flag = drawParams(tf? &tf[actualFace]: NULL, mcol? &mcol[actualFace*4]: NULL, mf[actualFace].mat_nr);
+ flag = drawParams(tf? &tf[actualFace]: NULL, mcol!=NULL, mf[actualFace].mat_nr);
}
else {
if(index) {
@@ -806,7 +827,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
}
}
-static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
+static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr))
{
cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
}
@@ -817,14 +838,14 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
MVert *mv = cddm->mvert;
MFace *mf = cddm->mface;
MCol *mc;
- float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
- int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+ float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
+ int i, orig, *index = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
- mc = DM_get_face_data_layer(dm, CD_ID_MCOL);
+ mc = DM_get_tessface_data_layer(dm, CD_ID_MCOL);
if(!mc)
- mc = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL);
+ mc = DM_get_tessface_data_layer(dm, CD_WEIGHT_MCOL);
if(!mc)
- mc = DM_get_face_data_layer(dm, CD_MCOL);
+ mc = DM_get_tessface_data_layer(dm, CD_MCOL);
cdDM_update_normals_from_pbvh(dm);
@@ -968,11 +989,11 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
DMVertexAttribs attribs;
MVert *mvert = cddm->mvert;
MFace *mface = cddm->mface;
- MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE);
- float (*nors)[3] = dm->getFaceDataArray(dm, CD_NORMAL);
+ MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE);
+ float (*nors)[3] = dm->getTessFaceDataArray(dm, CD_NORMAL);
int a, b, dodraw, matnr, new_matnr;
int transp, new_transp, orig_transp;
- int orig, *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ int orig, *index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
cdDM_update_normals_from_pbvh(dm);
@@ -1081,7 +1102,6 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
else
PASSVERT(mface->v3, 2)
-#undef PASSVERT
}
glEnd();
}
@@ -1397,35 +1417,69 @@ static void cdDM_foreachMappedFaceCenter(
{
CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
MVert *mv = cddm->mvert;
- MFace *mf = cddm->mface;
- int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+ MPoly *mf = cddm->mpoly;
+ MLoop *ml = cddm->mloop;
+ int i, j, orig, *index;
- for(i = 0; i < dm->numFaceData; i++, mf++) {
+ index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
+ mf = cddm->mpoly;
+ for(i = 0; i < dm->numPolyData; i++, mf++) {
float cent[3];
float no[3];
if (index) {
orig = *index++;
if(orig == ORIGINDEX_NONE) continue;
- }
- else
+ } else
orig = i;
+
+ ml = &cddm->mloop[mf->loopstart];
+ cent[0] = cent[1] = cent[2] = 0.0f;
+ for (j=0; j<mf->totloop; j++, ml++) {
+ add_v3_v3v3(cent, cent, mv[ml->v].co);
+ }
+ mul_v3_fl(cent, 1.0f / (float)j);
- VECCOPY(cent, mv[mf->v1].co);
- add_v3_v3(cent, mv[mf->v2].co);
- add_v3_v3(cent, mv[mf->v3].co);
-
- if (mf->v4) {
- normal_quad_v3( no,mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co, mv[mf->v4].co);
- add_v3_v3(cent, mv[mf->v4].co);
- mul_v3_fl(cent, 0.25f);
+ ml = &cddm->mloop[mf->loopstart];
+ if (j > 3) {
+ normal_quad_v3(no, mv[ml->v].co, mv[(ml+1)->v].co,
+ mv[(ml+2)->v].co, mv[(ml+3)->v].co);
} else {
- normal_tri_v3( no,mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co);
- mul_v3_fl(cent, 0.33333333333f);
+ normal_tri_v3(no, mv[ml->v].co, mv[(ml+1)->v].co,
+ mv[(ml+2)->v].co);
}
func(userData, orig, cent, no);
}
+
+}
+
+static void cdDM_recalcTesselation(DerivedMesh *dm)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+
+ dm->numFaceData = mesh_recalcTesselation(&dm->faceData, &dm->loopData,
+ &dm->polyData, cddm->mvert, dm->numFaceData, dm->numLoopData,
+ dm->numPolyData, 1, 0);
+
+ cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+}
+
+void CDDM_recalc_tesselation(DerivedMesh *dm)
+{
+ cdDM_recalcTesselation(dm);
+}
+
+/*ignores original poly origindex layer*/
+static void cdDM_recalcTesselation2(DerivedMesh *dm)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+
+ dm->numFaceData = mesh_recalcTesselation(&dm->faceData, &dm->loopData,
+ &dm->polyData, cddm->mvert, dm->numFaceData, dm->numLoopData,
+ dm->numPolyData, 0, 0);
+
+ cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
}
static void cdDM_free_internal(CDDerivedMesh *cddm)
@@ -1444,6 +1498,11 @@ static void cdDM_release(DerivedMesh *dm)
}
}
+int CDDM_Check(DerivedMesh *dm)
+{
+ return dm && dm->getMinMax == cdDM_getMinMax;
+}
+
/**************** CDDM interface functions ****************/
static CDDerivedMesh *cdDM_create(const char *desc)
{
@@ -1456,21 +1515,27 @@ static CDDerivedMesh *cdDM_create(const char *desc)
dm->getMinMax = cdDM_getMinMax;
dm->getNumVerts = cdDM_getNumVerts;
- dm->getNumFaces = cdDM_getNumFaces;
dm->getNumEdges = cdDM_getNumEdges;
+ dm->getNumTessFaces = cdDM_getNumTessFaces;
+ dm->getNumFaces = cdDM_getNumFaces;
+
+ dm->newFaceIter = cdDM_newFaceIter;
dm->getVert = cdDM_getVert;
dm->getEdge = cdDM_getEdge;
- dm->getFace = cdDM_getFace;
+ dm->getTessFace = cdDM_getFace;
dm->copyVertArray = cdDM_copyVertArray;
dm->copyEdgeArray = cdDM_copyEdgeArray;
- dm->copyFaceArray = cdDM_copyFaceArray;
+ dm->copyTessFaceArray = cdDM_copyFaceArray;
dm->getVertData = DM_get_vert_data;
dm->getEdgeData = DM_get_edge_data;
- dm->getFaceData = DM_get_face_data;
+ dm->getTessFaceData = DM_get_face_data;
dm->getVertDataArray = DM_get_vert_data_layer;
dm->getEdgeDataArray = DM_get_edge_data_layer;
- dm->getFaceDataArray = DM_get_face_data_layer;
+ dm->getTessFaceDataArray = DM_get_tessface_data_layer;
+
+ //doesn't work yet for all cases
+ //dm->recalcTesselation = cdDM_recalcTesselation;
dm->getVertCos = cdDM_getVertCos;
dm->getVertCo = cdDM_getVertCo;
@@ -1503,24 +1568,29 @@ static CDDerivedMesh *cdDM_create(const char *desc)
return cddm;
}
-DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces)
+DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces, int numLoops, int numPolys)
{
CDDerivedMesh *cddm = cdDM_create("CDDM_new dm");
DerivedMesh *dm = &cddm->dm;
- DM_init(dm, DM_TYPE_CDDM, numVerts, numEdges, numFaces);
+ DM_init(dm, DM_TYPE_CDDM, numVerts, numEdges, numFaces, numLoops, numPolys);
CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numFaces);
+ CustomData_add_layer(&dm->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, numPolys);
CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
+ CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, numLoops);
+ CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, numPolys);
cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+ cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+ cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
return dm;
}
@@ -1534,7 +1604,8 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *UNUSED(ob))
/* this does a referenced copy, with an exception for fluidsim */
- DM_init(dm, DM_TYPE_CDDM, mesh->totvert, mesh->totedge, mesh->totface);
+ DM_init(dm, DM_TYPE_CDDM, mesh->totvert, mesh->totedge, mesh->totface,
+ mesh->totloop, mesh->totpoly);
dm->deformedOnly = 1;
@@ -1544,21 +1615,30 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *UNUSED(ob))
mesh->totvert);
CustomData_merge(&mesh->edata, &dm->edgeData, mask, alloctype,
mesh->totedge);
- CustomData_merge(&mesh->fdata, &dm->faceData, mask, alloctype,
+ CustomData_merge(&mesh->fdata, &dm->faceData, mask|CD_MASK_ORIGINDEX, alloctype,
mesh->totface);
+ CustomData_merge(&mesh->ldata, &dm->loopData, mask, alloctype,
+ mesh->totloop);
+ CustomData_merge(&mesh->pdata, &dm->polyData, mask, alloctype,
+ mesh->totpoly);
cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
+ cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+ cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+ if (!CustomData_has_layer(&cddm->dm.faceData, CD_ORIGINDEX))
+ CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totface);
+
return dm;
}
DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *UNUSED(me))
{
DerivedMesh *dm = CDDM_new(BLI_countlist(&em->verts),
- BLI_countlist(&em->edges),
- BLI_countlist(&em->faces));
+ BLI_countlist(&em->edges),
+ BLI_countlist(&em->faces), 0, 0);
CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
EditVert *eve;
EditEdge *eed;
@@ -1576,6 +1656,8 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *UNUSED(me))
CD_CALLOC, dm->numEdgeData); */
CustomData_merge(&em->fdata, &dm->faceData, CD_MASK_DERIVEDMESH,
CD_CALLOC, dm->numFaceData);
+ CustomData_merge(&em->fdata, &dm->faceData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, dm->numFaceData);
/* set eve->hash to vert index */
for(i = 0, eve = em->verts.first; eve; eve = eve->next, ++i)
@@ -1631,7 +1713,7 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *UNUSED(me))
/* CustomData_from_em_block(&em->edata, &dm->edgeData, eed->data, i); */
}
- index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
for(i = 0, efa = em->faces.first; i < dm->numFaceData;
i++, efa = efa->next, index++) {
MFace *mf = &mface[i];
@@ -1669,10 +1751,10 @@ DerivedMesh *CDDM_from_curve_customDB(Object *ob, ListBase *dispbase)
if (nurbs_to_mdata_customdb(ob, dispbase, &allvert, &totvert, &alledge,
&totedge, &allface, &totface) != 0) {
/* Error initializing mdata. This often happens when curve is empty */
- return CDDM_new(0, 0, 0);
+ return CDDM_new(0, 0, 0, 0, 0);
}
- dm = CDDM_new(totvert, totedge, totface);
+ dm = CDDM_new(totvert, totedge, totface, totface*4, totface);
dm->deformedOnly = 1;
cddm = (CDDerivedMesh*)dm;
@@ -1688,21 +1770,348 @@ DerivedMesh *CDDM_from_curve_customDB(Object *ob, ListBase *dispbase)
return dm;
}
-DerivedMesh *CDDM_copy(DerivedMesh *source)
+static void loops_to_customdata_corners(BMesh *bm, CustomData *facedata,
+ int cdindex, BMLoop *l3[3],
+ int numCol, int numTex)
+{
+ BMLoop *l;
+ BMFace *f = l3[0]->f;
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ int i, j, hasWCol = CustomData_has_layer(&bm->ldata, CD_WEIGHT_MLOOPCOL);
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_get_n(facedata, CD_MTFACE, cdindex, i);
+ texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
+
+ texface->tpage = texpoly->tpage;
+ texface->flag = texpoly->flag;
+ texface->transp = texpoly->transp;
+ texface->mode = texpoly->mode;
+ texface->tile = texpoly->tile;
+ texface->unwrap = texpoly->unwrap;
+
+ for (j=0; j<3; j++) {
+ l = l3[j];
+ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
+ texface->uv[j][0] = mloopuv->uv[0];
+ texface->uv[j][1] = mloopuv->uv[1];
+ }
+ }
+
+ for(i=0; i < numCol; i++){
+ mcol = CustomData_get_n(facedata, CD_MCOL, cdindex, i);
+
+ for (j=0; j<3; j++) {
+ l = l3[j];
+ mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
+ mcol[j].r = mloopcol->r;
+ mcol[j].g = mloopcol->g;
+ mcol[j].b = mloopcol->b;
+ mcol[j].a = mloopcol->a;
+ }
+ }
+
+ if (hasWCol) {
+ mcol = CustomData_get(facedata, cdindex, CD_WEIGHT_MCOL);
+
+ for (j=0; j<3; j++) {
+ l = l3[j];
+ mloopcol = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_WEIGHT_MLOOPCOL);
+ mcol[j].r = mloopcol->r;
+ mcol[j].g = mloopcol->g;
+ mcol[j].b = mloopcol->b;
+ mcol[j].a = mloopcol->a;
+ }
+ }
+}
+
+DerivedMesh *CDDM_from_BMEditMesh(BMEditMesh *em, Mesh *me)
+{
+ DerivedMesh *dm = CDDM_new(em->bm->totvert, em->bm->totedge,
+ em->tottri, em->bm->totloop, em->bm->totface);
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ BMesh *bm = em->bm;
+ BMIter iter, liter;
+ BMVert *eve;
+ BMEdge *eed;
+ BMFace *efa;
+ MVert *mvert = cddm->mvert;
+ MEdge *medge = cddm->medge;
+ MFace *mface = cddm->mface;
+ MLoop *mloop = cddm->mloop;
+ MPoly *mpoly = cddm->mpoly;
+ int numCol = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL);
+ int numTex = CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY);
+ int i, j, *index, add_orig;
+
+ dm->deformedOnly = 1;
+
+ /*don't add origindex layer if one already exists*/
+ add_orig = !CustomData_has_layer(&em->bm->pdata, CD_ORIGINDEX);
+
+ CustomData_merge(&em->bm->vdata, &dm->vertData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, dm->numVertData);
+ CustomData_merge(&em->bm->edata, &dm->edgeData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, dm->numEdgeData);
+ CustomData_merge(&em->bm->ldata, &dm->loopData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, dm->numLoopData);
+ CustomData_merge(&em->bm->pdata, &dm->polyData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, dm->numPolyData);
+
+ /*add tesselation mface layers*/
+ CustomData_from_bmeshpoly(&dm->faceData, &dm->polyData, &dm->loopData, em->tottri);
+
+ /* set vert index */
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++)
+ BMINDEX_SET(eve, i);
+
+ index = dm->getVertDataArray(dm, CD_ORIGINDEX);
+
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++, index++) {
+ MVert *mv = &mvert[i];
+
+ VECCOPY(mv->co, eve->co);
+
+ BMINDEX_SET(eve, i);
+
+ mv->no[0] = eve->no[0] * 32767.0;
+ mv->no[1] = eve->no[1] * 32767.0;
+ mv->no[2] = eve->no[2] * 32767.0;
+
+ mv->flag = BMFlags_To_MEFlags(eve);
+
+ if (add_orig) *index = i;
+
+ CustomData_from_bmesh_block(&bm->vdata, &dm->vertData, eve->head.data, i);
+ }
+
+ index = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
+ eed = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);
+ for (i=0; eed; eed=BMIter_Step(&iter), i++, index++) {
+ MEdge *med = &medge[i];
+
+ BMINDEX_SET(eed, i);
+
+ med->v1 = BMINDEX_GET(eed->v1);
+ med->v2 = BMINDEX_GET(eed->v2);
+ med->flag = ME_EDGEDRAW|ME_EDGERENDER;
+
+ med->flag = BMFlags_To_MEFlags(eed);
+
+ CustomData_from_bmesh_block(&bm->edata, &dm->edgeData, eed->head.data, i);
+ if (add_orig) *index = i;
+ }
+
+ efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
+ for (i=0; efa; i++, efa=BMIter_Step(&iter)) {
+ BMINDEX_SET(efa, i);
+ }
+
+ index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ for(i = 0; i < dm->numFaceData; i++, index++) {
+ MFace *mf = &mface[i];
+ BMLoop **l = em->looptris[i];
+ efa = l[0]->f;
+
+ mf->v1 = BMINDEX_GET(l[0]->v);
+ mf->v2 = BMINDEX_GET(l[1]->v);
+ mf->v3 = BMINDEX_GET(l[2]->v);
+ mf->v4 = 0;
+ mf->mat_nr = efa->mat_nr;
+ mf->flag = BMFlags_To_MEFlags(efa);
+
+ *index = add_orig ? BMINDEX_GET(efa) : *(int*)CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_ORIGINDEX);
+
+ loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numTex);
+ test_index_face(mf, &dm->faceData, i, 3);
+ }
+
+ index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
+ j = 0;
+ efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
+ for (i=0; efa; i++, efa=BMIter_Step(&iter), index++) {
+ BMLoop *l;
+ MPoly *mp = &mpoly[i];
+
+ mp->totloop = efa->len;
+ mp->flag = BMFlags_To_MEFlags(efa);
+ mp->loopstart = j;
+ mp->mat_nr = efa->mat_nr;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) {
+ mloop->v = BMINDEX_GET(l->v);
+ mloop->e = BMINDEX_GET(l->e);
+ CustomData_from_bmesh_block(&bm->ldata, &dm->loopData, l->head.data, j);
+
+ j++;
+ mloop++;
+ }
+
+ CustomData_from_bmesh_block(&bm->pdata, &dm->polyData, efa->head.data, i);
+
+ if (add_orig) *index = i;
+ }
+
+ return dm;
+}
+
+typedef struct CDDM_LoopIter {
+ DMLoopIter head;
+ CDDerivedMesh *cddm;
+ int len, i;
+} CDDM_LoopIter;
+
+typedef struct CDDM_FaceIter {
+ DMFaceIter head;
+ CDDerivedMesh *cddm;
+ CDDM_LoopIter liter;
+} CDDM_FaceIter;
+
+void cddm_freeiter(void *self)
+{
+ MEM_freeN(self);
+}
+
+void cddm_stepiter(void *self)
+{
+ CDDM_FaceIter *iter = self;
+ MPoly *mp;
+
+ mp = iter->cddm->mpoly + iter->head.index;
+ mp->flag = iter->head.flags;
+ mp->mat_nr = iter->head.mat_nr;
+
+ iter->head.index++;
+ if (iter->head.index >= iter->cddm->dm.numPolyData) {
+ iter->head.done = 1;
+ return;
+ }
+
+ mp = iter->cddm->mpoly + iter->head.index;
+
+ iter->head.flags = mp->flag;
+ iter->head.mat_nr = mp->mat_nr;
+ iter->head.len = mp->totloop;
+}
+
+void *cddm_faceiter_getcddata(void *self, int type, int layer)
+{
+ CDDM_FaceIter *iter = self;
+
+ if (layer == -1) return CustomData_get(&iter->cddm->dm.polyData,
+ iter->head.index, type);
+ else return CustomData_get_n(&iter->cddm->dm.polyData, type,
+ iter->head.index, layer);
+}
+
+void *cddm_loopiter_getcddata(void *self, int type, int layer)
+{
+ CDDM_LoopIter *iter = self;
+
+ if (layer == -1) return CustomData_get(&iter->cddm->dm.loopData,
+ iter->head.index, type);
+ else return CustomData_get_n(&iter->cddm->dm.loopData, type,
+ iter->head.index, layer);
+}
+
+void *cddm_loopiter_getvertcddata(void *self, int type, int layer)
+{
+ CDDM_LoopIter *iter = self;
+
+ if (layer == -1) return CustomData_get(&iter->cddm->dm.vertData,
+ iter->cddm->mloop[iter->head.vindex].v,
+ type);
+ else return CustomData_get_n(&iter->cddm->dm.vertData, type,
+ iter->cddm->mloop[iter->head.vindex].v, layer);
+}
+
+DMLoopIter *cddmiter_get_loopiter(void *self)
+{
+ CDDM_FaceIter *iter = self;
+ CDDM_LoopIter *liter = &iter->liter;
+ MPoly *mp = iter->cddm->mpoly + iter->head.index;
+
+ liter->i = -1;
+ liter->len = iter->head.len;
+ liter->head.index = mp->loopstart-1;
+ liter->head.done = 0;
+
+ liter->head.step(liter);
+
+ return (DMLoopIter*) liter;
+}
+
+void cddm_loopiter_step(void *self)
+{
+ CDDM_LoopIter *liter = self;
+ MLoop *ml;
+
+ liter->i++;
+ liter->head.index++;
+
+ if (liter->i == liter->len) {
+ liter->head.done = 1;
+ return;
+ }
+
+ ml = liter->cddm->mloop + liter->head.index;
+
+ liter->head.eindex = ml->e;
+ liter->head.v = liter->cddm->mvert[ml->v];
+ liter->head.vindex = ml->v;
+}
+
+DMFaceIter *cdDM_newFaceIter(DerivedMesh *source)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) source;
+ CDDM_FaceIter *iter = MEM_callocN(sizeof(CDDM_FaceIter), "DMFaceIter from cddm");
+
+ iter->head.free = cddm_freeiter;
+ iter->head.step = cddm_stepiter;
+ iter->head.getCDData = cddm_faceiter_getcddata;
+ iter->head.getLoopsIter = cddmiter_get_loopiter;
+
+ iter->liter.head.step = cddm_loopiter_step;
+ iter->liter.head.getLoopCDData = cddm_loopiter_getcddata;
+ iter->liter.head.getVertCDData = cddm_loopiter_getvertcddata;
+ iter->liter.cddm = cddm;
+
+ iter->cddm = cddm;
+
+ if (source->numFaceData) {
+ iter->head.index = -1;
+ iter->head.step(iter);
+ } else {
+ iter->head.done = 1;
+ }
+
+ return (DMFaceIter*) iter;
+}
+
+DerivedMesh *CDDM_copy(DerivedMesh *source, int faces_from_tessfaces)
{
CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm");
DerivedMesh *dm = &cddm->dm;
int numVerts = source->numVertData;
int numEdges = source->numEdgeData;
int numFaces = source->numFaceData;
+ int numLoops = source->numLoopData;
+ int numPolys = source->numPolyData;
/* ensure these are created if they are made on demand */
source->getVertDataArray(source, CD_ORIGINDEX);
source->getEdgeDataArray(source, CD_ORIGINDEX);
- source->getFaceDataArray(source, CD_ORIGINDEX);
+ source->getTessFaceDataArray(source, CD_ORIGINDEX);
/* this initializes dm, and copies all non mvert/medge/mface layers */
- DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numFaces);
+ DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numFaces,
+ numLoops, numPolys);
dm->deformedOnly = source->deformedOnly;
CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
@@ -1712,11 +2121,19 @@ DerivedMesh *CDDM_copy(DerivedMesh *source)
/* now add mvert/medge/mface layers */
cddm->mvert = source->dupVertArray(source);
cddm->medge = source->dupEdgeArray(source);
- cddm->mface = source->dupFaceArray(source);
+ cddm->mface = source->dupTessFaceArray(source);
CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts);
CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges);
CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numFaces);
+
+ if (!faces_from_tessfaces)
+ DM_DupPolys(source, dm);
+ else
+ CDDM_tessfaces_to_faces(dm);
+
+ cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+ cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
return dm;
}
@@ -1724,7 +2141,8 @@ DerivedMesh *CDDM_copy(DerivedMesh *source)
/* note, the CD_ORIGINDEX layers are all 0, so if there is a direct
* relationship betwen mesh data this needs to be set by the caller. */
DerivedMesh *CDDM_from_template(DerivedMesh *source,
- int numVerts, int numEdges, int numFaces)
+ int numVerts, int numEdges, int numFaces,
+ int numLoops, int numPolys)
{
CDDerivedMesh *cddm = cdDM_create("CDDM_from_template dest");
DerivedMesh *dm = &cddm->dm;
@@ -1732,15 +2150,17 @@ DerivedMesh *CDDM_from_template(DerivedMesh *source,
/* ensure these are created if they are made on demand */
source->getVertDataArray(source, CD_ORIGINDEX);
source->getEdgeDataArray(source, CD_ORIGINDEX);
- source->getFaceDataArray(source, CD_ORIGINDEX);
+ source->getTessFaceDataArray(source, CD_ORIGINDEX);
/* this does a copy of all non mvert/medge/mface layers */
- DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numFaces);
+ DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numFaces, numLoops, numPolys);
/* now add mvert/medge/mface layers */
CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
+ CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, numLoops);
+ CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, numPolys);
if(!CustomData_get_layer(&dm->vertData, CD_ORIGINDEX))
CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
@@ -1752,6 +2172,8 @@ DerivedMesh *CDDM_from_template(DerivedMesh *source,
cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+ cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+ cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
return dm;
}
@@ -1784,62 +2206,355 @@ void CDDM_apply_vert_normals(DerivedMesh *dm, short (*vertNormals)[3])
VECCOPY(vert->no, vertNormals[i]);
}
-/* adapted from mesh_calc_normals */
void CDDM_calc_normals(DerivedMesh *dm)
{
CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
float (*temp_nors)[3];
float (*face_nors)[3];
- int i;
+ float (*vert_nors)[3];
+ int i, j, *origIndex;
int numVerts = dm->numVertData;
int numFaces = dm->numFaceData;
MFace *mf;
+ MPoly *mp;
MVert *mv;
+ MLoop *ml;
if(numVerts == 0) return;
+ if (CustomData_has_layer(&dm->faceData, CD_NORMAL))
+ CustomData_free_layer(&dm->faceData, CD_NORMAL, dm->numFaceData, 0);
+
temp_nors = MEM_callocN(numVerts * sizeof(*temp_nors),
"CDDM_calc_normals temp_nors");
- /* we don't want to overwrite any referenced layers */
- mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT);
- cddm->mvert = mv;
+ /*recalc tesselation to ensure we have valid origindex values
+ for mface->mpoly lookups.*/
+ cdDM_recalcTesselation2(dm);
- /* make a face normal layer if not present */
- face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
- if(!face_nors)
- face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC,
- NULL, dm->numFaceData);
+ numFaces = dm->numFaceData;
- /* calculate face normals and add to vertex normals */
- mf = CDDM_get_faces(dm);
- for(i = 0; i < numFaces; i++, mf++) {
- float *f_no = face_nors[i];
+ /*first go through and calculate normals for all the polys*/
+ temp_nors = MEM_callocN(sizeof(float)*3*dm->numPolyData, "temp_nors cdderivedmesh.c");
+ vert_nors = MEM_callocN(sizeof(float)*3*dm->numVertData, "vert_nors cdderivedmesh.c");
+
+ mp = cddm->mpoly;
+ for (i=0; i<dm->numPolyData; i++, mp++) {
+ mesh_calc_poly_normal(mp, cddm->mloop+mp->loopstart, cddm->mvert, temp_nors[i]);
- if(mf->v4)
- normal_quad_v3( f_no,mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co, mv[mf->v4].co);
- else
- normal_tri_v3( f_no,mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co);
-
- add_v3_v3(temp_nors[mf->v1], f_no);
- add_v3_v3(temp_nors[mf->v2], f_no);
- add_v3_v3(temp_nors[mf->v3], f_no);
- if(mf->v4)
- add_v3_v3(temp_nors[mf->v4], f_no);
+ ml = cddm->mloop + mp->loopstart;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ VECADD(vert_nors[ml->v], vert_nors[ml->v], temp_nors[i]);
+ }
+ }
+
+ face_nors = MEM_callocN(sizeof(float)*3*dm->numFaceData, "face_nors cdderivedmesh.c");
+ origIndex = CustomData_get_layer(&dm->faceData, CD_ORIGINDEX);
+
+ mf = cddm->mface;
+ for (i=0; i<dm->numFaceData; i++, mf++, origIndex++) {
+ VECCOPY(face_nors[i], temp_nors[*origIndex]);
}
- /* normalize vertex normals and assign */
- for(i = 0; i < numVerts; i++, mv++) {
- float *no = temp_nors[i];
+ mv = cddm->mvert;
+ for (i=0; i<dm->numVertData; i++, mv++) {
+ float *no = vert_nors[i];
- if (normalize_v3(no) == 0.0)
- normalize_v3_v3(no, mv->co);
+ if (normalize_v3(no) == 0.0) {
+ VECCOPY(no, mv->co);
+ if (normalize_v3(no) == 0.0) {
+ no[0] = 0.0f;
+ no[1] = 0.0f;
+ no[2] = 1.0f;
+ }
+ }
normal_float_to_short_v3(mv->no, no);
}
-
+
MEM_freeN(temp_nors);
+ MEM_freeN(vert_nors);
+
+ /*this restores original poly origindex -> tessface origindex mapping,
+ instead of the poly index -> tessface origindex one we generated
+ with cdDM_recalcTesselation2*/
+ cdDM_recalcTesselation(dm);
+ CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_ASSIGN,
+ face_nors, dm->numFaceData);
+}
+
+#if 0
+/*merge verts
+
+ vtargetmap is a table that maps vertices to target vertices. a value of -1
+ indicates a vertex is a target, and is to be kept.
+
+ this is a really horribly written function. ger. - joeedh
+
+ */
+DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, int *vtargetmap)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ CDDerivedMesh *cddm2 = NULL;
+ MVert *mv, *mvert = NULL;
+ BLI_array_declare(mvert);
+ MEdge *me, *medge = NULL;
+ BLI_array_declare(medge);
+ MPoly *mp, *mpoly = NULL;
+ BLI_array_declare(mpoly);
+ MLoop *ml, *mloop = NULL;
+ BLI_array_declare(mloop);
+ SmallHash _hash, *hash=&_hash;
+ SmallHash _hash2, *hash2=&_hash2;
+ int *newv = NULL, *newe = NULL, *newl = NULL;
+ int *oldv = NULL, *olde = NULL, *oldl = NULL, *oldp = NULL;
+ BLI_array_declare(oldv); BLI_array_declare(olde); BLI_array_declare(oldl); BLI_array_declare(oldp);
+ int i, j, c, totloop, totpoly;
+
+ BLI_smallhash_init(hash);
+ BLI_smallhash_init(hash2);
+
+#if 0
+ /*split off ngon faces with merges in them*/
+ mp = cddm->mpoly;
+ for (i=0; i<dm->numPolyData; i++, mp++) {
+ ml = cddm->mloop + mp->loopstart;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ MLoop *ml2 = NULL;
+ int k, k1, a;
+
+ if (ml->v == -1)
+ continue;
+
+ for (k1=0; k1<mp->totloop; k1++) {
+ k = (j + k1) % mp->totloop;
+ ml2 = cddm->mloop + mp->loopstart + k;
+
+ if (ml == ml2 || ml2->v == -1)
+ continue;
+
+ if (vtargetmap[ml->v] == ml2->v || vtargetmap[ml2->v] == ml->v) {
+ MLoop *ml3;
+ MPoly *mp2;
+ int s, e, l, tot;
+
+ if (k < j)
+ SWAP(int, k, j);
+
+ s = j; e = k; tot = 0;
+ l = BLI_array_count(mloop);
+ ml3 = cddm->mloop + mp->loopstart + s;
+ for (a=s; a<e; a++, ml3++) {
+ if (ml3->v == -1)
+ continue;
+
+ BLI_smallhash_insert(hash, dm->numLoopData + BLI_array_count(mloop), SET_INT_IN_POINTER(mp->loopstart + a - s));
+ BLI_array_append(mloop, *ml3);
+
+ ml3->v = -1;
+ ml3->e = -1;
+ tot++;
+ }
+
+ if (!tot)
+ continue;
+
+ BLI_smallhash_insert(hash2, dm->numPolyData + BLI_array_count(mpoly), SET_INT_IN_POINTER(i));
+
+ mp2 = BLI_array_append(mpoly, *mp);
+ mp2->loopstart = l + dm->numLoopData;
+ mp2->totloop = tot;
+ }
+ }
+ }
+ }
+
+ ml = MEM_callocN(sizeof(MLoop)*(dm->numLoopData + BLI_array_count(mloop)), "merge mloop");
+ mp = MEM_callocN(sizeof(MPoly)*(dm->numPolyData + BLI_array_count(mloop)), "merge mpoly");
+
+ memcpy(ml, cddm->mloop, sizeof(MLoop)*dm->numLoopData);
+ memcpy(mp, cddm->mpoly, sizeof(MPoly)*dm->numPolyData);
+
+ cddm->mloop = ml; cddm->mpoly = mp;
+
+ memcpy(cddm->mloop+dm->numLoopData, mloop, sizeof(MLoop)*BLI_array_count(mloop));
+ memcpy(cddm->mpoly+dm->numPolyData, mpoly, sizeof(MPoly)*BLI_array_count(mpoly));
+
+ totloop = dm->numLoopData + BLI_array_count(mloop);
+ totpoly = dm->numPolyData + BLI_array_count(mpoly);
+
+ BLI_array_empty(mloop);
+ BLI_array_empty(mpoly);
+#else
+ totloop = dm->numLoopData;
+ totpoly = dm->numPolyData;
+#endif
+
+ newv = MEM_callocN(sizeof(int)*dm->numVertData, "newv vtable CDDM_merge_verts");
+ newe = MEM_callocN(sizeof(int)*dm->numEdgeData, "newv etable CDDM_merge_verts");
+ newl = MEM_callocN(sizeof(int)*totloop, "newv ltable CDDM_merge_verts");
+
+ mv = cddm->mvert;
+ c = 0;
+ for (i=0; i<dm->numVertData; i++, mv++) {
+ if (vtargetmap[i] == -1) {
+ BLI_array_append(oldv, i);
+ newv[i] = c++;
+ BLI_array_append(mvert, *mv);
+ }
+ }
+
+ /*find-replace merged vertices with target vertices*/
+ ml = cddm->mloop;
+ c = 0;
+ for (i=0; i<totloop; i++, ml++) {
+ if (ml->v == -1)
+ continue;
+
+ if (vtargetmap[ml->v] != -1) {
+ me = &cddm->medge[ml->e];
+ if (me->v1 == ml->v)
+ me->v1 = vtargetmap[ml->v];
+ else
+ me->v2 = vtargetmap[ml->v];
+
+ ml->v = vtargetmap[ml->v];
+ }
+ }
+
+ /*now go through and fix edges and faces*/
+ me = cddm->medge;
+ c = 0;
+ for (i=0; i<dm->numEdgeData; i++, me++) {
+ if (me->v1 == me->v2)
+ continue;
+
+ BLI_array_append(olde, i);
+ newe[i] = c++;
+ BLI_array_append(medge, *me);
+ }
+
+ mp = cddm->mpoly;
+ for (i=0; i<totpoly; i++, mp++) {
+ MPoly *mp2;
+
+ ml = cddm->mloop + mp->loopstart;
+
+ c = 0;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ if (ml->v == -1)
+ continue;
+
+ me = cddm->medge + ml->e;
+ if (me->v1 != me->v2) {
+ BLI_array_append(oldl, j);
+ BLI_array_append(mloop, *ml);
+ newl[c] = BLI_array_count(mloop)-1;
+ c++;
+ }
+ }
+
+ if (!c)
+ continue;
+
+ mp2 = BLI_array_append(mpoly, *mp);
+ mp2->totloop = c;
+ mp2->loopstart = BLI_array_count(mloop) - c;
+
+ BLI_array_append(oldp, i);
+ }
+
+ /*create new cddm*/
+ cddm2 = (CDDerivedMesh*) CDDM_new(BLI_array_count(mvert), BLI_array_count(medge), 0, BLI_array_count(mloop), BLI_array_count(mpoly));
+
+ /*copy over data. CustomData_add_layer can do this, need to look it up.*/
+ memcpy(cddm2->mvert, mvert, sizeof(MVert)*BLI_array_count(mvert));
+ memcpy(cddm2->medge, medge, sizeof(MEdge)*BLI_array_count(medge));
+ memcpy(cddm2->mloop, mloop, sizeof(MLoop)*BLI_array_count(mloop));
+ memcpy(cddm2->mpoly, mpoly, sizeof(MPoly)*BLI_array_count(mpoly));
+
+ BLI_array_free(mvert); BLI_array_free(medge); BLI_array_free(mloop); BLI_array_free(mpoly);
+ mvert = cddm2->mvert; medge = cddm2->medge; mloop = cddm2->mloop; mpoly = cddm2->mpoly;
+
+ /*update edge indices and copy customdata*/
+ me = cddm2->medge;
+ for (i=0; i<cddm2->dm.numEdgeData; i++, me++) {
+ MEdge cpy;
+
+ me->v1 = newv[me->v1];
+ me->v2 = newv[me->v2];
+
+ cpy = *me;
+ CustomData_copy_data(&dm->edgeData, &cddm2->dm.edgeData, olde[i], i, 1);
+ *me = cpy;
+ }
+
+ /*update loop indices and copy customdata*/
+ ml = cddm2->mloop;
+ for (i=0; i<cddm2->dm.numLoopData; i++, ml++) {
+ MLoop cpy;
+
+ ml->e = newe[ml->e];
+ ml->v = newv[ml->v];
+
+ cpy = *ml;
+
+ if (oldl[i] >= dm->numLoopData)
+ oldl[i] = GET_INT_FROM_POINTER(BLI_smallhash_lookup(hash, (intptr_t)oldl[i]));
+
+ CustomData_copy_data(&dm->loopData, &cddm2->dm.loopData, oldl[i], i, 1);
+ *ml = cpy;
+ }
+
+ /*copy vertex customdata*/
+ mv = cddm2->mvert;
+ for (i=0; i<cddm2->dm.numVertData; i++, mv++) {
+ MVert cpy = *mv;
+
+ CustomData_copy_data(&dm->vertData, &cddm2->dm.vertData, oldv[i], i, 1);
+ *mv = cpy;
+ }
+
+ /*copy poly customdata*/
+ mp = cddm2->mpoly;
+ for (i=0; i<cddm2->dm.numPolyData; i++, mp++) {
+ MPoly cpy = *mp;
+
+ if (oldl[i] >= dm->numPolyData)
+ oldl[i] = GET_INT_FROM_POINTER(BLI_smallhash_lookup(hash, (intptr_t)oldl[i]));
+
+ CustomData_copy_data(&dm->polyData, &cddm2->dm.polyData, oldp[i], i, 1);
+ *mp = cpy;
+ }
+
+ /*eek! not sure what to do with ORIGINDEX stuff here!!*/
+ cddm2->dm.numFaceData = mesh_recalcTesselation(&cddm2->dm.faceData, &cddm2->dm.loopData, &cddm2->dm.polyData, cddm2->mvert, 0, cddm2->dm.numLoopData, cddm2->dm.numPolyData, 1, 0);
+ cddm2->mface = CustomData_get_layer(&cddm->dm.faceData, CD_MFACE);
+
+ if (newv)
+ MEM_freeN(newv);
+ if (newe)
+ MEM_freeN(newe);
+ if (newl)
+ MEM_freeN(newl);
+ if (oldv)
+ MEM_freeN(oldv);
+ if (olde)
+ MEM_freeN(olde);
+ if (oldl)
+ MEM_freeN(oldl);
+ if (oldp)
+ MEM_freeN(oldp);
+
+ BLI_smallhash_release(hash);
+ BLI_smallhash_release(hash2);
+
+ dm->needsFree = 1;
+ dm->release(dm);
+
+ return (DerivedMesh*)cddm2;
}
+#endif
void CDDM_calc_edges(DerivedMesh *dm)
{
@@ -1897,6 +2612,83 @@ void CDDM_calc_edges(DerivedMesh *dm)
BLI_edgehash_free(eh, NULL);
}
+
+void CDDM_calc_edges_poly(DerivedMesh *dm)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ CustomData edgeData;
+ EdgeHashIterator *ehi;
+ MPoly *mp = cddm->mpoly;
+ MLoop *ml;
+ MEdge *med;
+ EdgeHash *eh = BLI_edgehash_new();
+ int v1, v2;
+ int *eindex;
+ int i, j, k, *index, numEdges = cddm->dm.numEdgeData, maxFaces = dm->numPolyData;
+
+ eindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
+
+ med = cddm->medge;
+ if (med) {
+ for (i=0; i < numEdges; i++, med++) {
+ BLI_edgehash_insert(eh, med->v1, med->v2, SET_INT_IN_POINTER(i+1));
+ }
+ }
+
+ for (i=0; i < maxFaces; i++, mp++) {
+ ml = cddm->mloop + mp->loopstart;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ v1 = ml->v;
+ v2 = (cddm->mloop + mp->loopstart + ((j+1)%mp->totloop))->v;
+ if (!BLI_edgehash_haskey(eh, v1, v2)) {
+ BLI_edgehash_insert(eh, v1, v2, NULL);
+ }
+ }
+ }
+
+ k = numEdges;
+ numEdges = BLI_edgehash_size(eh);
+
+ /* write new edges into a temporary CustomData */
+ memset(&edgeData, 0, sizeof(edgeData));
+ CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
+ CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
+
+ ehi = BLI_edgehashIterator_new(eh);
+ med = CustomData_get_layer(&edgeData, CD_MEDGE);
+ index = CustomData_get_layer(&edgeData, CD_ORIGINDEX);
+ for(i = 0; !BLI_edgehashIterator_isDone(ehi);
+ BLI_edgehashIterator_step(ehi), ++i, ++med, ++index) {
+ BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2);
+ j = GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi));
+
+ med->flag = ME_EDGEDRAW|ME_EDGERENDER;
+ *index = j==0 ? ORIGINDEX_NONE : eindex[j-1];
+
+ BLI_edgehashIterator_setValue(ehi, SET_INT_IN_POINTER(i));
+ }
+ BLI_edgehashIterator_free(ehi);
+
+ /* free old CustomData and assign new one */
+ CustomData_free(&dm->edgeData, dm->numEdgeData);
+ dm->edgeData = edgeData;
+ dm->numEdgeData = numEdges;
+
+ cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
+
+ mp = cddm->mpoly;
+ for (i=0; i < maxFaces; i++, mp++) {
+ ml = cddm->mloop + mp->loopstart;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ v1 = ml->v;
+ v2 = (cddm->mloop + mp->loopstart + ((j+1)%mp->totloop))->v;
+ ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, v1, v2));
+ }
+ }
+
+ BLI_edgehash_free(eh, NULL);
+}
+
void CDDM_lower_num_verts(DerivedMesh *dm, int numVerts)
{
if (numVerts < dm->numVertData)
@@ -1931,7 +2723,7 @@ MEdge *CDDM_get_edge(DerivedMesh *dm, int index)
return &((CDDerivedMesh*)dm)->medge[index];
}
-MFace *CDDM_get_face(DerivedMesh *dm, int index)
+MFace *CDDM_get_tessface(DerivedMesh *dm, int index)
{
return &((CDDerivedMesh*)dm)->mface[index];
}
@@ -1946,8 +2738,111 @@ MEdge *CDDM_get_edges(DerivedMesh *dm)
return ((CDDerivedMesh*)dm)->medge;
}
-MFace *CDDM_get_faces(DerivedMesh *dm)
+MFace *CDDM_get_tessfaces(DerivedMesh *dm)
{
return ((CDDerivedMesh*)dm)->mface;
}
+MPoly *CDDM_get_polys(DerivedMesh *dm)
+{
+ return ((CDDerivedMesh*)dm)->mpoly;
+}
+
+void CDDM_tessfaces_to_faces(DerivedMesh *dm)
+{
+ /*converts mfaces to mpolys/mloops*/
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ MFace *mf;
+ MEdge *me;
+ MLoop *ml;
+ MPoly *mp;
+ EdgeHash *eh = BLI_edgehash_new();
+ int i, l, totloop, *index1, *index2;
+
+ /*ensure we have all the edges we need*/
+ CDDM_calc_edges(dm);
+
+ /*build edge hash*/
+ me = cddm->medge;
+ for (i=0; i<cddm->dm.numEdgeData; i++, me++) {
+ BLI_edgehash_insert(eh, me->v1, me->v2, SET_INT_IN_POINTER(i));
+ }
+
+ mf = cddm->mface;
+ totloop = 0;
+ for (i=0; i<cddm->dm.numFaceData; i++, mf++) {
+ totloop += mf->v4 ? 4 : 3;
+ }
+
+ CustomData_free(&cddm->dm.polyData, cddm->dm.numPolyData);
+ CustomData_free(&cddm->dm.loopData, cddm->dm.numLoopData);
+
+ cddm->dm.numLoopData = totloop;
+ cddm->dm.numPolyData = cddm->dm.numFaceData;
+
+ if (!totloop) return;
+
+ cddm->mloop = MEM_callocN(sizeof(MLoop)*totloop, "cddm->mloop in CDDM_tessfaces_to_faces");
+ cddm->mpoly = MEM_callocN(sizeof(MPoly)*cddm->dm.numFaceData, "cddm->mpoly in CDDM_tessfaces_to_faces");
+
+ CustomData_add_layer(&cddm->dm.loopData, CD_MLOOP, CD_ASSIGN, cddm->mloop, totloop);
+ CustomData_add_layer(&cddm->dm.polyData, CD_MPOLY, CD_ASSIGN, cddm->mpoly, cddm->dm.numPolyData);
+ CustomData_merge(&cddm->dm.faceData, &cddm->dm.polyData,
+ CD_MASK_ORIGINDEX, CD_DUPLICATE, cddm->dm.numFaceData);
+
+ index1 = CustomData_get_layer(&cddm->dm.faceData, CD_ORIGINDEX);
+ index2 = CustomData_get_layer(&cddm->dm.polyData, CD_ORIGINDEX);
+
+ mf = cddm->mface;
+ mp = cddm->mpoly;
+ ml = cddm->mloop;
+ l = 0;
+ for (i=0; i<cddm->dm.numFaceData; i++, mf++, mp++) {
+ mp->flag = mf->flag;
+ mp->loopstart = l;
+ mp->mat_nr = mf->mat_nr;
+ mp->totloop = mf->v4 ? 4 : 3;
+
+ ml->v = mf->v1;
+ ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v1, mf->v2));
+ ml++, l++;
+
+ ml->v = mf->v2;
+ ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v2, mf->v3));
+ ml++, l++;
+
+ ml->v = mf->v3;
+ ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v3, mf->v4?mf->v4:mf->v1));
+ ml++, l++;
+
+ if (mf->v4) {
+ ml->v = mf->v4;
+ ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v4, mf->v1));
+ ml++, l++;
+ }
+
+ }
+
+ BLI_edgehash_free(eh, NULL);
+}
+
+void CDDM_set_mvert(DerivedMesh *dm, MVert *mvert)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+
+ cddm->mvert = mvert;
+}
+
+void CDDM_set_medge(DerivedMesh *dm, MEdge *medge)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+
+ cddm->medge = medge;
+}
+
+void CDDM_set_mface(DerivedMesh *dm, MFace *mface)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+
+ cddm->mface = mface;
+}
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 09f18514277..c115f6aa470 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -43,7 +43,6 @@
#include "BKE_modifier.h"
#include "BKE_pointcache.h"
-
#ifdef _WIN32
void tstart ( void )
{}
@@ -435,7 +434,7 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob,
clmd->scene= scene; /* nice to pass on later :) */
framenr= (int)scene->r.cfra;
cache= clmd->point_cache;
- result = CDDM_copy(dm);
+ result = CDDM_copy(dm, 0);
BKE_ptcache_id_from_cloth(&pid, ob, clmd);
BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
@@ -929,8 +928,8 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
{
unsigned int numverts = dm->getNumVerts ( dm );
- unsigned int numfaces = dm->getNumFaces ( dm );
- MFace *mface = dm->getFaceArray( dm );
+ unsigned int numfaces = dm->getNumTessFaces ( dm );
+ MFace *mface = dm->getTessFaceArray( dm );
unsigned int i = 0;
/* Allocate our vertices. */
@@ -1042,9 +1041,9 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
unsigned int i = 0;
unsigned int numverts = (unsigned int)dm->getNumVerts ( dm );
unsigned int numedges = (unsigned int)dm->getNumEdges ( dm );
- unsigned int numfaces = (unsigned int)dm->getNumFaces ( dm );
+ unsigned int numfaces = (unsigned int)dm->getNumTessFaces ( dm );
MEdge *medge = dm->getEdgeArray ( dm );
- MFace *mface = dm->getFaceArray ( dm );
+ MFace *mface = dm->getTessFaceArray ( dm );
int index2 = 0; // our second vertex index
LinkNode **edgelist = NULL;
EdgeHash *edgehash = NULL;
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 827dddf34d3..36d19b53ed2 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -39,6 +39,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_editVert.h"
+#include "BLI_cellalloc.h"
#include "BLI_utildefines.h"
#include "DNA_armature_types.h"
@@ -52,6 +53,7 @@
#include "DNA_lattice_types.h"
#include "DNA_scene_types.h"
#include "DNA_text_types.h"
+#include "DNA_windowmanager_types.h"
#include "BKE_action.h"
@@ -68,8 +70,10 @@
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_idprop.h"
+#include "BKE_mesh.h"
#include "BKE_shrinkwrap.h"
#include "BKE_mesh.h"
+#include "BKE_tessmesh.h"
#ifdef WITH_PYTHON
#include "BPY_extern.h"
@@ -423,7 +427,7 @@ static void contarget_get_mesh_mat (Scene *scene, Object *ob, const char *substr
{
DerivedMesh *dm = NULL;
Mesh *me= ob->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
+ BMEditMesh *em = me->edit_btmesh;
float vec[3] = {0.0f, 0.0f, 0.0f};
float normal[3] = {0.0f, 0.0f, 0.0f}, plane[3];
float imat[3][3], tmat[3][3];
@@ -440,7 +444,7 @@ static void contarget_get_mesh_mat (Scene *scene, Object *ob, const char *substr
/* get DerivedMesh */
if (em) {
/* target is in editmode, so get a special derived mesh */
- dm = CDDM_from_editmesh(em, ob->data);
+ dm = CDDM_from_BMEditMesh(em, ob->data);
freeDM= 1;
}
else {
@@ -519,8 +523,6 @@ static void contarget_get_mesh_mat (Scene *scene, Object *ob, const char *substr
/* free temporary DerivedMesh created (in EditMode case) */
if (dm && freeDM)
dm->release(dm);
- if (em)
- BKE_mesh_end_editmesh(me, em);
}
/* function that sets the given matrix based on given vertex group in lattice */
@@ -2536,9 +2538,9 @@ static void locktrack_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *
}
break;
default:
- {
- unit_m3(totmat);
- }
+ {
+ unit_m3(totmat);
+ }
break;
}
/* Block to keep matrix heading */
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index a80b6dfab7d..6f7188115e0 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -41,14 +41,21 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
+#include "PIL_time.h"
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_screen.h"
+#ifdef EVENT_RECORDER
+#include "../../../../intern/ghost/GHOST_C-api.h"
+#endif
+
+#ifndef DISABLE_PYTHON
#ifdef WITH_PYTHON
#include "BPY_extern.h"
#endif
+#endif
/* struct */
@@ -81,6 +88,12 @@ struct bContext {
struct {
int render;
} eval;
+
+#ifdef EVENT_RECORDER
+ int evtrec, evtplay;
+ char evtplaypath[300];
+ double evtlasttime;
+#endif
};
/* context */
@@ -101,6 +114,62 @@ bContext *CTX_copy(const bContext *C)
return newC;
}
+#ifdef EVENT_RECORDER
+extern GHOST_SystemHandle g_system;
+
+int CTX_rec_events(bContext *C)
+{
+ return GHOST_RecordingEvents(g_system);
+}
+
+int CTX_rec_events_set(bContext *C, int state)
+{
+ FILE *f = CTX_rec_file(C);
+
+ if (GHOST_RecordingEvents(g_system) && !state)
+ GHOST_StopRecording(g_system);
+ else if (!GHOST_RecordingEvents(g_system) && state)
+ GHOST_RecordEvents(g_system, f);
+
+ return 1;
+}
+
+FILE *CTX_rec_file(bContext *C)
+{
+ static FILE *f = NULL;
+ if (!f)
+ f = fopen("eventlog.txt", "wb");
+ return f;
+}
+
+int CTX_set_events_path(bContext *C, char *path)
+{
+ if (!path) {
+ C->evtplaypath[0] = 0;
+ } else {
+ FILE *file = fopen(path, "rb");
+
+ if (!file)
+ return 0;
+
+ strcpy(C->evtplaypath, path);
+ if (g_system)
+ GHOST_PlaybackEvents(g_system, file);
+ }
+
+ return 1;
+}
+
+extern int erec_playing;
+int CTX_play_events(bContext *C, char **playpath)
+{
+ if (playpath)
+ *playpath = C->evtplaypath[0] ? C->evtplaypath : NULL;
+
+ return GHOST_PlayingEvents(g_system);
+}
+#endif
+
void CTX_free(bContext *C)
{
MEM_freeN(C);
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 5dc62f2c7af..67e988249f5 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -47,6 +47,7 @@
#include "DNA_key_types.h"
#include "DNA_scene_types.h"
#include "DNA_vfont_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "BKE_animsys.h"
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 87fe545644a..0612a57d85d 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -34,6 +34,7 @@
#include <math.h>
#include <string.h>
+
#include <assert.h>
#include "MEM_guardedalloc.h"
@@ -46,6 +47,7 @@
#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_mempool.h"
+#include "BLI_cellalloc.h"
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
@@ -55,6 +57,11 @@
#include "BKE_utildefines.h"
#include "BKE_multires.h"
+#include "bmesh.h"
+
+#include <math.h>
+#include <string.h>
+
/* number of layers to add when growing a CustomData object */
#define CUSTOMDATA_GROW 5
@@ -97,6 +104,14 @@ typedef struct LayerTypeInfo {
default is assumed to be all zeros */
void (*set_default)(void *data, int count);
+ /* functions necassary for geometry collapse*/
+ int (*equal)(void *data1, void *data2);
+ void (*multiply)(void *data, float fac);
+ void (*initminmax)(void *min, void *max);
+ void (*add)(void *data1, void *data2);
+ void (*dominmax)(void *data1, void *min, void *max);
+ void (*copyvalue)(void *source, void *dest);
+
/* a function to read data from a cdf file */
int (*read)(CDataFile *cdf, void *data, int count);
@@ -123,7 +138,7 @@ static void layerCopy_mdeformvert(const void *source, void *dest,
MDeformVert *dvert = (MDeformVert *)((char *)dest + i * size);
if(dvert->totweight) {
- MDeformWeight *dw = MEM_callocN(dvert->totweight * sizeof(*dw),
+ MDeformWeight *dw = BLI_cellalloc_calloc(dvert->totweight * sizeof(*dw),
"layerCopy_mdeformvert dw");
memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw));
@@ -142,7 +157,7 @@ static void layerFree_mdeformvert(void *data, int count, int size)
MDeformVert *dvert = (MDeformVert *)((char *)data + i * size);
if(dvert->dw) {
- MEM_freeN(dvert->dw);
+ BLI_cellalloc_free(dvert->dw);
dvert->dw = NULL;
dvert->totweight = 0;
}
@@ -151,7 +166,7 @@ static void layerFree_mdeformvert(void *data, int count, int size)
static void linklist_free_simple(void *link)
{
- MEM_freeN(link);
+ BLI_cellalloc_free(link);
}
static void layerInterp_mdeformvert(void **sources, float *weights,
@@ -184,7 +199,7 @@ static void layerInterp_mdeformvert(void **sources, float *weights,
/* if this def_nr is not in the list, add it */
if(!node) {
- MDeformWeight *tmp_dw = MEM_callocN(sizeof(*tmp_dw),
+ MDeformWeight *tmp_dw = BLI_cellalloc_calloc(sizeof(*tmp_dw),
"layerInterp_mdeformvert tmp_dw");
tmp_dw->def_nr = dw->def_nr;
tmp_dw->weight = dw->weight * interp_weight;
@@ -195,10 +210,10 @@ static void layerInterp_mdeformvert(void **sources, float *weights,
}
/* now we know how many unique deform weights there are, so realloc */
- if(dvert->dw) MEM_freeN(dvert->dw);
+ if(dvert->dw) BLI_cellalloc_free(dvert->dw);
if(totweight) {
- dvert->dw = MEM_callocN(sizeof(*dvert->dw) * totweight,
+ dvert->dw = BLI_cellalloc_calloc(sizeof(*dvert->dw) * totweight,
"layerInterp_mdeformvert dvert->dw");
dvert->totweight = totweight;
@@ -278,6 +293,7 @@ static void layerInterp_tface(void **sources, float *weights,
}
*tf = *(MTFace *)sources[0];
+
for(j = 0; j < 4; ++j) {
tf->uv[j][0] = uv[j][0];
tf->uv[j][1] = uv[j][1];
@@ -639,12 +655,86 @@ static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), void *data, int count
}
/* --------- */
+static void layerCopyValue_mloopcol(void *source, void *dest)
+{
+ MLoopCol *m1 = source, *m2 = dest;
+
+ m2->r = m1->r;
+ m2->g = m1->g;
+ m2->b = m1->b;
+ m2->a = m1->a;
+}
+
+static int layerEqual_mloopcol(void *data1, void *data2)
+{
+ MLoopCol *m1 = data1, *m2 = data2;
+ float r, g, b, a;
+
+ r = m1->r - m2->r;
+ g = m1->g - m2->g;
+ b = m1->b - m2->b;
+ a = m1->a - m2->a;
+
+ return r*r + g*g + b*b + a*a < 0.001;
+}
+
+static void layerMultiply_mloopcol(void *data, float fac)
+{
+ MLoopCol *m = data;
+
+ m->r = (float)m->r * fac;
+ m->g = (float)m->g * fac;
+ m->b = (float)m->b * fac;
+ m->a = (float)m->a * fac;
+}
+
+static void layerAdd_mloopcol(void *data1, void *data2)
+{
+ MLoopCol *m = data1, *m2 = data2;
+
+ m->r += m2->r;
+ m->g += m2->g;
+ m->b += m2->b;
+ m->a += m2->a;
+}
+
+static void layerDoMinMax_mloopcol(void *data, void *vmin, void *vmax)
+{
+ MLoopCol *m = data;
+ MLoopCol *min = vmin, *max = vmax;
+
+ if (m->r < min->r) min->r = m->r;
+ if (m->g < min->g) min->g = m->g;
+ if (m->b < min->b) min->b = m->b;
+ if (m->a < min->a) min->a = m->a;
+
+ if (m->r > max->r) max->r = m->r;
+ if (m->g > max->g) max->g = m->g;
+ if (m->b > max->b) max->b = m->b;
+ if (m->a > max->a) max->a = m->a;
+}
+
+static void layerInitMinMax_mloopcol(void *vmin, void *vmax)
+{
+ MLoopCol *min = vmin, *max = vmax;
+
+ min->r = 255;
+ min->g = 255;
+ min->b = 255;
+ min->a = 255;
+
+ max->r = 0;
+ max->g = 0;
+ max->b = 0;
+ max->a = 0;
+}
static void layerDefault_mloopcol(void *data, int count)
{
- static MLoopCol default_mloopcol = {255,255,255,255};
+ MLoopCol default_mloopcol = {255,255,255,255};
MLoopCol *mlcol = (MLoopCol*)data;
int i;
+
for(i = 0; i < count; i++)
mlcol[i] = default_mloopcol;
@@ -694,6 +784,56 @@ static void layerInterp_mloopcol(void **sources, float *weights,
mc->g = (int)col.g;
mc->b = (int)col.b;
}
+
+static void layerCopyValue_mloopuv(void *source, void *dest)
+{
+ MLoopUV *luv1 = source, *luv2 = dest;
+
+ luv2->uv[0] = luv1->uv[0];
+ luv2->uv[1] = luv1->uv[1];
+}
+
+static int layerEqual_mloopuv(void *data1, void *data2)
+{
+ MLoopUV *luv1 = data1, *luv2 = data2;
+ float u, v;
+
+ u = luv1->uv[0] - luv2->uv[0];
+ v = luv1->uv[1] - luv2->uv[1];
+
+ return u*u + v*v < 0.00001;
+}
+
+static void layerMultiply_mloopuv(void *data, float fac)
+{
+ MLoopUV *luv = data;
+
+ luv->uv[0] *= fac;
+ luv->uv[1] *= fac;
+}
+
+static void layerInitMinMax_mloopuv(void *vmin, void *vmax)
+{
+ MLoopUV *min = vmin, *max = vmax;
+
+ INIT_MINMAX2(min->uv, max->uv);
+}
+
+static void layerDoMinMax_mloopuv(void *data, void *vmin, void *vmax)
+{
+ MLoopUV *min = vmin, *max = vmax, *luv = data;
+
+ DO_MINMAX2(luv->uv, min->uv, max->uv);
+}
+
+static void layerAdd_mloopuv(void *data1, void *data2)
+{
+ MLoopUV *l1 = data1, *l2 = data2;
+
+ l1->uv[0] += l2->uv[0];
+ l1->uv[1] += l2->uv[1];
+}
+
static void layerInterp_mloopuv(void **sources, float *weights,
float *sub_weights, int count, void *dest)
{
@@ -801,7 +941,45 @@ static void layerDefault_mcol(void *data, int count)
mcol[i] = default_mcol;
}
+static void layerInterp_bweight(void **sources, float *weights,
+ float *sub_weights, int count, void *dest)
+{
+ float *f = dest, *src;
+ float **in = sources;
+ int i;
+
+ if(count <= 0) return;
+
+ *f = 0.0f;
+
+ for(i = 0; i < count; ++i) {
+ float weight = weights ? weights[i] : 1.0f;
+
+ src = in[i];
+ *f += *src * weight;
+ }
+}
+
+static void layerInterp_shapekey(void **sources, float *weights,
+ float *sub_weights, int count, void *dest)
+{
+ float *co = dest, *src;
+ float **in = sources;
+ int i, j, k;
+
+ if(count <= 0) return;
+ memset(co, 0, sizeof(float)*3);
+
+ for(i = 0; i < count; ++i) {
+ float weight = weights ? weights[i] : 1.0f;
+
+ src = in[i];
+ co[0] += src[0] * weight;
+ co[1] += src[1] * weight;
+ co[2] += src[2] * weight;
+ }
+}
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
@@ -818,7 +996,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerSwap_mcol, layerDefault_mcol},
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
/* 3 floats per normal vector */
- {sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float)*3, "vec3f", 1, NULL, NULL, NULL, NULL, NULL, NULL},
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
{sizeof(MFloatProperty), "MFloatProperty",1,"Float",NULL,NULL,NULL,NULL},
{sizeof(MIntProperty), "MIntProperty",1,"Int",NULL,NULL,NULL,NULL},
@@ -827,49 +1005,71 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerInterp_origspace_face, layerSwap_origspace_face, layerDefault_origspace_face},
{sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
{sizeof(MTexPoly), "MTexPoly", 1, "Face Texture", NULL, NULL, NULL, NULL, NULL},
- {sizeof(MLoopUV), "MLoopUV", 1, "UV coord", NULL, NULL, layerInterp_mloopuv, NULL, NULL},
- {sizeof(MLoopCol), "MLoopCol", 1, "Col", NULL, NULL, layerInterp_mloopcol, NULL, layerDefault_mloopcol},
+ {sizeof(MLoopUV), "MLoopUV", 1, "UV coord", NULL, NULL, layerInterp_mloopuv, NULL, NULL,
+ layerEqual_mloopuv, layerMultiply_mloopuv, layerInitMinMax_mloopuv,
+ layerAdd_mloopuv, layerDoMinMax_mloopuv, layerCopyValue_mloopuv},
+ {sizeof(MLoopCol), "MLoopCol", 1, "Col", NULL, NULL, layerInterp_mloopcol, NULL,
+ layerDefault_mloopcol, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol,
+ layerAdd_mloopcol, layerDoMinMax_mloopcol, layerCopyValue_mloopcol},
{sizeof(float)*4*4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
{sizeof(MDisps), "MDisps", 1, NULL, layerCopy_mdisps,
- layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL, layerRead_mdisps, layerWrite_mdisps,
- layerFilesize_mdisps, layerValidate_mdisps},
+ layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ layerRead_mdisps, layerWrite_mdisps, layerFilesize_mdisps, layerValidate_mdisps},
{sizeof(MCol)*4, "MCol", 4, "WeightCol", NULL, NULL, layerInterp_mcol,
layerSwap_mcol, layerDefault_mcol},
- {sizeof(MCol)*4, "MCol", 4, "IDCol", NULL, NULL, layerInterp_mcol,
+ {sizeof(MPoly), "MPoly", 1, "NGon Face", NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MLoop), "MLoop", 1, "NGon Face-Vertex", NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float)*3, "", 0, "ClothOrco", NULL, NULL, layerInterp_shapekey},
+ {sizeof(MCol)*4, "MCol", 4, "IDCol", NULL, NULL, layerInterp_mcol,
layerSwap_mcol, layerDefault_mcol},
- {sizeof(MCol)*4, "MCol", 4, "TexturedCol", NULL, NULL, layerInterp_mcol,
+ {sizeof(MCol)*4, "MCol", 4, "TextureCol", NULL, NULL, layerInterp_mcol,
layerSwap_mcol, layerDefault_mcol},
- {sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}
+ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float)*3, "", 0, "ShapeKey", NULL, NULL, layerInterp_shapekey},
+ {sizeof(float), "", 0, "BevelWeight", NULL, NULL, layerInterp_bweight},
+ {sizeof(float), "", 0, "SubSurfCrease", NULL, NULL, layerInterp_bweight},
+ {sizeof(MLoopCol), "MLoopCol", 1, "WeightLoopCol", NULL, NULL, layerInterp_mloopcol, NULL,
+ layerDefault_mloopcol, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol,
+ layerAdd_mloopcol, layerDoMinMax_mloopcol, layerCopyValue_mloopcol},
};
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
- /* 0-4 */ "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace",
- /* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags",
- /* 10-14 */ "CDMFloatProperty", "CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco",
- /* 15-19 */ "CDMTexPoly", "CDMLoopUV", "CDMloopCol", "CDTangent", "CDMDisps",
- /* 20-23 */"CDWeightMCol", "CDIDMCol", "CDTextureMCol", "CDClothOrco"
+ "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace", "CDMTFace",
+ "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags","CDMFloatProperty",
+ "CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco", "CDMTexPoly", "CDMLoopUV",
+ "CDMloopCol", "CDTangent", "CDMDisps", "CDWeightMCol", "CDMPoly",
+ "CDMLoop", "CDMClothOrco", "CDMLoopCol", "CDIDCol", "CDTextureCol",
+ "CDShapeKeyIndex", "CDShapeKey", "CDBevelWeight", "CDSubSurfCrease"
};
+
const CustomDataMask CD_MASK_BAREMESH =
- CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE;
+ CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE | CD_MASK_MLOOP | CD_MASK_MPOLY | CD_MASK_BWEIGHT;
const CustomDataMask CD_MASK_MESH =
CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE |
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MCOL |
- CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS;
+ CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS |
+ CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MPOLY | CD_MASK_MLOOP |
+ CD_MASK_MTEXPOLY | CD_MASK_NORMAL | CD_MASK_MDISPS;
const CustomDataMask CD_MASK_EDITMESH =
- CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
- CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS;
+ CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MLOOPUV |
+ CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_SHAPE_KEYINDEX |
+ CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR |
+ CD_MASK_MDISPS | CD_MASK_SHAPEKEY;
const CustomDataMask CD_MASK_DERIVEDMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_CLOTH_ORCO |
- CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT | CD_MASK_WEIGHT_MCOL;
-const CustomDataMask CD_MASK_BMESH =
- CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
+ CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_WEIGHT_MLOOPCOL |
+ CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT |
+ CD_MASK_WEIGHT_MCOL | CD_MASK_NORMAL;
+const CustomDataMask CD_MASK_BMESH = CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY |
+ CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT |
+ CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MDISPS;
const CustomDataMask CD_MASK_FACECORNERS =
CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV |
CD_MASK_MLOOPCOL;
-
static const LayerTypeInfo *layerType_getInfo(int type)
{
if(type < 0 || type >= CD_NUMTYPES) return NULL;
@@ -890,13 +1090,29 @@ static void customData_update_offsets(CustomData *data);
static CustomDataLayer *customData_add_layer__internal(CustomData *data,
int type, int alloctype, void *layerdata, int totelem, const char *name);
+void customData_update_typemap(CustomData *data)
+{
+ int i, lasttype = -1;
+
+ for (i=0; i<CD_NUMTYPES; i++) {
+ data->typemap[i] = -1;
+ }
+
+ for (i=0; i<data->totlayer; i++) {
+ if (data->layers[i].type != lasttype) {
+ data->typemap[data->layers[i].type] = i;
+ }
+ lasttype = data->layers[i].type;
+ }
+}
+
void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
CustomDataMask mask, int alloctype, int totelem)
{
/*const LayerTypeInfo *typeInfo;*/
CustomDataLayer *layer, *newlayer;
int i, type, number = 0, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0, lastflag = 0;
-
+
for(i = 0; i < source->totlayer; ++i) {
layer = &source->layers[i];
/*typeInfo = layerType_getInfo(layer->type);*/ /*UNUSED*/
@@ -917,7 +1133,7 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
if(lastflag & CD_FLAG_NOCOPY) continue;
else if(!((int)mask & (int)(1 << (int)type))) continue;
- else if(number < CustomData_number_of_layers(dest, type)) continue;
+ else if(number+1 < CustomData_number_of_layers(dest, type)) continue;
if((alloctype == CD_ASSIGN) && (lastflag & CD_FLAG_NOFREE))
newlayer = customData_add_layer__internal(dest, type, CD_REFERENCE,
@@ -934,6 +1150,8 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
newlayer->flag |= lastflag & (CD_FLAG_EXTERNAL|CD_FLAG_IN_MEMORY);
}
}
+
+ customData_update_typemap(dest);
}
void CustomData_copy(const struct CustomData *source, struct CustomData *dest,
@@ -1011,6 +1229,17 @@ int CustomData_get_layer_index(const CustomData *data, int type)
return -1;
}
+int CustomData_get_layer_index_n(const struct CustomData *data, int type, int n)
+{
+ int i;
+
+ for(i=0; i < data->totlayer; ++i)
+ if(data->layers[i].type == type)
+ return i + n;
+
+ return -1;
+}
+
int CustomData_get_named_layer_index(const CustomData *data, int type, const char *name)
{
int i;
@@ -1024,11 +1253,12 @@ int CustomData_get_named_layer_index(const CustomData *data, int type, const cha
int CustomData_get_active_layer_index(const CustomData *data, int type)
{
- int i;
+ if (!data->totlayer)
+ return -1;
- for(i=0; i < data->totlayer; ++i)
- if(data->layers[i].type == type)
- return i + data->layers[i].active;
+ if (data->typemap[type] != -1) {
+ return data->typemap[type] + data->layers[data->typemap[type]].active;
+ }
return -1;
}
@@ -1257,6 +1487,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
data->layers[index].type = type;
data->layers[index].flag = flag;
data->layers[index].data = newlayerdata;
+
if(name || (name=typeInfo->defaultname)) {
BLI_strncpy(data->layers[index].name, name, 32);
CustomData_set_layer_unique_name(data, index);
@@ -1289,6 +1520,7 @@ void *CustomData_add_layer(CustomData *data, int type, int alloctype,
layer = customData_add_layer__internal(data, type, alloctype, layerdata,
totelem, typeInfo->defaultname);
+ customData_update_typemap(data);
if(layer)
return layer->data;
@@ -1304,6 +1536,7 @@ void *CustomData_add_layer_named(CustomData *data, int type, int alloctype,
layer = customData_add_layer__internal(data, type, alloctype, layerdata,
totelem, name);
+ customData_update_typemap(data);
if(layer)
return layer->data;
@@ -1342,6 +1575,7 @@ int CustomData_free_layer(CustomData *data, int type, int totelem, int index)
customData_resize(data, -CUSTOMDATA_GROW);
customData_update_offsets(data);
+ customData_update_typemap(data);
return 1;
}
@@ -1451,6 +1685,16 @@ void CustomData_set_only_copy(const struct CustomData *data,
data->layers[i].flag |= CD_FLAG_NOCOPY;
}
+void CustomData_copy_elements(int type, void *source, void *dest, int count)
+{
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+ if (typeInfo->copy)
+ typeInfo->copy(source, dest, count);
+ else
+ memcpy(dest, source, typeInfo->size*count);
+}
+
void CustomData_copy_data(const CustomData *source, CustomData *dest,
int source_index, int dest_index, int count)
{
@@ -1610,6 +1854,19 @@ void *CustomData_get(const CustomData *data, int index, int type)
return (char *)data->layers[layer_index].data + offset;
}
+void *CustomData_get_n(const CustomData *data, int type, int index, int n)
+{
+ int layer_index;
+ int offset;
+
+ /* get the layer index of the first layer of type */
+ layer_index = data->typemap[type];
+ if(layer_index < 0) return NULL;
+
+ offset = layerType_getInfo(type)->size * index;
+ return (char *)data->layers[layer_index+n].data + offset;
+}
+
void *CustomData_get_layer(const CustomData *data, int type)
{
/* get the layer index of the active layer of type */
@@ -1956,17 +2213,18 @@ void CustomData_from_em_block(const CustomData *source, CustomData *dest,
/*Bmesh functions*/
/*needed to convert to/from different face reps*/
-void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata)
+void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata,
+ int totloop, int totpoly)
{
int i;
for(i=0; i < fdata->totlayer; i++){
if(fdata->layers[i].type == CD_MTFACE){
- CustomData_add_layer(pdata, CD_MTEXPOLY, CD_CALLOC, &(fdata->layers[i].name), 0);
- CustomData_add_layer(ldata, CD_MLOOPUV, CD_CALLOC, &(fdata->layers[i].name), 0);
+ CustomData_add_layer(pdata, CD_MTEXPOLY, CD_CALLOC, &(fdata->layers[i].name), totpoly);
+ CustomData_add_layer(ldata, CD_MLOOPUV, CD_CALLOC, &(fdata->layers[i].name), totloop);
}
else if(fdata->layers[i].type == CD_MCOL)
- CustomData_add_layer(ldata, CD_MLOOPCOL, CD_CALLOC, &(fdata->layers[i].name), 0);
- }
+ CustomData_add_layer(ldata, CD_MLOOPCOL, CD_CALLOC, &(fdata->layers[i].name), totloop);
+ }
}
void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, int total){
int i;
@@ -1977,12 +2235,62 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData
for(i=0; i < ldata->totlayer; i++){
if(ldata->layers[i].type == CD_MLOOPCOL)
CustomData_add_layer(fdata, CD_MCOL, CD_CALLOC, &(ldata->layers[i].name), total);
+ if (ldata->layers[i].type == CD_WEIGHT_MLOOPCOL)
+ CustomData_add_layer(fdata, CD_WEIGHT_MCOL, CD_CALLOC, &(ldata->layers[i].name), total);
}
}
void CustomData_bmesh_init_pool(CustomData *data, int allocsize){
- if(data->totlayer)data->pool = BLI_mempool_create(data->totsize, allocsize, allocsize, 0);
+ if(data->totlayer)data->pool = BLI_mempool_create(data->totsize, allocsize, allocsize, 1, 0);
+}
+
+void CustomData_bmesh_merge(CustomData *source, CustomData *dest,
+ int mask, int alloctype, BMesh *bm, int type)
+{
+ BMHeader *h;
+ BMIter iter;
+ CustomData destold = *dest;
+ void *tmp;
+ int t;
+
+ CustomData_merge(source, dest, mask, alloctype, 0);
+ CustomData_bmesh_init_pool(dest, 512);
+
+ switch (type) {
+ case BM_VERT:
+ t = BM_VERTS_OF_MESH; break;
+ case BM_EDGE:
+ t = BM_EDGES_OF_MESH; break;
+ case BM_LOOP:
+ t = BM_LOOPS_OF_FACE; break;
+ case BM_FACE:
+ t = BM_FACES_OF_MESH; break;
+ }
+
+ if (t != BM_LOOPS_OF_FACE) {
+ /*ensure all current elements follow new customdata layout*/
+ BM_ITER(h, &iter, bm, t, NULL) {
+ CustomData_bmesh_copy_data(&destold, dest, h->data, &tmp);
+ CustomData_bmesh_free_block(&destold, &h->data);
+ h->data = tmp;
+ }
+ } else {
+ BMFace *f;
+ BMLoop *l;
+ BMIter liter;
+
+ /*ensure all current elements follow new customdata layout*/
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ CustomData_bmesh_copy_data(&destold, dest, l->head.data, &tmp);
+ CustomData_bmesh_free_block(&destold, &l->head.data);
+ l->head.data = tmp;
+ }
+ }
+ }
+
+ if (destold.pool) BLI_mempool_destroy(destold.pool);
}
void CustomData_bmesh_free_block(CustomData *data, void **block)
@@ -2002,7 +2310,9 @@ void CustomData_bmesh_free_block(CustomData *data, void **block)
}
}
- BLI_mempool_free(data->pool, *block);
+ if (data->totsize)
+ BLI_mempool_free(data->pool, *block);
+
*block = NULL;
}
@@ -2013,7 +2323,7 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
CustomData_bmesh_free_block(data, block);
if (data->totsize > 0)
- *block = BLI_mempool_calloc(data->pool);
+ *block = BLI_mempool_alloc(data->pool);
else
*block = NULL;
}
@@ -2086,6 +2396,82 @@ void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int
return (char *)block + data->layers[layer_index+n].offset;
}
+/*gets from the layer at physical index n, note: doesn't check type.*/
+void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
+{
+ if(n < 0 || n >= data->totlayer) return NULL;
+
+ return (char *)block + data->layers[n].offset;
+}
+
+int CustomData_layer_has_math(struct CustomData *data, int layern)
+{
+ const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layern].type);
+
+ if (typeInfo->equal && typeInfo->add && typeInfo->multiply &&
+ typeInfo->initminmax && typeInfo->dominmax) return 1;
+
+ return 0;
+}
+
+/*copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
+ another, while not overwriting anything else (e.g. flags)*/
+void CustomData_data_copy_value(int type, void *source, void *dest)
+{
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+ if(!dest) return;
+
+ if(typeInfo->copyvalue)
+ typeInfo->copyvalue(source, dest);
+ else
+ memcpy(dest, source, typeInfo->size);
+}
+
+int CustomData_data_equals(int type, void *data1, void *data2)
+{
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+ if (typeInfo->equal)
+ return typeInfo->equal(data1, data2);
+ else return !memcmp(data1, data2, typeInfo->size);
+}
+
+void CustomData_data_initminmax(int type, void *min, void *max)
+{
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+ if (typeInfo->initminmax)
+ typeInfo->initminmax(min, max);
+}
+
+
+void CustomData_data_dominmax(int type, void *data, void *min, void *max)
+{
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+ if (typeInfo->dominmax)
+ typeInfo->dominmax(data, min, max);
+}
+
+
+void CustomData_data_multiply(int type, void *data, float fac)
+{
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+ if (typeInfo->multiply)
+ typeInfo->multiply(data, fac);
+}
+
+
+void CustomData_data_add(int type, void *data1, void *data2)
+{
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+ if (typeInfo->add)
+ typeInfo->add(data1, data2);
+}
+
void CustomData_bmesh_set(const CustomData *data, void *block, int type, void *source)
{
void *dest = CustomData_bmesh_get(data, block, type);
@@ -2112,6 +2498,19 @@ void CustomData_bmesh_set_n(CustomData *data, void *block, int type, int n, void
memcpy(dest, source, typeInfo->size);
}
+void CustomData_bmesh_set_layer_n(CustomData *data, void *block, int n, void *source)
+{
+ void *dest = CustomData_bmesh_get_layer_n(data, block, n);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type);
+
+ if(!dest) return;
+
+ if(typeInfo->copy)
+ typeInfo->copy(source, dest, 1);
+ else
+ memcpy(dest, source, typeInfo->size);
+}
+
void CustomData_bmesh_interp(CustomData *data, void **src_blocks, float *weights,
float *sub_weights, int count, void *dest_block)
{
@@ -2157,6 +2556,7 @@ void CustomData_bmesh_set_default(CustomData *data, void **block)
if(typeInfo->set_default)
typeInfo->set_default((char*)*block + offset, 1);
+ else memset((char*)*block + offset, 0, typeInfo->size);
}
}
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 7967013c2d4..616bcb17f90 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -44,6 +44,7 @@
#include "BKE_deform.h"
#include "BLI_blenlib.h"
+#include "BLI_cellalloc.h"
void defgroup_copy_list (ListBase *outbase, ListBase *inbase)
@@ -84,10 +85,10 @@ void defvert_copy (MDeformVert *dvert_r, const MDeformVert *dvert)
}
else {
if(dvert_r->dw)
- MEM_freeN(dvert_r->dw);
+ BLI_cellalloc_free(dvert_r->dw);
if(dvert->totweight)
- dvert_r->dw= MEM_dupallocN(dvert->dw);
+ dvert_r->dw= BLI_cellalloc_dupalloc(dvert->dw);
else
dvert_r->dw= NULL;
@@ -492,10 +493,10 @@ MDeformWeight *defvert_verify_index(MDeformVert *dv, const int defgroup)
if(newdw)
return newdw;
- newdw = MEM_callocN(sizeof(MDeformWeight)*(dv->totweight+1), "deformWeight");
+ newdw = BLI_cellalloc_calloc(sizeof(MDeformWeight)*(dv->totweight+1), "deformWeight");
if(dv->dw) {
memcpy(newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight);
- MEM_freeN(dv->dw);
+ BLI_cellalloc_free(dv->dw);
}
dv->dw=newdw;
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index b59109c3f2a..59e5aa7ade6 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -510,10 +510,10 @@ static void mesh_create_shadedColors(Render *re, Object *ob, int onlyForMesh, un
dm = mesh_get_derived_final(RE_GetScene(re), ob, dataMask);
mvert = dm->getVertArray(dm);
- mface = dm->getFaceArray(dm);
- nors = dm->getFaceDataArray(dm, CD_NORMAL);
+ mface = dm->getTessFaceArray(dm);
+ nors = dm->getTessFaceDataArray(dm, CD_NORMAL);
totvert = dm->getNumVerts(dm);
- totface = dm->getNumFaces(dm);
+ totface = dm->getNumTessFaces(dm);
orco= dm->getVertDataArray(dm, CD_ORCO);
if (onlyForMesh) {
@@ -1404,7 +1404,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispba
if (dm) {
if (vertCos) {
- DerivedMesh *tdm = CDDM_copy(dm);
+ DerivedMesh *tdm = CDDM_copy(dm, 0);
dm->release(dm);
dm = tdm;
@@ -1445,7 +1445,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispba
if (vertCos) {
if (dm) {
- DerivedMesh *tdm = CDDM_copy(dm);
+ DerivedMesh *tdm = CDDM_copy(dm, 0);
dm->release(dm);
dm = tdm;
diff --git a/source/blender/blenkernel/intern/editderivedbmesh.c b/source/blender/blenkernel/intern/editderivedbmesh.c
new file mode 100644
index 00000000000..b38521b0a23
--- /dev/null
+++ b/source/blender/blenkernel/intern/editderivedbmesh.c
@@ -0,0 +1,1711 @@
+/**
+ * $Id: editderivedbmesh.c 18571 2009-01-19 06:04:57Z joeedh $
+ *
+ * ***** 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., 59 Tbmple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "PIL_time.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_effect_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_key_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h" // N_T
+#include "DNA_scene_types.h" // N_T
+#include "DNA_texture_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_particle_types.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+#include "BLI_edgehash.h"
+#include "BLI_linklist.h"
+#include "BLI_memarena.h"
+#include "BLI_scanfill.h"
+#include "BLI_ghash.h"
+#include "BLI_array.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_deform.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_fluidsim.h"
+#include "BKE_global.h"
+#include "BKE_key.h"
+#include "BKE_material.h"
+#include "BKE_modifier.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_subsurf.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_particle.h"
+#include "BKE_tessmesh.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "GPU_draw.h"
+#include "GPU_extensions.h"
+#include "GPU_material.h"
+
+#include "bmesh.h"
+
+BMEditMesh *BMEdit_Create(BMesh *bm)
+{
+ BMEditMesh *tm = MEM_callocN(sizeof(BMEditMesh), "tm");
+
+ tm->bm = bm;
+
+ BMEdit_RecalcTesselation(tm);
+
+ return tm;
+}
+
+BMEditMesh *BMEdit_Copy(BMEditMesh *tm)
+{
+ BMEditMesh *tm2 = MEM_callocN(sizeof(BMEditMesh), "tm2");
+ *tm2 = *tm;
+
+ tm2->derivedCage = tm2->derivedFinal = NULL;
+
+ tm2->looptris = NULL;
+ tm2->bm = BM_Copy_Mesh(tm->bm);
+ BMEdit_RecalcTesselation(tm2);
+
+ tm2->vert_index = NULL;
+ tm2->edge_index = NULL;
+ tm2->face_index = NULL;
+
+ return tm2;
+}
+
+static void BMEdit_RecalcTesselation_intern(BMEditMesh *tm)
+{
+ BMesh *bm = tm->bm;
+ BMLoop **looptris = NULL;
+ BLI_array_declare(looptris);
+ BMIter iter, liter;
+ BMFace *f;
+ BMLoop *l;
+ int i = 0, j;
+
+ if (tm->looptris) MEM_freeN(tm->looptris);
+
+#if 0 //simple quad/triangle code for performance testing purposes
+ looptris = MEM_callocN(sizeof(void*)*bm->totface*8, "looptris");
+
+ f = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
+ for ( ; f; f=BMIter_Step(&iter)) {
+ EditVert *v, *lastv=NULL, *firstv=NULL;
+ EditEdge *e;
+ EditFace *efa;
+
+ /*don't consider two-edged faces*/
+ if (f->len < 3) continue;
+
+ //BLI_array_growone(looptris);
+ //BLI_array_growone(looptris);
+ //BLI_array_growone(looptris);
+
+ looptris[i*3] = f->loopbase;
+ looptris[i*3+1] = f->loopbase->head.next;
+ looptris[i*3+2] = f->loopbase->head.next->next;
+ i++;
+
+ if (f->len > 3) {
+ //BLI_array_growone(looptris);
+ //BLI_array_growone(looptris);
+ //BLI_array_growone(looptris);
+
+ looptris[i*3] = f->loopbase;
+ looptris[i*3+1] = f->loopbase->head.next->next;
+ looptris[i*3+2] = f->loopbase->head.next->next->next;
+ i++;
+ }
+
+ }
+
+ tm->tottri = i;
+ tm->looptris = looptris;
+ return;
+#endif
+
+ f = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
+ for ( ; f; f=BMIter_Step(&iter)) {
+ EditVert *v, *lastv=NULL, *firstv=NULL;
+ EditEdge *e;
+ EditFace *efa;
+
+ /*don't consider two-edged faces*/
+ if (f->len < 3) continue;
+
+ /*scanfill time*/
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (j=0; l; l=BMIter_Step(&liter), j++) {
+ /*mark order*/
+ l->_index = j;
+
+ v = BLI_addfillvert(l->v->co);
+ v->tmp.p = l;
+
+ if (lastv) {
+ e = BLI_addfilledge(lastv, v);
+ }
+
+ lastv = v;
+ if (firstv==NULL) firstv = v;
+ }
+
+ /*complete the loop*/
+ BLI_addfilledge(firstv, v);
+
+ BLI_edgefill(0);
+
+ for (efa = fillfacebase.first; efa; efa=efa->next) {
+ BMLoop *l1, *l2, *l3;
+
+ BLI_array_growone(looptris);
+ BLI_array_growone(looptris);
+ BLI_array_growone(looptris);
+
+ looptris[i*3] = l1 = efa->v1->tmp.p;
+ looptris[i*3+1] = l2 = efa->v2->tmp.p;
+ looptris[i*3+2] = l3 = efa->v3->tmp.p;
+
+ if (l1->_index > l2->_index) {
+ SWAP(BMLoop*, l1, l2);
+ }
+ if (l2->_index > l3->_index) {
+ SWAP(BMLoop*, l2, l3);
+ }
+ if (l1->_index > l2->_index) {
+ SWAP(BMLoop*, l1, l2);
+ }
+
+ looptris[i*3] = l1;
+ looptris[i*3+1] = l2;
+ looptris[i*3+2] = l3;
+
+ i += 1;
+ }
+
+ BLI_end_edgefill();
+ }
+
+ tm->tottri = i;
+ tm->looptris = looptris;
+}
+
+void BMEdit_RecalcTesselation(BMEditMesh *tm)
+{
+ BMEdit_RecalcTesselation_intern(tm);
+
+ if (tm->derivedFinal && tm->derivedFinal == tm->derivedCage) {
+ if (tm->derivedFinal->recalcTesselation)
+ tm->derivedFinal->recalcTesselation(tm->derivedFinal);
+ } else if (tm->derivedFinal) {
+ if (tm->derivedCage->recalcTesselation)
+ tm->derivedCage->recalcTesselation(tm->derivedCage);
+ if (tm->derivedFinal->recalcTesselation)
+ tm->derivedFinal->recalcTesselation(tm->derivedFinal);
+ }
+}
+
+void BMEdit_UpdateLinkedCustomData(BMEditMesh *em)
+{
+ BMesh *bm = em->bm;
+ int act;
+
+ if (CustomData_has_layer(&bm->pdata, CD_MTEXPOLY)) {
+ act = CustomData_get_active_layer(&bm->pdata, CD_MTEXPOLY);
+ CustomData_set_layer_active(&bm->ldata, CD_MLOOPUV, act);
+
+ act = CustomData_get_render_layer(&bm->pdata, CD_MTEXPOLY);
+ CustomData_set_layer_render(&bm->ldata, CD_MLOOPUV, act);
+
+ act = CustomData_get_clone_layer(&bm->pdata, CD_MTEXPOLY);
+ CustomData_set_layer_clone(&bm->ldata, CD_MLOOPUV, act);
+
+ act = CustomData_get_stencil_layer(&bm->pdata, CD_MTEXPOLY);
+ CustomData_set_layer_stencil(&bm->ldata, CD_MLOOPUV, act);
+ }
+}
+
+/*does not free the BMEditMesh struct itself*/
+void BMEdit_Free(BMEditMesh *em)
+{
+ if(em->derivedFinal) {
+ if (em->derivedFinal!=em->derivedCage) {
+ em->derivedFinal->needsFree= 1;
+ em->derivedFinal->release(em->derivedFinal);
+ }
+ em->derivedFinal= NULL;
+ }
+ if(em->derivedCage) {
+ em->derivedCage->needsFree= 1;
+ em->derivedCage->release(em->derivedCage);
+ em->derivedCage= NULL;
+ }
+
+ em->retopo_paint_data= NULL;
+
+ if (em->looptris) MEM_freeN(em->looptris);
+
+ if (em->vert_index) MEM_freeN(em->vert_index);
+ if (em->edge_index) MEM_freeN(em->edge_index);
+ if (em->face_index) MEM_freeN(em->face_index);
+
+ BM_Free_Mesh(em->bm);
+}
+
+
+/*
+ok, basic design:
+
+the bmesh derivedmesh exposes the mesh as triangles. it stores pointers
+to three loops per triangle. the derivedmesh stores a cache of tesselations
+for each face. this cache will smartly update as needed (though at first
+it'll simply be more brute force). keeping track of face/edge counts may
+be a small problbm.
+
+this won't be the most efficient thing, considering that internal edges and
+faces of tesselations are exposed. looking up an edge by index in particular
+is likely to be a little slow.
+*/
+
+typedef struct EditDerivedBMesh {
+ DerivedMesh dm;
+
+ Object *ob;
+ BMEditMesh *tc;
+
+ float (*vertexCos)[3];
+ float (*vertexNos)[3];
+ float (*faceNos)[3];
+
+ /*lookup caches; these are rebuilt on dm->RecalcTesselation()
+ (or when the derivedmesh is created, of course)*/
+ GHash *vhash, *ehash, *fhash;
+ BMVert **vtable;
+ BMEdge **etable;
+ BMFace **ftable;
+
+ /*private variables, for number of verts/edges/faces
+ within the above hash/table members*/
+ int tv, te, tf;
+
+ /*customdata layout of the tesselated faces*/
+ CustomData tessface_layout;
+} EditDerivedBMesh;
+
+static void bmdm_recalc_lookups(EditDerivedBMesh *bmdm)
+{
+ BMIter iter;
+ BMHeader *h;
+ int a, i, iters[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
+
+ bmdm->tv = bmdm->tc->bm->totvert;
+ bmdm->te = bmdm->tc->bm->totedge;
+ bmdm->tf = bmdm->tc->bm->totface;
+
+ if (bmdm->vhash) BLI_ghash_free(bmdm->vhash, NULL, NULL);
+ if (bmdm->ehash) BLI_ghash_free(bmdm->ehash, NULL, NULL);
+ if (bmdm->fhash) BLI_ghash_free(bmdm->fhash, NULL, NULL);
+
+ bmdm->vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh derived");
+ bmdm->ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh derived");
+ bmdm->fhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh derived");
+
+ if (bmdm->vtable) MEM_freeN(bmdm->vtable);
+ if (bmdm->etable) MEM_freeN(bmdm->etable);
+ if (bmdm->ftable) MEM_freeN(bmdm->ftable);
+
+ if (bmdm->tc->bm->totvert)
+ bmdm->vtable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totvert, "bmdm->vtable");
+ else bmdm->vtable = NULL;
+
+ if (bmdm->tc->bm->totedge)
+ bmdm->etable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totedge, "bmdm->etable");
+ else bmdm->etable = NULL;
+
+ if (bmdm->tc->bm->totface)
+ bmdm->ftable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totface, "bmdm->ftable");
+ else bmdm->ftable = NULL;
+
+ for (a=0; a<3; a++) {
+ h = BMIter_New(&iter, bmdm->tc->bm, iters[a], NULL);
+ for (i=0; h; h=BMIter_Step(&iter), i++) {
+ switch (a) {
+ case 0:
+ bmdm->vtable[i] = (BMVert*) h;
+ BLI_ghash_insert(bmdm->vhash, h, SET_INT_IN_POINTER(i));
+ break;
+ case 1:
+ bmdm->etable[i] = (BMEdge*) h;
+ BLI_ghash_insert(bmdm->ehash, h, SET_INT_IN_POINTER(i));
+ break;
+ case 2:
+ bmdm->ftable[i] = (BMFace*) h;
+ BLI_ghash_insert(bmdm->fhash, h, SET_INT_IN_POINTER(i));
+ break;
+
+ }
+ }
+ }
+}
+
+static void bmDM_recalcTesselation(DerivedMesh *dm)
+{
+ //EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ //bmdm_recalc_lookups(bmdm);
+}
+
+static void bmDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMVert *eve;
+ BMIter iter;
+ int i;
+
+ eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; i++, eve=BMIter_Step(&iter)) {
+ if (bmdm->vertexCos) {
+ func(userData, i, bmdm->vertexCos[i], bmdm->vertexNos[i], NULL);
+ } else {
+ func(userData, i, eve->co, eve->no, NULL);
+ }
+ }
+}
+static void bmDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEdge *eed;
+ BMIter iter;
+ int i;
+
+ if (bmdm->vertexCos) {
+ BMVert *eve;
+ BMIter viter;
+
+ eve = BMIter_New(&viter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&viter), i++) {
+ BMINDEX_SET(eve, i);
+ }
+
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter))
+ func(userData, i,
+ bmdm->vertexCos[BMINDEX_GET(eve)],
+ bmdm->vertexCos[BMINDEX_GET(eve)]);
+ } else {
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter))
+ func(userData, i, eed->v1->co, eed->v2->co);
+ }
+
+}
+
+static void bmDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEdge *eed;
+ BMIter iter;
+ int i;
+
+ if (bmdm->vertexCos) {
+ BMVert *eve;
+ BMIter viter;
+
+ eve = BMIter_New(&viter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&viter), i++) {
+ BMINDEX_SET(eve, i);
+ }
+
+ glBegin(GL_LINES);
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ glVertex3fv(bmdm->vertexCos[BMINDEX_GET(eed->v1)]);
+ glVertex3fv(bmdm->vertexCos[BMINDEX_GET(eed->v2)]);
+ }
+ }
+ glEnd();
+
+ } else {
+ glBegin(GL_LINES);
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ glVertex3fv(eed->v1->co);
+ glVertex3fv(eed->v2->co);
+ }
+ }
+ glEnd();
+ }
+}
+
+static void bmDM_drawEdges(DerivedMesh *dm, int drawLooseEdges)
+{
+ bmDM_drawMappedEdges(dm, NULL, NULL);
+}
+
+static void bmDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEdge *eed;
+ BMIter iter;
+ int i;
+
+ if (bmdm->vertexCos) {
+ BMVert *eve;
+
+ eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++)
+ BMINDEX_SET(eve, i);
+
+ glBegin(GL_LINES);
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ setDrawInterpOptions(userData, i, 0.0);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(eed->v1)]);
+ setDrawInterpOptions(userData, i, 1.0);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(eed->v2)]);
+ }
+ }
+ glEnd();
+ } else {
+ glBegin(GL_LINES);
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ setDrawInterpOptions(userData, i, 0.0);
+ glVertex3fv(eed->v1->co);
+ setDrawInterpOptions(userData, i, 1.0);
+ glVertex3fv(eed->v2->co);
+ }
+ }
+ glEnd();
+ }
+}
+
+static void bmDM_drawUVEdges(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEditMesh *em = bmdm->tc;
+ BMFace *efa;
+ BMIter iter;
+
+ glBegin(GL_LINES);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BMIter liter;
+ BMLoop *l;
+ MLoopUV *lastluv = NULL, *firstluv = NULL;
+
+ if (BM_TestHFlag(efa, BM_HIDDEN))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if (luv) {
+ if (lastluv)
+ glVertex2fv(luv->uv);
+ glVertex2fv(luv->uv);
+
+ lastluv = luv;
+ if (!firstluv)
+ firstluv = luv;
+ }
+ }
+
+ if (lastluv) {
+ glVertex2fv(lastluv->uv);
+ glVertex2fv(firstluv->uv);
+ }
+ }
+ glEnd();
+}
+
+static void bmDM__calcFaceCent(BMesh *bm, BMFace *efa, float cent[3],
+ float (*vertexCos)[3])
+{
+ BMIter iter;
+ BMLoop *l;
+ int tot = 0;
+
+ cent[0] = cent[1] = cent[2] = 0.0f;
+
+ /*simple (and stupid) median (average) based method :/ */
+
+ if (vertexCos) {
+ l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BMIter_Step(&iter)) {
+ VECADD(cent, cent, vertexCos[BMINDEX_GET(l->v)]);
+ tot++;
+ }
+ } else {
+ l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BMIter_Step(&iter)) {
+ VECADD(cent, cent, l->v->co);
+ tot++;
+ }
+ }
+
+ if (tot==0) return;
+ mul_v3_fl(cent, 1.0f/(float)tot);
+}
+
+static void bmDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMVert *eve;
+ BMFace *efa;
+ BMIter iter;
+ float cent[3];
+ int i;
+
+ if (bmdm->vertexCos) {
+ eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++)
+ BMINDEX_SET(eve, i);
+ }
+
+ efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL);
+ for (i=0; efa; efa=BMIter_Step(&iter), i++) {
+ bmDM__calcFaceCent(bmdm->tc->bm, efa, cent, bmdm->vertexCos);
+ func(userData, i, cent, bmdm->vertexCos?bmdm->faceNos[i]:efa->no);
+ }
+}
+
+static void bmDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMFace *efa;
+ BMIter iter;
+ int i, draw;
+
+ if (bmdm->vertexCos) {
+ BMVert *eve;
+
+ eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++)
+ BMINDEX_SET(eve, i);
+
+ efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL);
+ for (i=0; efa; efa=BMIter_Step(&iter), i++)
+ BMINDEX_SET(efa, i);
+
+ for (i=0; i<bmdm->tc->tottri; i++) {
+ BMLoop **l = bmdm->tc->looptris[i];
+ int drawSmooth;
+
+ efa = l[0]->f;
+ drawSmooth = (efa->head.flag & BM_SMOOTH);
+
+ draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BMINDEX_GET(efa), &drawSmooth);
+ if(draw) {
+ if (draw==2) { /* enabled with stipple */
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(stipple_quarttone);
+ }
+
+ glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+
+ glBegin(GL_TRIANGLES);
+
+ if (!drawSmooth) {
+ glNormal3fv(bmdm->faceNos[i]);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[0]->v)]);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[1]->v)]);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[2]->v)]);
+ } else {
+ glNormal3fv(bmdm->vertexNos[(int) BMINDEX_GET(l[0]->v)]);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[0]->v)]);
+ glNormal3fv(bmdm->vertexNos[(int) BMINDEX_GET(l[1]->v)]);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[1]->v)]);
+ glNormal3fv(bmdm->vertexNos[(int) BMINDEX_GET(l[2]->v)]);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[2]->v)]);
+ }
+ glEnd();
+
+ if (draw==2)
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+ }
+ } else {
+ efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL);
+ for (i=0; efa; efa=BMIter_Step(&iter), i++)
+ BMINDEX_SET(efa, i);
+
+ for (i=0; i<bmdm->tc->tottri; i++) {
+ BMLoop **l = bmdm->tc->looptris[i];
+ int drawSmooth;
+
+ efa = l[0]->f;
+ drawSmooth = (efa->head.flag & BM_SMOOTH);
+
+ draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BMINDEX_GET(efa), &drawSmooth);
+ if(draw) {
+ if (draw==2) { /* enabled with stipple */
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(stipple_quarttone);
+ }
+ glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+
+ glBegin(GL_TRIANGLES);
+ if (!drawSmooth) {
+ glNormal3fv(efa->no);
+ glVertex3fv(l[0]->v->co);
+ glVertex3fv(l[1]->v->co);
+ glVertex3fv(l[2]->v->co);
+ } else {
+ glNormal3fv(l[0]->v->no);
+ glVertex3fv(l[0]->v->co);
+ glNormal3fv(l[1]->v->no);
+ glVertex3fv(l[1]->v->co);
+ glNormal3fv(l[2]->v->no);
+ glVertex3fv(l[2]->v->co);
+ }
+ glEnd();
+
+ if (draw==2)
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+ }
+ }
+}
+
+static void bmdm_get_tri_tex(BMesh *bm, BMLoop **ls, MLoopUV *luv[3], MLoopCol *lcol[3],
+ int has_uv, int has_col)
+{
+ if (has_uv) {
+ luv[0] = CustomData_bmesh_get(&bm->ldata, ls[0]->head.data, CD_MLOOPUV);
+ luv[1] = CustomData_bmesh_get(&bm->ldata, ls[1]->head.data, CD_MLOOPUV);
+ luv[2] = CustomData_bmesh_get(&bm->ldata, ls[2]->head.data, CD_MLOOPUV);
+ }
+
+ if (has_col) {
+ lcol[0] = CustomData_bmesh_get(&bm->ldata, ls[0]->head.data, CD_MLOOPCOL);
+ lcol[1] = CustomData_bmesh_get(&bm->ldata, ls[1]->head.data, CD_MLOOPCOL);
+ lcol[2] = CustomData_bmesh_get(&bm->ldata, ls[2]->head.data, CD_MLOOPCOL);
+ }
+
+
+}
+
+static void bmDM_drawFacesTex_common(DerivedMesh *dm,
+ int (*drawParams)(MTFace *tface, int has_vcol, int matnr),
+ int (*drawParamsMapped)(void *userData, int index),
+ void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEditMesh *em = bmdm->tc;
+ BMesh *bm= bmdm->tc->bm;
+ float (*vertexCos)[3]= bmdm->vertexCos;
+ float (*vertexNos)[3]= bmdm->vertexNos;
+ BMFace *efa;
+ BMVert *eve;
+ BMIter iter;
+ MLoopUV *luv[3], dummyluv = {0};
+ MLoopCol *lcol[3], dummylcol = {0};
+ int i, has_vcol = CustomData_has_layer(&bm->ldata, CD_MLOOPCOL);
+ int has_uv = CustomData_has_layer(&bm->pdata, CD_MTEXPOLY);
+
+ luv[0] = luv[1] = luv[2] = &dummyluv;
+ lcol[0] = lcol[1] = lcol[2] = &dummylcol;
+
+ dummylcol.a = dummylcol.r = dummylcol.g = dummylcol.b = 255;
+
+ /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
+ glShadeModel(GL_SMOOTH);
+
+ i = 0;
+ BM_ITER(efa, &iter, bm, BM_FACES_OF_MESH, NULL)
+ BMINDEX_SET(efa, i++);
+
+ if (vertexCos) {
+ i = 0;
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
+ BMINDEX_SET(eve, i++);
+
+ glBegin(GL_TRIANGLES);
+ for (i=0; i<em->tottri; i++) {
+ BMLoop **ls = em->looptris[i];
+ MTexPoly *tp= CustomData_bmesh_get(&bm->pdata, ls[0]->f->head.data, CD_MTEXPOLY);
+ MTFace mtf = {0};
+ unsigned char *cp= NULL;
+ int drawSmooth= BM_TestHFlag(ls[0]->f, BM_SMOOTH);
+ int flag;
+
+ efa = ls[0]->f;
+
+ if (has_uv) {
+ mtf.flag = tp->flag;
+ mtf.tpage = tp->tpage;
+ mtf.transp = tp->transp;
+ mtf.mode = tp->mode;
+ mtf.tile = tp->tile;
+ mtf.unwrap = tp->unwrap;
+ }
+
+ if(drawParams)
+ flag= drawParams(&mtf, has_vcol, efa->mat_nr);
+ else if(drawParamsMapped)
+ flag= drawParamsMapped(userData, BMINDEX_GET(efa));
+ else
+ flag= 1;
+
+ if(flag != 0) { /* flag 0 == the face is hidden or invisible */
+
+ /* we always want smooth here since otherwise vertex colors dont interpolate */
+ if (!has_vcol) {
+ glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+ }
+
+ if (!drawSmooth) {
+ glNormal3fv(bmdm->faceNos[i]);
+
+ bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
+
+ glTexCoord2fv(luv[0]->uv);
+ glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
+ glVertex3fv(vertexCos[BMINDEX_GET(ls[0]->v)]);
+
+ glTexCoord2fv(luv[1]->uv);
+ glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
+ glVertex3fv(vertexCos[BMINDEX_GET(ls[1]->v)]);
+
+ glTexCoord2fv(luv[2]->uv);
+ glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
+ glVertex3fv(vertexCos[BMINDEX_GET(ls[2]->v)]);
+ } else {
+ bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
+
+ glTexCoord2fv(luv[0]->uv);
+ glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
+ glNormal3fv(vertexNos[BMINDEX_GET(ls[0]->v)]);
+ glVertex3fv(vertexCos[BMINDEX_GET(ls[0]->v)]);
+
+ glTexCoord2fv(luv[1]->uv);
+ glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
+ glNormal3fv(vertexNos[BMINDEX_GET(ls[1]->v)]);
+ glVertex3fv(vertexCos[BMINDEX_GET(ls[1]->v)]);
+
+ glTexCoord2fv(luv[2]->uv);
+ glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
+ glNormal3fv(vertexNos[BMINDEX_GET(ls[2]->v)]);
+ glVertex3fv(vertexCos[BMINDEX_GET(ls[2]->v)]);
+ }
+ }
+ }
+ glEnd();
+ } else {
+ i = 0;
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
+ BMINDEX_SET(eve, i++);
+
+ for (i=0; i<em->tottri; i++) {
+ BMLoop **ls = em->looptris[i];
+ MTexPoly *tp= CustomData_bmesh_get(&bm->pdata, ls[0]->f->head.data, CD_MTEXPOLY);
+ MTFace mtf = {0};
+ unsigned char *cp= NULL;
+ int drawSmooth= BM_TestHFlag(ls[0]->f, BM_SMOOTH);
+ int flag;
+
+ efa = ls[0]->f;
+
+ if (has_uv) {
+ mtf.flag = tp->flag;
+ mtf.tpage = tp->tpage;
+ mtf.transp = tp->transp;
+ mtf.mode = tp->mode;
+ mtf.tile = tp->tile;
+ mtf.unwrap = tp->unwrap;
+ }
+
+ if(drawParams)
+ flag= drawParams(&mtf, has_vcol, efa->mat_nr);
+ else if(drawParamsMapped)
+ flag= drawParamsMapped(userData, BMINDEX_GET(efa));
+ else
+ flag= 1;
+
+ if(flag != 0) { /* flag 0 == the face is hidden or invisible */
+
+ /* we always want smooth here since otherwise vertex colors dont interpolate */
+ if (!has_vcol) {
+ glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+ }
+
+ glBegin(GL_TRIANGLES);
+ if (!drawSmooth) {
+ glNormal3fv(efa->no);
+
+ bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
+
+ if (luv[0])
+ glTexCoord2fv(luv[0]->uv);
+ if (lcol[0])
+ glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
+ else glColor3ub(0, 0, 0);
+ glVertex3fv(ls[0]->v->co);
+
+ if (luv[1])
+ glTexCoord2fv(luv[1]->uv);
+ if (lcol[1])
+ glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
+ else glColor3ub(0, 0, 0);
+ glVertex3fv(ls[1]->v->co);
+
+ if (luv[2])
+ glTexCoord2fv(luv[2]->uv);
+ if (lcol[2])
+ glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
+ else glColor3ub(0, 0, 0);
+ glVertex3fv(ls[2]->v->co);
+ } else {
+ bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
+
+ if (luv[0])
+ glTexCoord2fv(luv[0]->uv);
+ if (lcol[0])
+ glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
+ else glColor3ub(0, 0, 0);
+ glNormal3fv(ls[0]->v->no);
+ glVertex3fv(ls[0]->v->co);
+
+ if (luv[1])
+ glTexCoord2fv(luv[1]->uv);
+ if (lcol[1])
+ glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
+ else glColor3ub(0, 0, 0);
+ glNormal3fv(ls[1]->v->no);
+ glVertex3fv(ls[1]->v->co);
+
+ if (luv[2])
+ glTexCoord2fv(luv[2]->uv);
+ if (lcol[2])
+ glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
+ else glColor3ub(0, 0, 0);
+ glNormal3fv(ls[2]->v->no);
+ glVertex3fv(ls[2]->v->co);
+ }
+ glEnd();
+ }
+ }
+ }
+}
+
+static void bmDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr))
+{
+ bmDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
+}
+
+static void bmDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+{
+ bmDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
+}
+
+static void bmDM_drawMappedFacesGLSL(DerivedMesh *dm,
+ int (*setMaterial)(int, void *attribs),
+ int (*setDrawOptions)(void *userData, int index), void *userData)
+{
+#if 0
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMesh *bm= bmdm->tc->bm;
+ float (*vertexCos)[3]= bmdm->vertexCos;
+ float (*vertexNos)[3]= bmdm->vertexNos;
+ BMVert *eve;
+ BMFace *efa;
+ DMVertexAttribs attribs;
+ GPUVertexAttribs gattribs;
+ MTFace *tf;
+ int transp, new_transp, orig_transp, tfoffset;
+ int i, b, matnr, new_matnr, dodraw, layer;
+
+ dodraw = 0;
+ matnr = -1;
+
+ transp = GPU_get_material_blend_mode();
+ orig_transp = transp;
+ layer = CustomData_get_layer_index(&bm->pdata, CD_MTFACE);
+ tfoffset = (layer == -1)? -1: bm->pdata.layers[layer].offset;
+
+ memset(&attribs, 0, sizeof(attribs));
+
+ /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
+ glShadeModel(GL_SMOOTH);
+
+ for (i=0,eve=bm->verts.first; eve; eve= eve->next)
+ BMINDEX_SET(eve, i++);
+
+#define PASSATTRIB(efa, eve, vert) { \
+ if(attribs.totorco) { \
+ float *orco = attribs.orco.array[BMINDEX_GET(eve)]; \
+ glVertexAttrib3fvARB(attribs.orco.glIndex, orco); \
+ } \
+ for(b = 0; b < attribs.tottface; b++) { \
+ MTFace *_tf = (MTFace*)((char*)efa->data + attribs.tface[b].bmOffset); \
+ glVertexAttrib2fvARB(attribs.tface[b].glIndex, _tf->uv[vert]); \
+ } \
+ for(b = 0; b < attribs.totmcol; b++) { \
+ MCol *cp = (MCol*)((char*)efa->data + attribs.mcol[b].bmOffset); \
+ GLubyte col[4]; \
+ col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a; \
+ glVertexAttrib4ubvARB(attribs.mcol[b].glIndex, col); \
+ } \
+ if(attribs.tottang) { \
+ float *tang = attribs.tang.array[i*4 + vert]; \
+ glVertexAttrib3fvARB(attribs.tang.glIndex, tang); \
+ } \
+}
+
+ for (i=0,efa= bm->faces.first; efa; i++,efa= efa->next) {
+ int drawSmooth= (efa->flag & ME_SMOOTH);
+
+ if(setDrawOptions && !setDrawOptions(userData, i))
+ continue;
+
+ new_matnr = efa->mat_nr + 1;
+ if(new_matnr != matnr) {
+ dodraw = setMaterial(matnr = new_matnr, &gattribs);
+ if(dodraw)
+ DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+ }
+
+ if(tfoffset != -1) {
+ tf = (MTFace*)((char*)efa->data)+tfoffset;
+ new_transp = tf->transp;
+
+ if(new_transp != transp) {
+ if(new_transp == GPU_BLEND_SOLID && orig_transp != GPU_BLEND_SOLID)
+ GPU_set_material_blend_mode(orig_transp);
+ else
+ GPU_set_material_blend_mode(new_transp);
+ transp = new_transp;
+ }
+ }
+
+ if(dodraw) {
+ glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
+ if (!drawSmooth) {
+ if(vertexCos) glNormal3fv(bmdm->faceNos[i]);
+ else glNormal3fv(efa->n);
+
+ PASSATTRIB(efa, efa->v1, 0);
+ if(vertexCos) glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
+ else glVertex3fv(efa->v1->co);
+
+ PASSATTRIB(efa, efa->v2, 1);
+ if(vertexCos) glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
+ else glVertex3fv(efa->v2->co);
+
+ PASSATTRIB(efa, efa->v3, 2);
+ if(vertexCos) glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
+ else glVertex3fv(efa->v3->co);
+
+ if(efa->v4) {
+ PASSATTRIB(efa, efa->v4, 3);
+ if(vertexCos) glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
+ else glVertex3fv(efa->v4->co);
+ }
+ } else {
+ PASSATTRIB(efa, efa->v1, 0);
+ if(vertexCos) {
+ glNormal3fv(vertexNos[(int) efa->v1->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
+ }
+ else {
+ glNormal3fv(efa->v1->no);
+ glVertex3fv(efa->v1->co);
+ }
+
+ PASSATTRIB(efa, efa->v2, 1);
+ if(vertexCos) {
+ glNormal3fv(vertexNos[(int) efa->v2->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
+ }
+ else {
+ glNormal3fv(efa->v2->no);
+ glVertex3fv(efa->v2->co);
+ }
+
+ PASSATTRIB(efa, efa->v3, 2);
+ if(vertexCos) {
+ glNormal3fv(vertexNos[(int) efa->v3->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
+ }
+ else {
+ glNormal3fv(efa->v3->no);
+ glVertex3fv(efa->v3->co);
+ }
+
+ if(efa->v4) {
+ PASSATTRIB(efa, efa->v4, 3);
+ if(vertexCos) {
+ glNormal3fv(vertexNos[(int) efa->v4->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
+ }
+ else {
+ glNormal3fv(efa->v4->no);
+ glVertex3fv(efa->v4->co);
+ }
+ }
+ }
+ glEnd();
+ }
+ }
+#endif
+}
+
+static void bmDM_drawFacesGLSL(DerivedMesh *dm,
+ int (*setMaterial)(int, void *attribs))
+{
+ dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
+}
+
+static void bmDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMVert *eve;
+ BMIter iter;
+ int i;
+
+ if (bmdm->tc->bm->totvert) {
+ eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++) {
+ if (bmdm->vertexCos) {
+ DO_MINMAX(bmdm->vertexCos[i], min_r, max_r);
+ } else {
+ DO_MINMAX(eve->co, min_r, max_r);
+ }
+ }
+ } else {
+ min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
+ }
+}
+static int bmDM_getNumVerts(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ return bmdm->tc->bm->totvert;
+}
+
+static int bmDM_getNumEdges(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ return bmdm->tc->bm->totedge;
+}
+
+static int bmDM_getNumTessFaces(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ return bmdm->tc->tottri;
+}
+
+static int bmDM_getNumFaces(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ return bmdm->tc->bm->totface;
+}
+
+static int bmvert_to_mvert(BMesh *bm, BMVert *ev, MVert *vert_r)
+{
+ VECCOPY(vert_r->co, ev->co);
+
+ vert_r->no[0] = (short)(ev->no[0] * 32767.0f);
+ vert_r->no[1] = (short)(ev->no[1] * 32767.0f);
+ vert_r->no[2] = (short)(ev->no[2] * 32767.0f);
+
+ vert_r->flag = BMFlags_To_MEFlags(ev);
+
+ if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
+ vert_r->bweight = (unsigned char) (BM_GetCDf(&bm->vdata, ev, CD_BWEIGHT)*255.0f);
+ }
+
+ return 1;
+}
+
+static void bmDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
+{
+ BMVert *ev;
+
+ if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tv) {
+ printf("error in bmDM_getVert.\n");
+ return;
+ }
+
+ ev = ((EditDerivedBMesh *)dm)->vtable[index];
+ bmvert_to_mvert(((EditDerivedBMesh *)dm)->tc->bm, ev, vert_r);
+}
+
+static void bmDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMEdge *e;
+
+ if (index < 0 || index >= ((EditDerivedBMesh *)dm)->te) {
+ printf("error in bmDM_getEdge.\n");
+ return;
+ }
+
+ e = bmdm->etable[index];
+
+ if (CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
+ edge_r->bweight = (unsigned char) (BM_GetCDf(&bm->edata, e, CD_BWEIGHT)*255.0f);
+ }
+
+ if (CustomData_has_layer(&bm->edata, CD_CREASE)) {
+ edge_r->crease = (unsigned char) (BM_GetCDf(&bm->edata, e, CD_CREASE)*255.0f);
+ }
+
+ edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
+ edge_r->flag |= BMFlags_To_MEFlags(e);
+#if 0
+ /* this needs setup of f2 field */
+ if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
+#endif
+
+ edge_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v1));
+ edge_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v2));
+}
+
+static void bmDM_getTessFace(DerivedMesh *dm, int index, MFace *face_r)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMFace *ef;
+ BMLoop **l;
+
+ if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tf) {
+ printf("error in bmDM_getTessFace.\n");
+ return;
+ }
+
+ l = ((EditDerivedBMesh *)dm)->tc->looptris[index];
+
+ ef = l[0]->f;
+
+ face_r->mat_nr = (unsigned char) ef->mat_nr;
+ face_r->flag = BMFlags_To_MEFlags(ef);
+
+ face_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[0]->v));
+ face_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[1]->v));
+ face_r->v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[2]->v));
+ face_r->v4 = 0;
+
+ test_index_face(face_r, NULL, 0, 3);
+}
+
+static void bmDM_copyVertArray(DerivedMesh *dm, MVert *vert_r)
+{
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMVert *ev;
+ BMIter iter;
+
+ ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for( ; ev; ev = BMIter_Step(&iter), ++vert_r) {
+ VECCOPY(vert_r->co, ev->co);
+
+ vert_r->no[0] = (short) (ev->no[0] * 32767.0);
+ vert_r->no[1] = (short) (ev->no[1] * 32767.0);
+ vert_r->no[2] = (short) (ev->no[2] * 32767.0);
+
+ vert_r->flag = BMFlags_To_MEFlags(ev);
+
+ if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
+ vert_r->bweight = (unsigned char) (BM_GetCDf(&bm->vdata, ev, CD_BWEIGHT)*255.0f);
+ }
+ }
+}
+
+static void bmDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
+{
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMEdge *ee;
+ BMIter iter;
+ BMVert *ev;
+ int i;
+
+ /* store vertex indices in tmp union */
+ ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; ev; ev=BMIter_Step(&iter), i++)
+ BMINDEX_SET(ev, i);
+
+ ee = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);
+ for( ; ee; ee=BMIter_Step(&iter)) {
+ if (CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
+ edge_r->bweight = (unsigned char) (BM_GetCDf(&bm->edata, ee, CD_BWEIGHT)*255.0f);
+ }
+
+ if (CustomData_has_layer(&bm->edata, CD_CREASE)) {
+ edge_r->crease = (unsigned char) (BM_GetCDf(&bm->edata, ee, CD_CREASE)*255.0f);
+ }
+
+ edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
+ if (ee->head.flag & BM_SEAM) edge_r->flag |= ME_SEAM;
+ if (ee->head.flag & BM_SHARP) edge_r->flag |= ME_SHARP;
+#if 0
+ /* this needs setup of f2 field */
+ if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
+#endif
+
+ edge_r->v1 = (int)BMINDEX_GET(ee->v1);
+ edge_r->v2 = (int)BMINDEX_GET(ee->v2);
+ }
+}
+
+static void bmDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMFace *ef;
+ BMVert *ev;
+ BMIter iter;
+ BMLoop **l;
+ int i;
+
+ /* store vertexes indices in tmp union */
+ ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; ev; ev=BMIter_Step(&iter), i++)
+ BMINDEX_SET(ev, i);
+
+ for (i=0; i<bmdm->tc->tottri; i++) {
+ l = bmdm->tc->looptris[i];
+ ef = l[0]->f;
+
+ face_r->mat_nr = (unsigned char) ef->mat_nr;
+
+ /*HACK/TODO: need to convert this*/
+ face_r->flag = ef->head.flag;
+
+ face_r->v1 = BMINDEX_GET(l[0]->v);
+ face_r->v2 = BMINDEX_GET(l[1]->v);
+ face_r->v3 = BMINDEX_GET(l[2]->v);
+ face_r->v4 = 0;
+
+ test_index_face(face_r, NULL, 0, 3);
+ }
+}
+
+static void *bmDM_getFaceDataArray(DerivedMesh *dm, int type)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMesh *bm= bmdm->tc->bm;
+ BMFace *efa;
+ char *data, *bmdata;
+ void *datalayer;
+ int index, offset, size, i;
+
+ datalayer = DM_get_tessface_data_layer(dm, type);
+ if(datalayer)
+ return datalayer;
+
+ /* layers are store per face for editmesh, we convert to a tbmporary
+ * data layer array in the derivedmesh when these are requested */
+ if(type == CD_MTFACE || type == CD_MCOL) {
+ index = CustomData_get_layer_index(&bm->pdata, type);
+
+ if(index != -1) {
+ offset = bm->pdata.layers[index].offset;
+ size = CustomData_sizeof(type);
+
+ DM_add_tessface_layer(dm, type, CD_CALLOC, NULL);
+ index = CustomData_get_layer_index(&dm->faceData, type);
+ dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY;
+
+ data = datalayer = DM_get_tessface_data_layer(dm, type);
+ for (i=0; i<bmdm->tc->tottri; i++, data+=size) {
+ efa = bmdm->tc->looptris[i][0]->f;
+ /*BMESH_TODO: need to still add tface data,
+ derived from the loops.*/
+ bmdata = CustomData_bmesh_get(&bm->pdata, efa->head.data, type);
+ memcpy(data, bmdata, size);
+ }
+ }
+ }
+
+ return datalayer;
+}
+
+typedef struct bmDM_loopIter {
+ DMLoopIter head;
+
+ BMFace *f;
+ BMLoop *l, *nextl;
+ BMIter iter;
+ BMesh *bm;
+} bmDM_loopIter;
+
+typedef struct bmDM_faceIter {
+ DMFaceIter head;
+
+ BMFace *f, *nextf;
+ BMIter iter;
+ BMesh *bm;
+
+ bmDM_loopIter loopiter;
+} bmDM_faceIter;
+
+void bmDM_faceIterStep(void *self)
+{
+ bmDM_faceIter *iter = self;
+
+ if (iter->f) {
+ iter->f->mat_nr = iter->head.mat_nr;
+ iter->f->head.flag = MEFlags_To_BMFlags(iter->head.flags, BM_FACE);
+ }
+
+ iter->f = iter->nextf;
+
+ iter->head.mat_nr = iter->f->mat_nr;
+ iter->head.flags = BMFlags_To_MEFlags(iter->f);
+ iter->head.index++;
+
+ iter->head.len = iter->f->len;
+
+ iter->nextf = BMIter_Step(&iter->iter);
+
+ if (!iter->nextf) iter->head.done = 1;
+}
+
+void *bmDM_getFaceCDData(void *self, int type, int layer)
+{
+ bmDM_faceIter *iter = self;
+
+ if (layer == -1)
+ return CustomData_bmesh_get(&iter->bm->pdata, iter->f->head.data, type);
+ else return CustomData_bmesh_get_n(&iter->bm->pdata, iter->f->head.data, type, layer);
+}
+
+void bmDM_loopIterStep(void *self)
+{
+ bmDM_loopIter *iter = self;
+
+ iter->l = BMIter_Step(&iter->iter);
+ if (!iter->l) {
+ iter->head.done = 1;
+ return;
+ }
+
+ bmvert_to_mvert(iter->bm, iter->l->v, &iter->head.v);
+ iter->head.index++;
+ iter->head.vindex = BMINDEX_GET(iter->l->v);
+ iter->head.eindex = BMINDEX_GET(iter->l->e);
+}
+
+void *bmDM_getLoopCDData(void *self, int type, int layer)
+{
+ bmDM_loopIter *iter = self;
+
+ if (layer == -1)
+ return CustomData_bmesh_get(&iter->bm->ldata, iter->l->head.data, type);
+ else return CustomData_bmesh_get_n(&iter->bm->ldata, iter->l->head.data, type, layer);
+}
+
+void *bmDM_getVertCDData(void *self, int type, int layer)
+{
+ bmDM_loopIter *iter = self;
+
+ if (layer == -1)
+ return CustomData_bmesh_get(&iter->bm->vdata, iter->l->v->head.data, type);
+ else return CustomData_bmesh_get_n(&iter->bm->vdata, iter->l->v->head.data, type, layer);
+}
+
+void bmDM_iterFree(void *self)
+{
+ MEM_freeN(self);
+}
+
+void bmDM_nulliterFree(void *self)
+{
+}
+
+DMLoopIter *bmDM_newLoopsIter(void *faceiter)
+{
+ bmDM_faceIter *fiter = faceiter;
+ bmDM_loopIter *iter = &fiter->loopiter;
+
+ memset(&fiter->loopiter, 0, sizeof(bmDM_loopIter));
+
+ iter->bm = fiter->bm;
+ iter->f = fiter->f;
+ iter->l = BMIter_New(&iter->iter, iter->bm, BM_LOOPS_OF_FACE, iter->f);
+
+ iter->head.step = bmDM_loopIterStep;
+ iter->head.getLoopCDData = bmDM_getLoopCDData;
+ iter->head.getVertCDData = bmDM_getVertCDData;
+
+ bmvert_to_mvert(iter->bm, iter->l->v, &iter->head.v);
+ iter->head.vindex = BMINDEX_GET(iter->l->v);
+ iter->head.eindex = BMINDEX_GET(iter->l->e);
+
+ return (DMLoopIter*) iter;
+}
+
+static DMFaceIter *bmDM_getFaceIter(void *dm)
+{
+ EditDerivedBMesh *bmdm= dm;
+ bmDM_faceIter *iter = MEM_callocN(sizeof(bmDM_faceIter), "bmDM_faceIter");
+ BMIter biter;
+ BMVert *v;
+ BMEdge *e;
+ int i;
+
+ iter->bm = bmdm->tc->bm;
+ iter->f = iter->nextf = BMIter_New(&iter->iter, iter->bm, BM_FACES_OF_MESH, NULL);
+
+ iter->head.step = bmDM_faceIterStep;
+ iter->head.free = bmDM_iterFree;
+ iter->head.getCDData = bmDM_getFaceCDData;
+ iter->head.getLoopsIter = bmDM_newLoopsIter;
+
+ iter->head.mat_nr = iter->f->mat_nr;
+ iter->head.flags = BMFlags_To_MEFlags(iter->f);
+
+ /*set up vert/edge indices*/
+ i = 0;
+ BM_ITER(v, &biter, iter->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(v, i);
+ i++;
+ }
+
+ i = 0;
+ BM_ITER(e, &biter, iter->bm, BM_EDGES_OF_MESH, NULL) {
+ BMINDEX_SET(e, i);
+ i++;
+ }
+
+ return (DMFaceIter*) iter;
+}
+
+static void bmDM_release(void *dm)
+{
+ EditDerivedBMesh *bmdm= dm;
+
+ if (DM_release(dm)) {
+ if (bmdm->vertexCos) {
+ MEM_freeN(bmdm->vertexCos);
+ MEM_freeN(bmdm->vertexNos);
+ MEM_freeN(bmdm->faceNos);
+ }
+
+ if (bmdm->fhash) BLI_ghash_free(bmdm->fhash, NULL, NULL);
+ if (bmdm->ehash) BLI_ghash_free(bmdm->ehash, NULL, NULL);
+ if (bmdm->vhash) BLI_ghash_free(bmdm->vhash, NULL, NULL);
+
+ if (bmdm->vtable) MEM_freeN(bmdm->vtable);
+ if (bmdm->etable) MEM_freeN(bmdm->etable);
+ if (bmdm->ftable) MEM_freeN(bmdm->ftable);
+
+ MEM_freeN(bmdm);
+ }
+}
+
+CustomData *bmDm_getVertDataLayout(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
+
+ return &bmdm->tc->bm->vdata;
+}
+
+CustomData *bmDm_getEdgeDataLayout(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
+
+ return &bmdm->tc->bm->edata;
+}
+
+CustomData *bmDm_getTessFaceDataLayout(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
+
+ return &bmdm->tessface_layout;
+}
+
+CustomData *bmDm_getLoopDataLayout(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
+
+ return &bmdm->tc->bm->ldata;
+}
+
+CustomData *bmDm_getFaceDataLayout(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
+
+ return &bmdm->tc->bm->pdata;
+}
+
+
+DerivedMesh *getEditDerivedBMesh(BMEditMesh *em, Object *ob,
+ float (*vertexCos)[3])
+{
+ EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), "bmdm");
+ BMesh *bm = em->bm;
+ int i;
+
+ bmdm->tc = em;
+
+ DM_init((DerivedMesh*)bmdm, DM_TYPE_EDITBMESH, em->bm->totvert,
+ em->bm->totedge, em->tottri, em->bm->totloop, em->bm->totface);
+
+ for (i=0; i<bm->ldata.totlayer; i++) {
+ if (bm->ldata.layers[i].type == CD_MLOOPCOL) {
+ CustomData_add_layer(&bmdm->tessface_layout, CD_MCOL, CD_ASSIGN, NULL, 0);
+ } else if (bm->ldata.layers[i].type == CD_MLOOPUV) {
+ CustomData_add_layer(&bmdm->tessface_layout, CD_MTFACE, CD_ASSIGN, NULL, 0);
+ }
+ }
+
+ bmdm->dm.numVertData = bm->totvert;
+ bmdm->dm.numEdgeData = bm->totedge;
+ bmdm->dm.numFaceData = em->tottri;
+ bmdm->dm.numLoopData = bm->totloop;
+ bmdm->dm.numPolyData = bm->totface;
+
+ bmdm->dm.getMinMax = bmDM_getMinMax;
+
+ bmdm->dm.getVertDataLayout = bmDm_getVertDataLayout;
+ bmdm->dm.getEdgeDataLayout = bmDm_getEdgeDataLayout;
+ bmdm->dm.getTessFaceDataLayout = bmDm_getTessFaceDataLayout;
+ bmdm->dm.getLoopDataLayout = bmDm_getLoopDataLayout;
+ bmdm->dm.getFaceDataLayout = bmDm_getFaceDataLayout;
+
+ bmdm->dm.getNumVerts = bmDM_getNumVerts;
+ bmdm->dm.getNumEdges = bmDM_getNumEdges;
+ bmdm->dm.getNumTessFaces = bmDM_getNumTessFaces;
+ bmdm->dm.getNumFaces = bmDM_getNumFaces;
+
+ bmdm->dm.getVert = bmDM_getVert;
+ bmdm->dm.getEdge = bmDM_getEdge;
+ bmdm->dm.getTessFace = bmDM_getTessFace;
+ bmdm->dm.copyVertArray = bmDM_copyVertArray;
+ bmdm->dm.copyEdgeArray = bmDM_copyEdgeArray;
+ bmdm->dm.copyTessFaceArray = bmDM_copyFaceArray;
+ bmdm->dm.getTessFaceDataArray = bmDM_getFaceDataArray;
+
+ bmdm->dm.newFaceIter = bmDM_getFaceIter;
+ bmdm->dm.recalcTesselation = bmDM_recalcTesselation;
+
+ bmdm->dm.foreachMappedVert = bmDM_foreachMappedVert;
+ bmdm->dm.foreachMappedEdge = bmDM_foreachMappedEdge;
+ bmdm->dm.foreachMappedFaceCenter = bmDM_foreachMappedFaceCenter;
+
+ bmdm->dm.drawEdges = bmDM_drawEdges;
+ bmdm->dm.drawMappedEdges = bmDM_drawMappedEdges;
+ bmdm->dm.drawMappedEdgesInterp = bmDM_drawMappedEdgesInterp;
+ bmdm->dm.drawMappedFaces = bmDM_drawMappedFaces;
+ bmdm->dm.drawMappedFacesTex = bmDM_drawMappedFacesTex;
+ bmdm->dm.drawMappedFacesGLSL = bmDM_drawMappedFacesGLSL;
+ bmdm->dm.drawFacesTex = bmDM_drawFacesTex;
+ bmdm->dm.drawFacesGLSL = bmDM_drawFacesGLSL;
+ bmdm->dm.drawUVEdges = bmDM_drawUVEdges;
+
+ bmdm->dm.release = bmDM_release;
+
+ bmdm->vertexCos = vertexCos;
+
+ if(CustomData_has_layer(&bm->vdata, CD_MDEFORMVERT)) {
+ BMIter iter;
+ BMVert *eve;
+ int i;
+
+ DM_add_vert_layer(&bmdm->dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
+
+ eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++)
+ DM_set_vert_data(&bmdm->dm, i, CD_MDEFORMVERT,
+ CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_MDEFORMVERT));
+ }
+
+ if(vertexCos) {
+ BMVert *eve;
+ BMIter iter;
+ int totface = bmdm->tc->tottri;
+ int i;
+
+ eve=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++)
+ BMINDEX_SET(eve, i);
+
+ bmdm->vertexNos = MEM_callocN(sizeof(*bmdm->vertexNos)*i, "bmdm_vno");
+ bmdm->faceNos = MEM_mallocN(sizeof(*bmdm->faceNos)*totface, "bmdm_vno");
+
+ for (i=0; i<bmdm->tc->tottri; i++) {
+ BMLoop **l = bmdm->tc->looptris[i];
+ float *v1 = vertexCos[(int) BMINDEX_GET(l[0]->v)];
+ float *v2 = vertexCos[(int) BMINDEX_GET(l[1]->v)];
+ float *v3 = vertexCos[(int) BMINDEX_GET(l[2]->v)];
+ float *no = bmdm->faceNos[i];
+
+ normal_tri_v3( no,v1, v2, v3);
+ add_v3_v3v3(bmdm->vertexNos[BMINDEX_GET(l[0]->v)], bmdm->vertexNos[BMINDEX_GET(l[0]->v)], no);
+ add_v3_v3v3(bmdm->vertexNos[BMINDEX_GET(l[1]->v)], bmdm->vertexNos[BMINDEX_GET(l[1]->v)], no);
+ add_v3_v3v3(bmdm->vertexNos[BMINDEX_GET(l[2]->v)], bmdm->vertexNos[BMINDEX_GET(l[2]->v)], no);
+ }
+
+ eve=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++) {
+ float *no = bmdm->vertexNos[i];
+ /* following Mesh convention; we use vertex coordinate itself
+ * for normal in this case */
+ if (normalize_v3(no)==0.0) {
+ VECCOPY(no, vertexCos[i]);
+ normalize_v3(no);
+ }
+ }
+ }
+
+ //bmdm_recalc_lookups(bmdm);
+
+ return (DerivedMesh*) bmdm;
+}
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index ddfc58b7491..5d8401d7a43 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -576,7 +576,7 @@ int closest_point_on_surface(SurfaceModifierData *surmd, float *co, float *surfa
}
if(surface_vel) {
- MFace *mface = CDDM_get_face(surmd->dm, nearest.index);
+ MFace *mface = CDDM_get_tessface(surmd->dm, nearest.index);
VECCOPY(surface_vel, surmd->v[mface->v1].co);
add_v3_v3(surface_vel, surmd->v[mface->v2].co);
diff --git a/source/blender/blenkernel/intern/exotic.c b/source/blender/blenkernel/intern/exotic.c
index 4a6638ff3a0..4afce1e56c4 100644
--- a/source/blender/blenkernel/intern/exotic.c
+++ b/source/blender/blenkernel/intern/exotic.c
@@ -534,8 +534,8 @@ static void write_vert_stl(Object *ob, MVert *verts, int index, FILE *fpSTL)
static int write_derivedmesh_stl(FILE *fpSTL, Object *ob, DerivedMesh *dm)
{
MVert *mvert = dm->getVertArray(dm);
- MFace *mface = dm->getFaceArray(dm);
- int i, numfacets = 0, totface = dm->getNumFaces(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
+ int i, numfacets = 0, totface = dm->getNumTessFaces(dm);
float zero[3] = {0.0f, 0.0f, 0.0f};
for (i=0; i<totface; i++, mface++) {
diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c
index bb56a5b176a..810c56dbe5d 100644
--- a/source/blender/blenkernel/intern/fluidsim.c
+++ b/source/blender/blenkernel/intern/fluidsim.c
@@ -62,7 +62,6 @@
/* ************************* fluidsim bobj file handling **************************** */
-
//-------------------------------------------------------------------------------
// file handling
//-------------------------------------------------------------------------------
@@ -83,9 +82,9 @@ void initElbeemMesh(struct Scene *scene, struct Object *ob,
//dm = mesh_create_derived_no_deform(ob,NULL);
mvert = dm->getVertArray(dm);
- mface = dm->getFaceArray(dm);
+ mface = dm->getTessFaceArray(dm);
totvert = dm->getNumVerts(dm);
- totface = dm->getNumFaces(dm);
+ totface = dm->getNumTessFaces(dm);
*numVertices = totvert;
verts = MEM_callocN( totvert*3*sizeof(float), "elbeemmesh_vertices");
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index f979973f55d..804c26295bd 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: fmodifier.c 21537 2009-07-11 22:22:53Z gsrb3d $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index bf0427e4fee..05988605b4c 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -261,7 +261,7 @@ static PackedFile *get_builtin_packedfile(void)
void free_ttfont(void)
{
struct TmpFont *tf;
-
+
for(tf= ttfdata.first; tf; tf= tf->next) {
if(tf->pf) freePackedFile(tf->pf); /* NULL when the font file can't be found on disk */
tf->pf= NULL;
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index 6c8b5329711..6c8b5329711 100644..100755
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 3681dc910cd..5c10c14c4e2 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -56,11 +56,13 @@
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_tessmesh.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "RNA_access.h"
+#include "BLI_cellalloc.h"
#define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */
#define KEY_MODE_BPOINT 1
@@ -90,6 +92,20 @@ void free_key(Key *key)
}
+void free_key_nolib(Key *key)
+{
+ KeyBlock *kb;
+
+ while( (kb= key->block.first) ) {
+
+ if(kb->data) MEM_freeN(kb->data);
+
+ BLI_remlink(&key->block, kb);
+ MEM_freeN(kb);
+ }
+
+}
+
/* GS reads the memory pointed at in a specific ordering. There are,
* however two definitions for it. I have jotted them down here, both,
* but I think the first one is actually used. The thing is that
@@ -112,6 +128,8 @@ Key *add_key(ID *id) /* common function */
key->type= KEY_NORMAL;
key->from= id;
+
+ key->uidgen = 1;
// XXX the code here uses some defines which will soon be depreceated...
if( GS(id->name)==ID_ME) {
@@ -170,6 +188,32 @@ Key *copy_key(Key *key)
return keyn;
}
+
+Key *copy_key_nolib(Key *key)
+{
+ Key *keyn;
+ KeyBlock *kbn, *kb;
+
+ if(key==0) return 0;
+
+ keyn= MEM_dupallocN(key);
+
+ BLI_duplicatelist(&keyn->block, &key->block);
+
+ kb= key->block.first;
+ kbn= keyn->block.first;
+ while(kbn) {
+
+ if(kbn->data) kbn->data= MEM_dupallocN(kbn->data);
+ if(kb==key->refkey) keyn->refkey= kbn;
+
+ kbn= kbn->next;
+ kb= kb->next;
+ }
+
+ return keyn;
+}
+
void make_local_key(Key *key)
{
@@ -493,18 +537,21 @@ static char *key_block_get_data(Key *key, KeyBlock *actkb, KeyBlock *kb, char **
edit mode with shape keys blending applied */
if(GS(key->from->name) == ID_ME) {
Mesh *me;
- EditVert *eve;
+ BMVert *eve;
+ BMIter iter;
float (*co)[3];
int a;
me= (Mesh*)key->from;
- if(me->edit_mesh && me->edit_mesh->totvert == kb->totelem) {
+ if(me->edit_btmesh && me->edit_btmesh->bm->totvert == kb->totelem) {
a= 0;
- co= MEM_callocN(sizeof(float)*3*me->edit_mesh->totvert, "key_block_get_data");
+ co= MEM_callocN(sizeof(float)*3*me->edit_btmesh->bm->totvert, "key_block_get_data");
- for(eve=me->edit_mesh->verts.first; eve; eve=eve->next, a++)
+ BM_ITER(eve, &iter, me->edit_btmesh->bm, BM_VERTS_OF_MESH, NULL) {
VECCOPY(co[a], eve->co);
+ a++;
+ }
*freedata= (char*)co;
return (char*)co;
@@ -998,8 +1045,9 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
static float *get_weights_array(Object *ob, char *vgroup)
{
MDeformVert *dvert= NULL;
- EditMesh *em= NULL;
- EditVert *eve;
+ BMEditMesh *em= NULL;
+ BMIter iter;
+ BMVert *eve;
int totvert= 0, index= 0;
/* no vgroup string set? */
@@ -1011,8 +1059,8 @@ static float *get_weights_array(Object *ob, char *vgroup)
dvert= me->dvert;
totvert= me->totvert;
- if(me->edit_mesh && me->edit_mesh->totvert == totvert)
- em= me->edit_mesh;
+ if(me->edit_btmesh && me->edit_btmesh->bm->totvert == totvert)
+ em= me->edit_btmesh;
}
else if(ob->type==OB_LATTICE) {
Lattice *lt= ob->data;
@@ -1031,8 +1079,9 @@ static float *get_weights_array(Object *ob, char *vgroup)
weights= MEM_callocN(totvert*sizeof(float), "weights");
if(em) {
- for(i=0, eve=em->verts.first; eve; eve=eve->next, i++) {
- dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+ eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++) {
+ dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
if(dvert) {
for(j=0; j<dvert->totweight; j++) {
@@ -1459,7 +1508,8 @@ KeyBlock *add_keyblock(Key *key, const char *name)
// XXX this is old anim system stuff? (i.e. the 'index' of the shapekey)
kb->adrcode= tot-1;
-
+ kb->uid = key->uidgen++;
+
key->totkey++;
if(key->totkey==1) key->refkey= kb;
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index b0f90ef8042..70eba3903d0 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -40,6 +40,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_cellalloc.h"
#include "BLI_utildefines.h"
#include "DNA_mesh_types.h"
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 05d1e5841dc..cb96f549829 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -728,7 +728,7 @@ void free_libblock(ListBase *lb, void *idv)
free_object((Object *)id);
break;
case ID_ME:
- free_mesh((Mesh *)id);
+ free_mesh((Mesh *)id, 1);
break;
case ID_CU:
free_curve((Curve *)id);
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 3c56cb4663b..f6679315606 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -42,15 +42,18 @@
#include "DNA_key_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_ipo_types.h"
+#include "DNA_customdata_types.h"
#include "BLI_blenlib.h"
#include "BLI_editVert.h"
#include "BLI_math.h"
#include "BLI_edgehash.h"
#include "BLI_utildefines.h"
+#include "BLI_scanfill.h"
#include "BKE_animsys.h"
#include "BKE_main.h"
+#include "BKE_customdata.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
@@ -64,20 +67,316 @@
#include "BKE_curve.h"
/* -- */
#include "BKE_object.h"
+#include "BKE_tessmesh.h"
+#include "BLI_edgehash.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+#include "BLI_math.h"
+#include "BLI_cellalloc.h"
+#include "BLI_array.h"
+#include "BLI_edgehash.h"
+
+#include "bmesh.h"
+
+enum {
+ MESHCMP_DVERT_WEIGHTMISMATCH = 1,
+ MESHCMP_DVERT_GROUPMISMATCH,
+ MESHCMP_DVERT_TOTGROUPMISMATCH,
+ MESHCMP_LOOPCOLMISMATCH,
+ MESHCMP_LOOPUVMISMATCH,
+ MESHCMP_LOOPMISMATCH,
+ MESHCMP_POLYVERTMISMATCH,
+ MESHCMP_POLYMISMATCH,
+ MESHCMP_EDGEUNKNOWN,
+ MESHCMP_VERTCOMISMATCH,
+ MESHCMP_CDLAYERS_MISMATCH,
+};
+
+static char *cmpcode_to_str(int code)
+{
+ switch (code) {
+ case MESHCMP_DVERT_WEIGHTMISMATCH:
+ return "Vertex Weight Mismatch";
+ case MESHCMP_DVERT_GROUPMISMATCH:
+ return "Vertex Group Mismatch";
+ case MESHCMP_DVERT_TOTGROUPMISMATCH:
+ return "Vertex Doesn't Belong To Same Number Of Groups";
+ case MESHCMP_LOOPCOLMISMATCH:
+ return "Vertex Color Mismatch";
+ case MESHCMP_LOOPUVMISMATCH:
+ return "UV Mismatch";
+ case MESHCMP_LOOPMISMATCH:
+ return "Loop Mismatch";
+ case MESHCMP_POLYVERTMISMATCH:
+ return "Loop Vert Mismatch In Poly Test";
+ case MESHCMP_POLYMISMATCH:
+ return "Loop Vert Mismatch";
+ case MESHCMP_EDGEUNKNOWN:
+ return "Edge Mismatch";
+ case MESHCMP_VERTCOMISMATCH:
+ return "Vertex Coordinate Mismatch";
+ case MESHCMP_CDLAYERS_MISMATCH:
+ "CustomData Layer Count Mismatch";
+ default:
+ return "Mesh Comparison Code Unknown";
+ }
+}
+
+/*thresh is threshold for comparing vertices, uvs, vertex colors,
+ weights, etc.*/
+int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2, float thresh)
+{
+ CustomDataLayer *l1, *l2;
+ int i, i1=0, i2=0, tot, j;
+
+ for (i=0; i<c1->totlayer; i++) {
+ if (ELEM7(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY,
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ i1++;
+ }
+
+ for (i=0; i<c2->totlayer; i++) {
+ if (ELEM7(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY,
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ i2++;
+ }
+
+ if (i1 != i2)
+ return MESHCMP_CDLAYERS_MISMATCH;
+
+ l1 = c1->layers; l2 = c2->layers;
+ tot = i1;
+ i1 = 0; i2 = 0;
+ for (i=0; i < tot; i++) {
+ while (i1 < c1->totlayer && !ELEM7(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ i1++, l1++;
+
+ while (i2 < c2->totlayer && !ELEM7(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ i2++, l2++;
+
+ if (l1->type == CD_MVERT) {
+ MVert *v1 = l1->data;
+ MVert *v2 = l2->data;
+ int vtot = m1->totvert;
+
+ for (j=0; j<vtot; j++, v1++, v2++) {
+ if (len_v3v3(v1->co, v2->co) > thresh)
+ return MESHCMP_VERTCOMISMATCH;
+ /*I don't care about normals, let's just do coodinates*/
+ }
+ }
+
+ /*we're order-agnostic for edges here*/
+ if (l1->type == CD_MEDGE) {
+ MEdge *e1 = l1->data;
+ MEdge *e2 = l2->data;
+ EdgeHash *eh = BLI_edgehash_new();
+ int etot = m1->totedge;
+
+ for (j=0; j<etot; j++, e1++) {
+ BLI_edgehash_insert(eh, e1->v1, e1->v2, e1);
+ }
+
+ for (j=0; j<etot; j++, e2++) {
+ if (!BLI_edgehash_lookup(eh, e2->v1, e2->v2))
+ return MESHCMP_EDGEUNKNOWN;
+ }
+ BLI_edgehash_free(eh, NULL);
+ }
+
+ if (l1->type == CD_MPOLY) {
+ MPoly *p1 = l1->data;
+ MPoly *p2 = l2->data;
+ int ptot = m1->totpoly;
+
+ for (j=0; j<ptot; j++, p1++, p2++) {
+ MLoop *lp1, *lp2;
+ int k;
+
+ if (p1->totloop != p2->totloop)
+ return MESHCMP_POLYMISMATCH;
+
+ lp1 = m1->mloop + p1->loopstart;
+ lp2 = m2->mloop + p2->loopstart;
+
+ for (k=0; k<p1->totloop; k++, lp1++, lp2++) {
+ if (lp1->v != lp2->v)
+ return MESHCMP_POLYVERTMISMATCH;
+ }
+ }
+ }
+ if (l1->type == CD_MLOOP) {
+ MLoop *lp1 = l1->data;
+ MLoop *lp2 = l2->data;
+ int ltot = m1->totloop;
+
+ for (j=0; j<ltot; j++, lp1++, lp2++) {
+ if (lp1->v != lp2->v)
+ return MESHCMP_LOOPMISMATCH;
+ }
+ }
+ if (l1->type == CD_MLOOPUV) {
+ MLoopUV *lp1 = l1->data;
+ MLoopUV *lp2 = l2->data;
+ int ltot = m1->totloop;
+
+ for (j=0; j<ltot; j++, lp1++, lp2++) {
+ if (len_v2v2(lp1->uv, lp2->uv) > thresh)
+ return MESHCMP_LOOPUVMISMATCH;
+ }
+ }
+
+ if (l1->type == CD_MLOOPCOL) {
+ MLoopCol *lp1 = l1->data;
+ MLoopCol *lp2 = l2->data;
+ int ltot = m1->totloop;
+
+ for (j=0; j<ltot; j++, lp1++, lp2++) {
+ if (ABS(lp1->r - lp2->r) > thresh ||
+ ABS(lp1->g - lp2->g) > thresh ||
+ ABS(lp1->b - lp2->b) > thresh ||
+ ABS(lp1->a - lp2->a) > thresh)
+ {
+ return MESHCMP_LOOPCOLMISMATCH;
+ }
+ }
+ }
+ if (l1->type == CD_MDEFORMVERT) {
+ MDeformVert *dv1 = l1->data;
+ MDeformVert *dv2 = l2->data;
+ int dvtot = m1->totvert;
+
+ for (j=0; j<dvtot; j++, dv1++, dv2++) {
+ int k;
+ MDeformWeight *dw1 = dv1->dw, *dw2=dv2->dw;
+
+ if (dv1->totweight != dv2->totweight)
+ return MESHCMP_DVERT_TOTGROUPMISMATCH;
+
+ for (k=0; k<dv1->totweight; k++, dw1++, dw2++) {
+ if (dw1->def_nr != dw2->def_nr)
+ return MESHCMP_DVERT_GROUPMISMATCH;
+ if (ABS(dw1->weight - dw2->weight) > thresh)
+ return MESHCMP_DVERT_WEIGHTMISMATCH;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
-EditMesh *BKE_mesh_get_editmesh(Mesh *me)
+/*used for testing. returns an error string the two meshes don't match*/
+char *mesh_cmp(Mesh *me1, Mesh *me2, float thresh)
{
- return me->edit_mesh;
+ int c;
+
+ if (!me1 || !me2)
+ return "Requires two input meshes";
+
+ if (me1->totvert != me2->totvert)
+ return "Number of verts don't match";
+
+ if (me1->totedge != me2->totedge)
+ return "Number of edges don't match";
+
+ if (me1->totpoly != me2->totpoly)
+ return "Number of faces don't match";
+
+ if (me1->totloop !=me2->totloop)
+ return "Number of loops don't match";
+
+ if ((c = customdata_compare(&me1->vdata, &me2->vdata, me1, me2, thresh)))
+ return cmpcode_to_str(c);
+
+ if ((c = customdata_compare(&me1->edata, &me2->edata, me1, me2, thresh)))
+ return cmpcode_to_str(c);
+
+ if ((c = customdata_compare(&me1->ldata, &me2->ldata, me1, me2, thresh)))
+ return cmpcode_to_str(c);
+
+ if ((c = customdata_compare(&me1->pdata, &me2->pdata, me1, me2, thresh)))
+ return cmpcode_to_str(c);
+
+ return NULL;
}
-void BKE_mesh_end_editmesh(Mesh *UNUSED(me), EditMesh *UNUSED(em))
+static void mesh_ensure_tesselation_customdata(Mesh *me)
{
+ int tottex, totcol;
+
+ tottex = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ totcol = CustomData_number_of_layers(&me->fdata, CD_MCOL);
+
+ if (tottex != CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY) ||
+ totcol != CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL))
+ {
+ CustomData_free(&me->fdata, me->totface);
+
+ me->mface = NULL;
+ me->mtface = NULL;
+ me->mcol = NULL;
+ me->totface = 0;
+
+ memset(&me->fdata, 0, sizeof(&me->fdata));
+
+ CustomData_from_bmeshpoly(&me->fdata, &me->pdata, &me->ldata, me->totface);
+ printf("Warning! Tesselation uvs or vcol data got out of sync, had to reset!\n");
+ }
}
+/*this ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or
+ mloopcol and mcol) have the same relative active/render/clone/mask indices.*/
+void mesh_update_linked_customdata(Mesh *me)
+{
+ int act;
+
+ if (me->edit_btmesh)
+ BMEdit_UpdateLinkedCustomData(me->edit_btmesh);
+
+ mesh_ensure_tesselation_customdata(me);
+
+ if (CustomData_has_layer(&me->pdata, CD_MTEXPOLY)) {
+ act = CustomData_get_active_layer(&me->pdata, CD_MTEXPOLY);
+ CustomData_set_layer_active(&me->ldata, CD_MLOOPUV, act);
+ CustomData_set_layer_active(&me->fdata, CD_MTFACE, act);
+
+ act = CustomData_get_render_layer(&me->pdata, CD_MTEXPOLY);
+ CustomData_set_layer_render(&me->ldata, CD_MLOOPUV, act);
+ CustomData_set_layer_render(&me->fdata, CD_MTFACE, act);
+
+ act = CustomData_get_clone_layer(&me->pdata, CD_MTEXPOLY);
+ CustomData_set_layer_clone(&me->ldata, CD_MLOOPUV, act);
+ CustomData_set_layer_clone(&me->fdata, CD_MTFACE, act);
+
+ act = CustomData_get_stencil_layer(&me->pdata, CD_MTEXPOLY);
+ CustomData_set_layer_stencil(&me->ldata, CD_MLOOPUV, act);
+ CustomData_set_layer_stencil(&me->fdata, CD_MTFACE, act);
+ }
+
+ if (CustomData_has_layer(&me->ldata, CD_MLOOPCOL)) {
+ act = CustomData_get_active_layer(&me->ldata, CD_MLOOPCOL);
+ CustomData_set_layer_active(&me->fdata, CD_MCOL, act);
+
+ act = CustomData_get_render_layer(&me->ldata, CD_MLOOPCOL);
+ CustomData_set_layer_render(&me->fdata, CD_MCOL, act);
+
+ act = CustomData_get_clone_layer(&me->ldata, CD_MLOOPCOL);
+ CustomData_set_layer_clone(&me->fdata, CD_MCOL, act);
+
+ act = CustomData_get_stencil_layer(&me->ldata, CD_MLOOPCOL);
+ CustomData_set_layer_stencil(&me->fdata, CD_MCOL, act);
+ }
+}
void mesh_update_customdata_pointers(Mesh *me)
{
+ mesh_update_linked_customdata(me);
+
me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
me->msticky = CustomData_get_layer(&me->vdata, CD_MSTICKY);
@@ -87,6 +386,13 @@ void mesh_update_customdata_pointers(Mesh *me)
me->mface = CustomData_get_layer(&me->fdata, CD_MFACE);
me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL);
me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE);
+
+ me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY);
+ me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP);
+
+ me->mtpoly = CustomData_get_layer(&me->pdata, CD_MTEXPOLY);
+ me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
+ me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
}
/* Note: unlinking is called when me->id.us is 0, question remains how
@@ -117,9 +423,10 @@ void unlink_mesh(Mesh *me)
/* do not free mesh itself */
-void free_mesh(Mesh *me)
+void free_mesh(Mesh *me, int unlink)
{
- unlink_mesh(me);
+ if (unlink)
+ unlink_mesh(me);
if(me->pv) {
if(me->pv->vert_map) MEM_freeN(me->pv->vert_map);
@@ -135,7 +442,9 @@ void free_mesh(Mesh *me)
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
CustomData_free(&me->fdata, me->totface);
-
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
+
if(me->adt) {
BKE_free_animdata(&me->id);
me->adt= NULL;
@@ -145,7 +454,7 @@ void free_mesh(Mesh *me)
if(me->bb) MEM_freeN(me->bb);
if(me->mselect) MEM_freeN(me->mselect);
- if(me->edit_mesh) MEM_freeN(me->edit_mesh);
+ if(me->edit_btmesh) MEM_freeN(me->edit_btmesh);
}
void copy_dverts(MDeformVert *dst, MDeformVert *src, int copycount)
@@ -160,7 +469,7 @@ void copy_dverts(MDeformVert *dst, MDeformVert *src, int copycount)
for (i=0; i<copycount; i++){
if (src[i].dw){
- dst[i].dw = MEM_callocN (sizeof(MDeformWeight)*src[i].totweight, "copy_deformWeight");
+ dst[i].dw = BLI_cellalloc_calloc (sizeof(MDeformWeight)*src[i].totweight, "copy_deformWeight");
memcpy (dst[i].dw, src[i].dw, sizeof (MDeformWeight)*src[i].totweight);
}
}
@@ -179,7 +488,7 @@ void free_dverts(MDeformVert *dvert, int totvert)
/* Free any special data from the verts */
for (i=0; i<totvert; i++){
- if (dvert[i].dw) MEM_freeN (dvert[i].dw);
+ if (dvert[i].dw) BLI_cellalloc_free (dvert[i].dw);
}
MEM_freeN (dvert);
}
@@ -204,6 +513,7 @@ Mesh *copy_mesh(Mesh *me)
{
Mesh *men;
MTFace *tface;
+ MTexPoly *txface;
int a, i;
men= copy_libblock(me);
@@ -217,6 +527,8 @@ Mesh *copy_mesh(Mesh *me)
CustomData_copy(&me->vdata, &men->vdata, CD_MASK_MESH, CD_DUPLICATE, men->totvert);
CustomData_copy(&me->edata, &men->edata, CD_MASK_MESH, CD_DUPLICATE, men->totedge);
CustomData_copy(&me->fdata, &men->fdata, CD_MASK_MESH, CD_DUPLICATE, men->totface);
+ CustomData_copy(&me->ldata, &men->ldata, CD_MASK_MESH, CD_DUPLICATE, men->totloop);
+ CustomData_copy(&me->pdata, &men->pdata, CD_MASK_MESH, CD_DUPLICATE, men->totpoly);
mesh_update_customdata_pointers(men);
/* ensure indirect linked data becomes lib-extern */
@@ -229,7 +541,17 @@ Mesh *copy_mesh(Mesh *me)
id_lib_extern((ID*)tface->tpage);
}
}
-
+
+ for(i=0; i<me->pdata.totlayer; i++) {
+ if(me->pdata.layers[i].type == CD_MTEXPOLY) {
+ txface= (MTexPoly*)me->pdata.layers[i].data;
+
+ for(a=0; a<me->totpoly; a++, txface++)
+ if(txface->tpage)
+ id_lib_extern((ID*)txface->tpage);
+ }
+ }
+
men->mselect= NULL;
men->bb= MEM_dupallocN(men->bb);
@@ -240,12 +562,43 @@ Mesh *copy_mesh(Mesh *me)
return men;
}
+BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob)
+{
+ BMesh *bm;
+ int allocsize[4] = {512,512,2048,512};
+
+ bm = BM_Make_Mesh(allocsize);
+
+ BMO_CallOpf(bm, "mesh_to_bmesh mesh=%p object=%p", me, ob);
+
+ return bm;
+}
+
void make_local_tface(Mesh *me)
{
MTFace *tface;
+ MTexPoly *txface;
Image *ima;
int a, i;
+ for(i=0; i<me->pdata.totlayer; i++) {
+ if(me->pdata.layers[i].type == CD_MTEXPOLY) {
+ txface= (MTexPoly*)me->fdata.layers[i].data;
+
+ for(a=0; a<me->totpoly; a++, txface++) {
+ /* special case: ima always local immediately */
+ if(txface->tpage) {
+ ima= txface->tpage;
+ if(ima->id.lib) {
+ ima->id.lib= 0;
+ ima->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)ima, 0);
+ }
+ }
+ }
+ }
+ }
+
for(i=0; i<me->fdata.totlayer; i++) {
if(me->fdata.layers[i].type == CD_MTFACE) {
tface= (MTFace*)me->fdata.layers[i].data;
@@ -263,6 +616,7 @@ void make_local_tface(Mesh *me)
}
}
}
+
}
void make_local_mesh(Mesh *me)
@@ -1076,10 +1430,10 @@ void mesh_to_curve(Scene *scene, Object *ob)
MVert *mverts= dm->getVertArray(dm);
MEdge *med, *medge= dm->getEdgeArray(dm);
- MFace *mf, *mface= dm->getFaceArray(dm);
+ MFace *mf, *mface= dm->getTessFaceArray(dm);
int totedge = dm->getNumEdges(dm);
- int totface = dm->getNumFaces(dm);
+ int totface = dm->getNumTessFaces(dm);
int totedges = 0;
int i, needsFree = 0;
@@ -1536,6 +1890,285 @@ void mesh_pmv_off(Mesh *me)
}
}
+static void mesh_loops_to_corners(CustomData *fdata, CustomData *ldata,
+ CustomData *pdata, int lindex[4], int findex,
+ int polyindex, int numTex, int numCol, int tot)
+{
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ int i, j, hasWCol = CustomData_has_layer(ldata, CD_WEIGHT_MLOOPCOL);
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
+ texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i);
+
+ texface->tpage = texpoly->tpage;
+ texface->flag = texpoly->flag;
+ texface->transp = texpoly->transp;
+ texface->mode = texpoly->mode;
+ texface->tile = texpoly->tile;
+ texface->unwrap = texpoly->unwrap;
+
+ for (j=0; j<tot; j++) {
+ mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, lindex[j], i);
+ texface->uv[j][0] = mloopuv->uv[0];
+ texface->uv[j][1] = mloopuv->uv[1];
+ }
+ }
+
+ for(i=0; i < numCol; i++){
+ mcol = CustomData_get_n(fdata, CD_MCOL, findex, i);
+
+ for (j=0; j<tot; j++) {
+ mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, lindex[j], i);
+ mcol[j].r = mloopcol->r;
+ mcol[j].g = mloopcol->g;
+ mcol[j].b = mloopcol->b;
+ mcol[j].a = mloopcol->a;
+ }
+ }
+
+ if (hasWCol) {
+ mcol = CustomData_get(fdata, findex, CD_WEIGHT_MCOL);
+
+ for (j=0; j<tot; j++) {
+ mloopcol = CustomData_get(ldata, lindex[j], CD_WEIGHT_MLOOPCOL);
+ mcol[j].r = mloopcol->r;
+ mcol[j].g = mloopcol->g;
+ mcol[j].b = mloopcol->b;
+ mcol[j].a = mloopcol->a;
+ }
+ }
+}
+
+/*
+ this function recreates a tesselation.
+ returns number of tesselation faces.
+
+ use_poly_origindex sets whether or not the tesselation faces' origindex
+ layer should point to original poly indices or real poly indices.
+
+ use_face_origindex sets the tesselation faces' origindex layer
+ to point to the tesselation faces themselves, not the polys.
+
+ if both of the above are 0, it'll use the indices of the mpolys of the MPoly
+ data in pdata, and ignore the origindex layer altogether.
+ */
+int mesh_recalcTesselation(CustomData *fdata,
+ CustomData *ldata, CustomData *pdata,
+ MVert *mvert, int totface, int totloop,
+ int totpoly, int use_poly_origindex,
+ int use_face_origindex)
+{
+ MPoly *mp, *mpoly;
+ MLoop *ml, *mloop;
+ MFace *mf = NULL, *mface;
+ BLI_array_declare(mf);
+ EditVert *v, *lastv, *firstv;
+ EditFace *f;
+ BLI_array_declare(origIndex);
+ int i, j, k, lindex[4], *origIndex = NULL, *polyorigIndex;
+ int numTex, numCol;
+
+ mpoly = CustomData_get_layer(pdata, CD_MPOLY);
+ mloop = CustomData_get_layer(ldata, CD_MLOOP);
+
+ numTex = CustomData_number_of_layers(ldata, CD_MLOOPUV);
+ numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
+
+ k = 0;
+ mp = mpoly;
+ polyorigIndex = use_poly_origindex? CustomData_get_layer(pdata, CD_ORIGINDEX) : NULL;
+ for (i=0; i<totpoly; i++, mp++) {
+ if (mp->totloop > 2) {
+ ml = mloop + mp->loopstart;
+
+ firstv = NULL;
+ lastv = NULL;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ v = BLI_addfillvert(mvert[ml->v].co);
+ if (polyorigIndex && use_poly_origindex)
+ v->tmp.l = polyorigIndex[i];
+ else
+ v->tmp.l = i;
+
+ v->keyindex = mp->loopstart + j;
+
+ if (lastv)
+ BLI_addfilledge(lastv, v);
+
+ if (!firstv)
+ firstv = v;
+ lastv = v;
+ }
+ BLI_addfilledge(lastv, firstv);
+
+ BLI_edgefill(0);
+ for (f=fillfacebase.first; f; f=f->next) {
+ BLI_array_growone(mf);
+ BLI_array_growone(origIndex);
+
+ /*these are loop indices, they'll be transformed
+ into vert indices later.*/
+ mf[k].v1 = f->v1->keyindex;
+ mf[k].v2 = f->v2->keyindex;
+ mf[k].v3 = f->v3->keyindex;
+
+ /*put poly index in mf->v4*/
+ mf[k].v4 = f->v1->tmp.l;
+
+ mf[k].mat_nr = mp->mat_nr;
+ mf[k].flag = mp->flag;
+ origIndex[k] = use_face_origindex ? k : f->v1->tmp.l;
+
+ k++;
+ }
+
+ BLI_end_edgefill();
+ }
+ }
+
+ CustomData_free(fdata, totface);
+ memset(fdata, 0, sizeof(CustomData));
+ totface = k;
+
+ CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mf, totface);
+ CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, origIndex, totface);
+ CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
+
+ mface = mf;
+ for (i=0; i<totface; i++, mf++) {
+ /*sort loop indices to ensure winding is correct*/
+ if (mf->v1 > mf->v2) SWAP(int, mf->v1, mf->v2);
+ if (mf->v2 > mf->v3) SWAP(int, mf->v2, mf->v3);
+ if (mf->v1 > mf->v2) SWAP(int, mf->v1, mf->v2);
+
+ if (mf->v1 > mf->v2) SWAP(int, mf->v1, mf->v2);
+ if (mf->v2 > mf->v3) SWAP(int, mf->v2, mf->v3);
+ if (mf->v1 > mf->v2) SWAP(int, mf->v1, mf->v2);
+
+ lindex[0] = mf->v1;
+ lindex[1] = mf->v2;
+ lindex[2] = mf->v3;
+
+ /*transform loop indices to vert indices*/
+ mf->v1 = mloop[mf->v1].v;
+ mf->v2 = mloop[mf->v2].v;
+ mf->v3 = mloop[mf->v3].v;
+
+ mesh_loops_to_corners(fdata, ldata, pdata,
+ lindex, i, mf->v4, numTex, numCol, 3);
+
+ mf->v4 = 0;
+ }
+
+ return totface;
+}
+
+/*
+ * COMPUTE POLY NORMAL
+ *
+ * Computes the normal of a planar
+ * polygon See Graphics Gems for
+ * computing newell normal.
+ *
+*/
+static void mesh_calc_ngon_normal(MPoly *mpoly, MLoop *loopstart,
+ MVert *mvert, float *normal)
+{
+
+ MVert *v1, *v2, *v3;
+ double u[3], v[3], w[3];
+ double n[3] = {0.0, 0.0, 0.0}, l;
+ int i, s=0;
+
+ for(i = 0; i < mpoly->totloop; i++){
+ v1 = mvert + loopstart[i].v;
+ v2 = mvert + loopstart[(i+1)%mpoly->totloop].v;
+ v3 = mvert + loopstart[(i+2)%mpoly->totloop].v;
+
+ VECCOPY(u, v1->co);
+ VECCOPY(v, v2->co);
+ VECCOPY(w, v3->co);
+
+ /*this fixes some weird numerical error*/
+ if (i==0) {
+ u[0] += 0.0001f;
+ u[1] += 0.0001f;
+ u[2] += 0.0001f;
+ }
+
+ /* newell's method
+
+ so thats?:
+ (a[1] - b[1]) * (a[2] + b[2]);
+ a[1]*b[2] - b[1]*a[2] - b[1]*b[2] + a[1]*a[2]
+
+ odd. half of that is the cross product. . .what's the
+ other half?
+
+ also could be like a[1]*(b[2] + a[2]) - b[1]*(a[2] - b[2])
+ */
+
+ n[0] += (u[1] - v[1]) * (u[2] + v[2]);
+ n[1] += (u[2] - v[2]) * (u[0] + v[0]);
+ n[2] += (u[0] - v[0]) * (u[1] + v[1]);
+ }
+
+ l = n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
+ l = sqrt(l);
+
+ if (l == 0.0) {
+ normal[0] = 0.0f;
+ normal[1] = 0.0f;
+ normal[2] = 1.0f;
+
+ return;
+ } else l = 1.0f / l;
+
+ n[0] *= l;
+ n[1] *= l;
+ n[2] *= l;
+
+ normal[0] = (float) n[0];
+ normal[1] = (float) n[1];
+ normal[2] = (float) n[2];
+
+}
+
+void mesh_calc_poly_normal(MPoly *mpoly, MLoop *loopstart,
+ MVert *mvarray, float *no)
+{
+ if(mpoly->totloop > 4) {
+ mesh_calc_ngon_normal(mpoly, loopstart, mvarray, no);
+ }
+ else if(mpoly->totloop == 3){
+ MVert *v1, *v2, *v3;
+
+ v1 = mvarray + (loopstart++)->v;
+ v2 = mvarray + (loopstart++)->v;
+ v3 = mvarray + loopstart->v;
+ normal_tri_v3( no,v1->co, v2->co, v3->co);
+ }
+ else if(mpoly->totloop == 4){
+ MVert *v1, *v2, *v3, *v4;
+
+ v1 = mvarray + (loopstart++)->v;
+ v2 = mvarray + (loopstart++)->v;
+ v3 = mvarray + (loopstart++)->v;
+ v4 = mvarray + loopstart->v;
+ normal_quad_v3( no,v1->co, v2->co, v3->co, v4->co);
+ }
+ else{ /*horrible, two sided face!*/
+ no[0] = 0.0;
+ no[1] = 0.0;
+ no[2] = 1.0;
+ }
+}
+
/* basic vertex data functions */
int minmax_mesh(Mesh *me, float min[3], float max[3])
{
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 8b0b7a041dc..0821b4188fe 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -308,7 +308,7 @@ int BKE_mesh_validate(Mesh *me, int do_verbose)
int BKE_mesh_validate_dm(DerivedMesh *dm)
{
- return BKE_mesh_validate_arrays(NULL, dm->getVertArray(dm), dm->getNumVerts(dm), dm->getEdgeArray(dm), dm->getNumEdges(dm), dm->getFaceArray(dm), dm->getNumFaces(dm), TRUE, FALSE);
+ return BKE_mesh_validate_arrays(NULL, dm->getVertArray(dm), dm->getNumVerts(dm), dm->getEdgeArray(dm), dm->getNumEdges(dm), dm->getTessFaceArray(dm), dm->getNumTessFaces(dm), TRUE, FALSE);
}
void BKE_mesh_calc_edges(Mesh *mesh, int update)
diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c
new file mode 100644
index 00000000000..8b437635b2a
--- /dev/null
+++ b/source/blender/blenkernel/intern/modifiers_bmesh.c
@@ -0,0 +1,226 @@
+/*
+* $Id: modifier_bmesh.c 20831 2009-06-12 14:02:37Z joeedh $
+*
+* ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* The Original Code is Copyright (C) 2005 by the Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Joseph Eagar
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+* Modifier stack implementation.
+*
+* BKE_modifier.h contains the function prototypes for this file.
+*
+*/
+
+#include "string.h"
+#include "stdarg.h"
+#include "math.h"
+#include "float.h"
+#include "ctype.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_kdopbvh.h"
+#include "BLI_kdtree.h"
+#include "BLI_linklist.h"
+#include "BLI_rand.h"
+#include "BLI_edgehash.h"
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+#include "BLI_cellalloc.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_cloth_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_particle_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+
+#include "BLI_editVert.h"
+#include "BLI_array.h"
+
+#include "BKE_main.h"
+#include "BKE_anim.h"
+#include "BKE_bmesh.h"
+// XXX #include "BKE_booleanops.h"
+#include "BKE_cloth.h"
+#include "BKE_collision.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_curve.h"
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_displist.h"
+#include "BKE_fluidsim.h"
+#include "BKE_global.h"
+#include "BKE_multires.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+#include "BKE_softbody.h"
+#include "BKE_subsurf.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
+
+#include "depsgraph_private.h"
+#include "BKE_deform.h"
+#include "BKE_shrinkwrap.h"
+
+#include "CCGSubSurf.h"
+#include "RE_shader_ext.h"
+#include "LOD_decimation.h"
+
+/*converts a cddm to a BMEditMesh. if existing is non-NULL, the
+ new geometry will be put in there.*/
+BMEditMesh *CDDM_To_BMesh(DerivedMesh *dm, BMEditMesh *existing)
+{
+ int allocsize[4] = {512, 512, 2048, 512};
+ BMesh *bm, bmold; /*bmold is for storing old customdata layout*/
+ BMEditMesh *em = existing;
+ MVert *mv, *mvert;
+ MEdge *me, *medge;
+ DMFaceIter *dfiter;
+ DMLoopIter *dliter;
+ BMVert *v, **vtable, **verts=NULL;
+ BMEdge *e, **etable, **edges=NULL;
+ BMFace *f;
+ BMIter liter;
+ BLI_array_declare(verts);
+ BLI_array_declare(edges);
+ int numTex, numCol;
+ int i, j, k, totvert, totedge, totface;
+
+ if (em) bm = em->bm;
+ else bm = BM_Make_Mesh(allocsize);
+
+ bmold = *bm;
+
+ /*merge custom data layout*/
+ CustomData_bmesh_merge(&dm->vertData, &bm->vdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_VERT);
+ CustomData_bmesh_merge(&dm->edgeData, &bm->edata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_EDGE);
+ CustomData_bmesh_merge(&dm->loopData, &bm->ldata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_LOOP);
+ CustomData_bmesh_merge(&dm->polyData, &bm->pdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_FACE);
+
+ /*needed later*/
+ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
+
+ totvert = dm->getNumVerts(dm);
+ totedge = dm->getNumEdges(dm);
+ totface = dm->getNumFaces(dm);
+
+ vtable = MEM_callocN(sizeof(void**)*totvert, "vert table in BMDM_Copy");
+ etable = MEM_callocN(sizeof(void**)*totedge, "edge table in BMDM_Copy");
+
+ /*do verts*/
+ mv = mvert = dm->dupVertArray(dm);
+ for (i=0; i<totvert; i++, mv++) {
+ v = BM_Make_Vert(bm, mv->co, NULL);
+
+ VECCOPY(v->no, mv->no);
+ v->head.flag = MEFlags_To_BMFlags(mv->flag, BM_VERT);
+
+ CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v->head.data);
+ vtable[i] = v;
+ }
+ MEM_freeN(mvert);
+
+ /*do edges*/
+ me = medge = dm->dupEdgeArray(dm);
+ for (i=0; i<totedge; i++, me++) {
+ e = BM_Make_Edge(bm, vtable[me->v1], vtable[me->v2], NULL, 0);
+
+ e->head.flag = MEFlags_To_BMFlags(me->flag, BM_EDGE);
+
+ CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->head.data);
+ etable[i] = e;
+ }
+ MEM_freeN(medge);
+
+ /*do faces*/
+ k = 0;
+ dfiter = dm->newFaceIter(dm);
+ for (; !dfiter->done; dfiter->step(dfiter)) {
+ BMLoop *l;
+
+ BLI_array_empty(verts);
+ BLI_array_empty(edges);
+
+ dliter = dfiter->getLoopsIter(dfiter);
+ for (j=0; !dliter->done; dliter->step(dliter), j++) {
+ BLI_array_growone(verts);
+ BLI_array_growone(edges);
+
+ verts[j] = vtable[dliter->vindex];
+ edges[j] = etable[dliter->eindex];
+ }
+
+ if (j < 2)
+ break;
+
+ f = BM_Make_Ngon(bm, verts[0], verts[1], edges, dfiter->len, 0);
+
+ if (!f)
+ continue;
+
+ f->head.flag = MEFlags_To_BMFlags(dfiter->flags, BM_FACE);
+ f->mat_nr = dfiter->mat_nr;
+
+ dliter = dfiter->getLoopsIter(dfiter);
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (j=0; l; l=BMIter_Step(&liter)) {
+ CustomData_to_bmesh_block(&dm->loopData, &bm->ldata, k, &l->head.data);
+ k += 1;
+ }
+
+ CustomData_to_bmesh_block(&dm->polyData, &bm->pdata,
+ dfiter->index, &f->head.data);
+ }
+ dfiter->free(dfiter);
+
+ MEM_freeN(vtable);
+ MEM_freeN(etable);
+
+ BLI_array_free(verts);
+ BLI_array_free(edges);
+
+ if (!em) em = BMEdit_Create(bm);
+ else BMEdit_RecalcTesselation(em);
+
+ return em;
+}
+
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 29726ccbc99..f2c5a9cbf37 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -47,6 +47,7 @@
#include "BKE_paint.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
+#include "BKE_tessmesh.h"
#include "BKE_object.h"
@@ -72,7 +73,7 @@ DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob
dm = mti->applyModifier(md, ob, tdm, 0, 1);
if (dm == tdm) {
- dm = CDDM_copy(tdm);
+ dm = CDDM_copy(tdm, 0);
}
return dm;
@@ -231,7 +232,7 @@ int multiresModifier_reshapeFromDeformMod(Scene *scene, MultiresModifierData *mm
dm->getVertCos(dm, deformedVerts);
mti->deformVerts(md, ob, dm, deformedVerts, numVerts, 0, 0);
- ndm= CDDM_copy(dm);
+ ndm= CDDM_copy(dm, 0);
CDDM_apply_vert_coords(ndm, deformedVerts);
MEM_freeN(deformedVerts);
@@ -250,26 +251,31 @@ int multiresModifier_reshapeFromDeformMod(Scene *scene, MultiresModifierData *mm
static int get_levels_from_disps(Object *ob)
{
Mesh *me = ob->data;
- MDisps *mdisp;
- int i, totlvl= 0;
+ MDisps *mdisp, *md;
+ int i, j, totlvl= 0;
mdisp = CustomData_get_layer(&me->fdata, CD_MDISPS);
- for(i = 0; i < me->totface; ++i, ++mdisp) {
- int S = me->mface[i].v4 ? 4 : 3;
-
- if(mdisp->totdisp == 0) continue;
-
- while(1) {
- int side = (1 << (totlvl-1)) + 1;
- int lvl_totdisp = side*side*S;
- if(mdisp->totdisp == lvl_totdisp)
- break;
- else if(mdisp->totdisp < lvl_totdisp)
- --totlvl;
- else
- ++totlvl;
-
+ for(i = 0; i < me->totpoly; ++i) {
+ int S = me->mpoly[i].totloop;
+
+ md = mdisp + me->mpoly[i].loopstart;
+ for (j=0; j<me->mpoly[i].totloop; j++, md++) {
+ if(md->totdisp == 0) continue;
+
+ while(1) {
+ int side = (1 << (totlvl-1)) + 1;
+ int lvl_totdisp = side*side*S;
+ if(md->totdisp == lvl_totdisp)
+ break;
+ else if(md->totdisp < lvl_totdisp)
+ --totlvl;
+ else
+ ++totlvl;
+
+ }
+
+ break;
}
}
@@ -282,10 +288,10 @@ void multiresModifier_set_levels_from_disps(MultiresModifierData *mmd, Object *o
Mesh *me = ob->data;
MDisps *mdisp;
- if(me->edit_mesh)
- mdisp = CustomData_get_layer(&me->edit_mesh->fdata, CD_MDISPS);
+ if(me->edit_btmesh)
+ mdisp = CustomData_get_layer(&me->edit_btmesh->bm->ldata, CD_MDISPS);
else
- mdisp = CustomData_get_layer(&me->fdata, CD_MDISPS);
+ mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS);
if(mdisp) {
mmd->totlvl = get_levels_from_disps(ob);
@@ -297,15 +303,12 @@ void multiresModifier_set_levels_from_disps(MultiresModifierData *mmd, Object *o
static void multires_set_tot_mdisps(Mesh *me, int lvl)
{
- MDisps *mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS);
+ MDisps *mdisps= CustomData_get_layer(&me->ldata, CD_MDISPS);
int i;
if(mdisps) {
- for(i = 0; i < me->totface; i++) {
- if(mdisps[i].totdisp == 0) {
- int nvert = (me->mface[i].v4)? 4: 3;
- mdisps[i].totdisp = multires_grid_tot[lvl]*nvert;
- }
+ for(i = 0; i < me->totloop; i++, mdisps++) {
+ mdisps->totdisp = multires_grid_tot[lvl];
}
}
}
@@ -315,9 +318,8 @@ static void multires_reallocate_mdisps(Mesh *me, MDisps *mdisps, int lvl)
int i;
/* reallocate displacements to be filled in */
- for(i = 0; i < me->totface; ++i) {
- int nvert = (me->mface[i].v4)? 4: 3;
- int totdisp = multires_grid_tot[lvl]*nvert;
+ for(i = 0; i < me->totloop; ++i) {
+ int totdisp = multires_grid_tot[lvl];
float (*disps)[3] = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
if(mdisps[i].disps)
@@ -382,44 +384,43 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
MDisps *mdisps;
multires_set_tot_mdisps(me, mmd->totlvl);
- CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
- mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS);
+ CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
+ mdisps= CustomData_get_layer(&me->ldata, CD_MDISPS);
multires_force_update(ob);
if(mdisps && levels > 0) {
if(lvl > 0) {
+ MLoop *ml = me->mloop;
int nsize = multires_side_tot[lvl];
int hsize = multires_side_tot[mmd->totlvl];
- int i;
+ int i, j, k=0;
- for(i = 0; i < me->totface; ++i) {
- MDisps *mdisp= &mdisps[i];
- float (*disps)[3], (*ndisps)[3], (*hdisps)[3];
- int nvert = (me->mface[i].v4)? 4: 3;
- int totdisp = multires_grid_tot[lvl]*nvert;
- int S;
+ for(i = 0; i < me->totpoly; ++i) {
+ for (j=0; j<me->mpoly[i].totloop; j++, k++) {
+ MDisps *mdisp= &mdisps[k];
+ float (*disps)[3], (*ndisps)[3], (*hdisps)[3];
+ int totdisp = multires_grid_tot[lvl];
- disps = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
+ disps = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
- ndisps = disps;
- hdisps = mdisp->disps;
+ ndisps = disps;
+ hdisps = mdisp->disps;
- for(S = 0; S < nvert; S++) {
multires_copy_grid(ndisps, hdisps, nsize, hsize);
ndisps += nsize*nsize;
hdisps += hsize*hsize;
- }
- MEM_freeN(mdisp->disps);
- mdisp->disps = disps;
- mdisp->totdisp = totdisp;
+ MEM_freeN(mdisp->disps);
+ mdisp->disps = disps;
+ mdisp->totdisp = totdisp;
+ }
}
}
else {
- CustomData_external_remove(&me->fdata, &me->id, CD_MDISPS, me->totface);
- CustomData_free_layer_active(&me->fdata, CD_MDISPS, me->totface);
+ CustomData_external_remove(&me->ldata, &me->id, CD_MDISPS, me->totloop);
+ CustomData_free_layer_active(&me->ldata, CD_MDISPS, me->totloop);
}
}
@@ -607,9 +608,9 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
multires_force_update(ob);
- mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
+ mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
if(!mdisps)
- mdisps = CustomData_add_layer(&me->fdata, CD_MDISPS, CD_DEFAULT, NULL, me->totface);
+ mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_DEFAULT, NULL, me->totloop);
if(mdisps->disps && !updateblock && totlvl > 1) {
/* upsample */
@@ -706,14 +707,14 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*)dm;
DMGridData **gridData, **subGridData;
- MFace *mface = me->mface;
- MDisps *mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
+ MPoly *mpoly = me->mpoly;
+ MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
int *gridOffset;
- int i, /*numGrids,*/ gridSize, dGridSize, dSkip;
+ int i, k, /*numGrids,*/ gridSize, dGridSize, dSkip;
if(!mdisps) {
if(invert)
- mdisps = CustomData_add_layer(&me->fdata, CD_MDISPS, CD_DEFAULT, NULL, me->totface);
+ mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_DEFAULT, NULL, me->totloop);
else
return;
}
@@ -727,23 +728,28 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int
dGridSize = multires_side_tot[totlvl];
dSkip = (dGridSize-1)/(gridSize-1);
- #pragma omp parallel for private(i) if(me->totface*gridSize*gridSize*4 >= CCG_OMP_LIMIT)
- for(i = 0; i < me->totface; ++i) {
- const int numVerts = mface[i].v4 ? 4 : 3;
- MDisps *mdisp = &mdisps[i];
- int S, x, y, gIndex = gridOffset[i];
+ k = 0; /*current loop/mdisp index within the mloop array*/
- /* when adding new faces in edit mode, need to allocate disps */
- if(!mdisp->disps)
- #pragma omp critical
- {
- multires_reallocate_mdisps(me, mdisps, totlvl);
- }
+ #pragma omp parallel for private(i) if(me->totloop*gridSize*gridSize >= CCG_OMP_LIMIT)
- for(S = 0; S < numVerts; ++S, ++gIndex) {
+ for(i = 0; i < me->totpoly; ++i) {
+ const int numVerts = mpoly[i].totloop;
+ int S, x, y, gIndex = gridOffset[i];
+
+ for(S = 0; S < numVerts; ++S, ++gIndex, ++k) {
+ MDisps *mdisp = &mdisps[k];
DMGridData *grid = gridData[gIndex];
DMGridData *subgrid = subGridData[gIndex];
- float (*dispgrid)[3] = &mdisp->disps[S*dGridSize*dGridSize];
+ float (*dispgrid)[3] = NULL;
+
+ /* when adding new faces in edit mode, need to allocate disps */
+ if(!mdisp->disps)
+ #pragma omp critical
+ {
+ multires_reallocate_mdisps(me, mdisps, totlvl);
+ }
+
+ dispgrid = mdisp->disps;
for(y = 0; y < gridSize; y++) {
for(x = 0; x < gridSize; x++) {
@@ -805,9 +811,10 @@ static void multiresModifier_update(DerivedMesh *dm)
ob = ccgdm->multires.ob;
me = ccgdm->multires.ob->data;
mmd = ccgdm->multires.mmd;
+
multires_set_tot_mdisps(me, mmd->totlvl);
- CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
- mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
+ CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
+ mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
if(mdisps) {
int lvl = ccgdm->multires.lvl;
@@ -821,7 +828,7 @@ static void multiresModifier_update(DerivedMesh *dm)
int i, j, numGrids, highGridSize, lowGridSize;
/* create subsurf DM from original mesh at high level */
- if (ob->derivedDeform) cddm = CDDM_copy(ob->derivedDeform);
+ if (ob->derivedDeform) cddm = CDDM_copy(ob->derivedDeform, 0);
else cddm = CDDM_from_mesh(me, NULL);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
@@ -875,7 +882,7 @@ static void multiresModifier_update(DerivedMesh *dm)
else {
DerivedMesh *cddm, *subdm;
- if (ob->derivedDeform) cddm = CDDM_copy(ob->derivedDeform);
+ if (ob->derivedDeform) cddm = CDDM_copy(ob->derivedDeform, 0);
else cddm = CDDM_from_mesh(me, NULL);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
@@ -948,7 +955,9 @@ DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int loca
}
multires_set_tot_mdisps(me, mmd->totlvl);
- CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
+ CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
+
+ /*run displacement*/
multiresModifier_disp_run(result, ob->data, 0, 0, subGridData, mmd->totlvl);
for(i = 0; i < numGrids; i++)
@@ -1049,15 +1058,33 @@ static void old_mdisps_convert(MFace *mface, MDisps *mdisp)
void multires_load_old_250(Mesh *me)
{
- MDisps *mdisps;
- int a;
+ MDisps *mdisps, *mdisps2;
+ MFace *mf;
+ int i, j, k;
mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS);
if(mdisps) {
- for(a=0; a<me->totface; a++)
- if(mdisps[a].totdisp)
- old_mdisps_convert(&me->mface[a], &mdisps[a]);
+ for(i=0; i<me->totface; i++)
+ if(mdisps[i].totdisp)
+ old_mdisps_convert(&me->mface[i], &mdisps[i]);
+
+ CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop);
+ mdisps2 = CustomData_get_layer(&me->ldata, CD_MDISPS);
+
+ k = 0;
+ mf = me->mface;
+ for (i=0; i<me->totface; i++, mf++) {
+ int nvert = mf->v4 ? 4 : 3;
+ int totdisp = mdisps[i].totdisp / nvert;
+
+ for (j=0; j < mf->v4 ? 4 : 3; j++, k++) {
+ mdisps2[k].disps = MEM_callocN(sizeof(float)*3*totdisp, "multires disp in conversion");
+ mdisps2[k].totdisp = totdisp;
+ memcpy(mdisps2[k].disps, mdisps[i].disps + totdisp*j, totdisp);
+ }
+
+ }
}
}
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 15ad3a7809a..53bac9171ae 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -3586,5 +3586,4 @@ void clear_scene_in_nodes(Main *bmain, Scene *sce)
}
}
}
-}
-
+} \ No newline at end of file
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 21a53d5365a..9910392e2d0 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -81,6 +81,7 @@
#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_mesh.h"
+#include "BKE_tessmesh.h"
#include "BKE_mball.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -947,7 +948,7 @@ void free_lamp(Lamp *la)
BKE_free_animdata((ID *)la);
- curvemapping_free(la->curfalloff);
+ curvemapping_free(la->curfalloff);
BKE_previewimg_free(&la->preview);
BKE_icon_delete(&la->id);
@@ -1897,7 +1898,7 @@ static void ob_parbone(Object *ob, Object *par, float mat[][4])
static void give_parvert(Object *par, int nr, float *vec)
{
- EditMesh *em;
+ BMEditMesh *em;
int a, count;
vec[0]=vec[1]=vec[2]= 0.0f;
@@ -1906,7 +1907,22 @@ static void give_parvert(Object *par, int nr, float *vec)
Mesh *me= par->data;
DerivedMesh *dm;
- em = BKE_mesh_get_editmesh(me);
+ em = me->edit_btmesh;
+
+ if(em) {
+ BMVert *eve;
+ BMIter iter;
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ int *keyindex = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_SHAPE_KEYINDEX);
+
+ if(keyindex && *keyindex==nr) {
+ memcpy(vec, eve->co, sizeof(float)*3);
+ break;
+ }
+ }
+ }
+
dm = (em)? em->derivedFinal: par->derivedFinal;
if(dm) {
@@ -1933,9 +1949,6 @@ static void give_parvert(Object *par, int nr, float *vec)
dm->getVertCo(dm, 0, vec);
}
}
-
- if(em)
- BKE_mesh_end_editmesh(me, em);
}
else if (ELEM(par->type, OB_CURVE, OB_SURF)) {
Nurb *nu;
@@ -2568,11 +2581,14 @@ void object_handle_update(Scene *scene, Object *ob)
if (G.f & G_DEBUG)
printf("recalcdata %s\n", ob->id.name+2);
+
if(adt) {
/* evaluate drivers */
// XXX: for mesh types, should we push this to derivedmesh instead?
BKE_animsys_evaluate_animdata(data_id, adt, ctime, ADT_RECALC_DRIVERS);
+
+
}
/* includes all keys and modifiers */
@@ -2580,19 +2596,17 @@ void object_handle_update(Scene *scene, Object *ob)
case OB_MESH:
{
#if 0 // XXX, comment for 2.56a release, background wont set 'scene->customdata_mask'
- EditMesh *em = (ob == scene->obedit)? BKE_mesh_get_editmesh(ob->data): NULL;
+ BMEditMesh *em = (ob == scene->obedit)? ((Mesh*)ob->data)->edit_btmesh : NULL;
BLI_assert((scene->customdata_mask & CD_MASK_BAREMESH) == CD_MASK_BAREMESH);
if(em) {
makeDerivedMesh(scene, ob, em, scene->customdata_mask); /* was CD_MASK_BAREMESH */
- BKE_mesh_end_editmesh(ob->data, em);
} else
makeDerivedMesh(scene, ob, NULL, scene->customdata_mask);
#else /* ensure CD_MASK_BAREMESH for now */
- EditMesh *em = (ob == scene->obedit)? BKE_mesh_get_editmesh(ob->data): NULL;
+ BMEditMesh *em = (ob == scene->obedit)? ((Mesh*)ob->data)->edit_btmesh : NULL;
if(em) {
makeDerivedMesh(scene, ob, em, scene->customdata_mask | CD_MASK_BAREMESH); /* was CD_MASK_BAREMESH */
- BKE_mesh_end_editmesh(ob->data, em);
} else
makeDerivedMesh(scene, ob, NULL, scene->customdata_mask | CD_MASK_BAREMESH);
#endif
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 4609e64c271..4b3b30e6cd2 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -51,6 +51,8 @@
#include "BLI_kdtree.h"
#include "BLI_rand.h"
#include "BLI_threads.h"
+#include "BLI_cellalloc.h"
+#include "BLI_math.h"
#include "BKE_anim.h"
#include "BKE_animsys.h"
@@ -696,7 +698,7 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[][4], float
data->totchildcache= psys->totchildcache;
if(psmd->dm)
- data->dm= CDDM_copy(psmd->dm);
+ data->dm= CDDM_copy(psmd->dm, 0);
data->totdmvert= psmd->totdmvert;
data->totdmedge= psmd->totdmedge;
data->totdmface= psmd->totdmface;
@@ -799,9 +801,9 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
return tot;
mvert= dm->getVertArray(dm);
- mface= dm->getFaceArray(dm);
- origindex= dm->getFaceDataArray(dm, CD_ORIGINDEX);
- totface= dm->getNumFaces(dm);
+ mface= dm->getTessFaceArray(dm);
+ origindex= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ totface= dm->getNumTessFaces(dm);
totorigface= me->totface;
if(totface == 0 || totorigface == 0)
@@ -1540,7 +1542,7 @@ static float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int
case PART_FROM_FACE:
case PART_FROM_VOLUME:
{
- MFace *mf=dm->getFaceData(dm,index,CD_MFACE);
+ MFace *mf=dm->getTessFaceData(dm,index,CD_MFACE);
return interpolate_particle_value(values[mf->v1],values[mf->v2],values[mf->v3],values[mf->v4],fw,mf->v4);
}
@@ -1588,11 +1590,11 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, float *
int quad, findex, totface;
float uv[2], (*faceuv)[2];
- mface = dm->getFaceDataArray(dm, CD_MFACE);
- origindex = dm->getFaceDataArray(dm, CD_ORIGINDEX);
- osface = dm->getFaceDataArray(dm, CD_ORIGSPACE);
+ mface = dm->getTessFaceDataArray(dm, CD_MFACE);
+ origindex = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ osface = dm->getTessFaceDataArray(dm, CD_ORIGSPACE);
- totface = dm->getNumFaces(dm);
+ totface = dm->getNumTessFaces(dm);
if(osface==NULL || origindex==NULL) {
/* Assume we dont need osface data */
@@ -1661,7 +1663,7 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
*mapindex = index;
}
else { /* FROM_FACE/FROM_VOLUME */
- if(index >= dm->getNumFaces(dm))
+ if(index >= dm->getNumTessFaces(dm))
return 0;
*mapindex = index;
@@ -1685,15 +1687,15 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
i = index_dmcache;
- if(i== DMCACHE_NOTFOUND || i >= dm->getNumFaces(dm))
+ if(i== DMCACHE_NOTFOUND || i >= dm->getNumTessFaces(dm))
return 0;
*mapindex = i;
/* modify the original weights to become
* weights for the derived mesh face */
- osface= dm->getFaceDataArray(dm, CD_ORIGSPACE);
- mface= dm->getFaceData(dm, i, CD_MFACE);
+ osface= dm->getTessFaceDataArray(dm, CD_ORIGSPACE);
+ mface= dm->getTessFaceData(dm, i, CD_MFACE);
if(osface == NULL)
mapfw[0]= mapfw[1]= mapfw[2]= mapfw[3]= 0.0f;
@@ -1751,7 +1753,7 @@ void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache
MTFace *mtface;
MVert *mvert;
- mface=dm->getFaceData(dm,mapindex,CD_MFACE);
+ mface=dm->getTessFaceData(dm,mapindex,CD_MFACE);
mvert=dm->getVertDataArray(dm,CD_MVERT);
mtface=CustomData_get_layer(&dm->faceData,CD_MTFACE);
@@ -3330,10 +3332,10 @@ static void psys_face_mat(Object *ob, DerivedMesh *dm, ParticleData *pa, float m
int i = pa->num_dmcache==DMCACHE_NOTFOUND ? pa->num : pa->num_dmcache;
- if (i==-1 || i >= dm->getNumFaces(dm)) { unit_m4(mat); return; }
+ if (i==-1 || i >= dm->getNumTessFaces(dm)) { unit_m4(mat); return; }
- mface=dm->getFaceData(dm,i,CD_MFACE);
- osface=dm->getFaceData(dm,i,CD_ORIGSPACE);
+ mface=dm->getTessFaceData(dm,i,CD_MFACE);
+ osface=dm->getTessFaceData(dm,i,CD_ORIGSPACE);
if(orco && (orcodata=dm->getVertDataArray(dm, CD_ORCO))) {
VECCOPY(v[0], orcodata[mface->v1]);
@@ -3667,7 +3669,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, fl
if(pa) {
i= (pa->num_dmcache==DMCACHE_NOTFOUND)? pa->num: pa->num_dmcache;
- if(i >= dm->getNumFaces(dm))
+ if(i >= dm->getNumTessFaces(dm))
i = -1;
}
else
@@ -3679,7 +3681,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, fl
texco[2]= 0.0f;
}
else {
- mf= dm->getFaceData(dm, i, CD_MFACE);
+ mf= dm->getTessFaceData(dm, i, CD_MFACE);
psys_interpolate_uvs(&tf[i], mf->v4, fuv, texco);
@@ -4318,7 +4320,7 @@ void psys_get_dupli_texture(Object *UNUSED(ob), ParticleSettings *part, Particle
if(part->childtype == PART_CHILD_FACES) {
mtface= CustomData_get_layer(&psmd->dm->faceData, CD_MTFACE);
if(mtface) {
- mface= psmd->dm->getFaceData(psmd->dm, cpa->num, CD_MFACE);
+ mface= psmd->dm->getTessFaceData(psmd->dm, cpa->num, CD_MFACE);
mtface += cpa->num;
psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv);
}
@@ -4340,14 +4342,14 @@ void psys_get_dupli_texture(Object *UNUSED(ob), ParticleSettings *part, Particle
if(num == DMCACHE_NOTFOUND)
num= pa->num;
- if (num >= psmd->dm->getNumFaces(psmd->dm)) {
+ if (num >= psmd->dm->getNumTessFaces(psmd->dm)) {
/* happens when simplify is enabled
* gives invalid coords but would crash otherwise */
num= DMCACHE_NOTFOUND;
}
if(mtface && num != DMCACHE_NOTFOUND) {
- mface= psmd->dm->getFaceData(psmd->dm, num, CD_MFACE);
+ mface= psmd->dm->getTessFaceData(psmd->dm, num, CD_MFACE);
mtface += num;
psys_interpolate_uvs(mtface, mface->v4, pa->fuv, uv);
}
@@ -4505,7 +4507,6 @@ void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3]
VECADDFAC(center, center, yvec, bb->offset[1]);
}
-
void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys) {
ParticleSimulationData sim= {0};
sim.scene= scene;
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index fd792168c6b..b4900553814 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -347,9 +347,9 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys)
origindex= dm->getVertDataArray(dm, CD_ORIGINDEX);
}
else { /* FROM_FACE/FROM_VOLUME */
- totdmelem= dm->getNumFaces(dm);
+ totdmelem= dm->getNumTessFaces(dm);
totelem= me->totface;
- origindex= dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ origindex= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
}
nodedmelem= MEM_callocN(sizeof(LinkNode)*totdmelem, "psys node elems");
@@ -489,8 +489,8 @@ static void distribute_particles_in_grid(DerivedMesh *dm, ParticleSystem *psys)
int a, a1, a2, a0mul, a1mul, a2mul, totface;
int amax= from==PART_FROM_FACE ? 3 : 1;
- totface=dm->getNumFaces(dm);
- mface_array= dm->getFaceDataArray(dm,CD_MFACE);
+ totface=dm->getNumTessFaces(dm);
+ mface=mface_array=dm->getTessFaceDataArray(dm,CD_MFACE);
for(a=0; a<amax; a++){
if(a==0){ a0mul=res*res; a1mul=res; a2mul=1; }
@@ -751,7 +751,7 @@ static void psys_thread_distribute_particle(ParticleThread *thread, ParticleData
MFace *mface;
pa->num = i = ctx->index[p];
- mface = dm->getFaceData(dm,i,CD_MFACE);
+ mface = dm->getTessFaceData(dm,i,CD_MFACE);
switch(distr){
case PART_DISTR_JIT:
@@ -773,7 +773,7 @@ static void psys_thread_distribute_particle(ParticleThread *thread, ParticleData
if(from==PART_FROM_VOLUME){
MVert *mvert=dm->getVertDataArray(dm,CD_MVERT);
- tot=dm->getNumFaces(dm);
+ tot=dm->getNumTessFaces(dm);
psys_interpolate_face(mvert,mface,0,0,pa->fuv,co1,nor,0,0,0,0);
@@ -785,7 +785,7 @@ static void psys_thread_distribute_particle(ParticleThread *thread, ParticleData
min_d=2.0;
intersect=0;
- for(i=0,mface=dm->getFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++){
+ for(i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++){
if(i==pa->num) continue;
v1=mvert[mface->v1].co;
@@ -842,7 +842,7 @@ static void psys_thread_distribute_particle(ParticleThread *thread, ParticleData
return;
}
- mf= dm->getFaceData(dm, ctx->index[p], CD_MFACE);
+ mf= dm->getTessFaceData(dm, ctx->index[p], CD_MFACE);
randu= rng_getFloat(thread->rng);
randv= rng_getFloat(thread->rng);
@@ -1001,7 +1001,7 @@ static int psys_threads_init_distribution(ParticleThread *threads, Scene *scene,
if(totpart==0)
return 0;
- if (!finaldm->deformedOnly && !finaldm->getFaceDataArray(finaldm, CD_ORIGINDEX)) {
+ if (!finaldm->deformedOnly && !finaldm->getTessFaceDataArray(finaldm, CD_ORIGINDEX)) {
printf("Can't create particles with the current modifier stack, disable destructive modifiers\n");
// XXX error("Can't paint with the current modifier stack, disable destructive modifiers");
return 0;
@@ -1102,7 +1102,7 @@ static int psys_threads_init_distribution(ParticleThread *threads, Scene *scene,
break;
case PART_FROM_VOLUME:
case PART_FROM_FACE:
- tot = dm->getNumFaces(dm);
+ tot = dm->getNumTessFaces(dm);
break;
case PART_FROM_PARTICLE:
if(psys->target_ob)
@@ -1162,7 +1162,7 @@ static int psys_threads_init_distribution(ParticleThread *threads, Scene *scene,
orcodata= dm->getVertDataArray(dm, CD_ORCO);
for(i=0; i<tot; i++){
- MFace *mf=dm->getFaceData(dm,i,CD_MFACE);
+ MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
if(orcodata) {
VECCOPY(co1, orcodata[mf->v1]);
@@ -1231,7 +1231,7 @@ static int psys_threads_init_distribution(ParticleThread *threads, Scene *scene,
}
else { /* PART_FROM_FACE / PART_FROM_VOLUME */
for(i=0;i<tot; i++){
- MFace *mf=dm->getFaceData(dm,i,CD_MFACE);
+ MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
tweight = vweight[mf->v1] + vweight[mf->v2] + vweight[mf->v3];
if(mf->v4) {
@@ -1307,7 +1307,7 @@ static int psys_threads_init_distribution(ParticleThread *threads, Scene *scene,
}
else {
if(dm->numFaceData)
- COMPARE_ORIG_INDEX= dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ COMPARE_ORIG_INDEX= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
}
if(COMPARE_ORIG_INDEX) {
@@ -1550,7 +1550,7 @@ void initialize_particle(ParticleSimulationData *sim, ParticleData *pa, int p)
pa->time = (part->type == PART_HAIR) ? 0.f : part->sta + (part->end - part->sta)*ptex.time;
}
-
+
pa->hair_index = 0;
/* we can't reset to -1 anymore since we've figured out correct index in distribute_particles */
/* usage other than straight after distribute has to handle this index by itself - jahka*/
@@ -1622,7 +1622,7 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime,
float q_phase[4];
int p = pa - psys->particles;
part=psys->part;
-
+
#if 0 /* deprecated code */
if(part->from==PART_FROM_PARTICLE){
float speed;
@@ -1885,7 +1885,6 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime,
}
}
-
if(part->type == PART_HAIR){
pa->lifetime = 100.0f;
}
@@ -2712,8 +2711,8 @@ int psys_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm, float *vert_cos
VECCOPY(p_max,pa_minmax+3);
}
- totface=dm->getNumFaces(dm);
- mface=dm->getFaceDataArray(dm,CD_MFACE);
+ totface=dm->getNumTessFaces(dm);
+ mface=dm->getTessFaceDataArray(dm,CD_MFACE);
mvert=dm->getVertDataArray(dm,CD_MVERT);
/* lets intersect the faces */
@@ -3228,7 +3227,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
}
if(!dm) {
- dm = psys->hair_in_dm = CDDM_new(totpoint, totedge, 0);
+ dm = psys->hair_in_dm = CDDM_new(totpoint, totedge, 0, 0, 0);
DM_add_vert_layer(dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
}
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
index c004e254572..c8a855c8156 100644
--- a/source/blender/blenkernel/intern/sca.c
+++ b/source/blender/blenkernel/intern/sca.c
@@ -589,6 +589,15 @@ void set_sca_new_poins_ob(Object *ob)
bPropertyActuator *pa= act->data;
ID_NEW(pa->ob);
}
+ else if(act->type==ACT_ARMATURE) {
+ bArmatureActuator *aa = act->data;
+ ID_NEW(aa->target);
+ ID_NEW(aa->subtarget);
+ }
+ else if(act->type==ACT_PROPERTY) {
+ bPropertyActuator *pa= act->data;
+ ID_NEW(pa->ob);
+ }
}
act= act->next;
}
diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c
index df81bcd1593..000d08e4df2 100644..100755
--- a/source/blender/blenkernel/intern/seqcache.c
+++ b/source/blender/blenkernel/intern/seqcache.c
@@ -145,8 +145,8 @@ void seq_stripelem_cache_init(void)
hash = BLI_ghash_new(HashHash, HashCmp, "seq stripelem cache hash");
limitor = new_MEM_CacheLimiter( IMB_seq_cache_destructor );
- entrypool = BLI_mempool_create(sizeof(seqCacheEntry), 64, 64, 0);
- keypool = BLI_mempool_create(sizeof(seqCacheKey), 64, 64, 0);
+ entrypool = BLI_mempool_create(sizeof(seqCacheEntry), 64, 64, 0, 0);
+ keypool = BLI_mempool_create(sizeof(seqCacheKey), 64, 64, 0, 0);
}
void seq_stripelem_cache_destruct(void)
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 53fefa685b9..5311f3a9c38 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -39,6 +39,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
+#include "DNA_windowmanager_types.h"
#include "BLI_editVert.h"
#include "BLI_math.h"
@@ -51,6 +52,8 @@
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_subsurf.h"
+#include "BKE_mesh.h"
+#include "BKE_tessmesh.h"
/* Util macros */
#define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n"))
@@ -86,11 +89,11 @@ typedef void ( *Shrinkwrap_ForeachVertexCallback) (DerivedMesh *target, float *c
DerivedMesh *object_get_derived_final(Object *ob)
{
Mesh *me= ob->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
+ BMEditMesh *em = me->edit_btmesh;
- if(em) {
+ if (em)
+ {
DerivedMesh *dm = em->derivedFinal;
- BKE_mesh_end_editmesh(me, em);
return dm;
}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index b2d3ddf2e52..b2f8831cced 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -295,7 +295,7 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene,
if(!smd->coll->bvhtree)
{
- smd->coll->bvhtree = NULL; // bvhtree_build_from_smoke ( ob->obmat, dm->getFaceArray(dm), dm->getNumFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm), 0.0 );
+ smd->coll->bvhtree = NULL; // bvhtree_build_from_smoke ( ob->obmat, dm->getTessFaceArray(dm), dm->getNumTessFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm), 0.0 );
}
return 1;
}
@@ -306,7 +306,7 @@ static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene,
static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs)
{
MVert *mvert = dm->getVertArray(dm);
- MFace *mface = dm->getFaceArray(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
int i = 0, divs = 0;
int *tridivs = NULL;
float cell_len = 1.0 / 50.0; // for res = 50
@@ -314,16 +314,16 @@ static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs)
int quads = 0, facecounter = 0;
// count quads
- for(i = 0; i < dm->getNumFaces(dm); i++)
+ for(i = 0; i < dm->getNumTessFaces(dm); i++)
{
if(mface[i].v4)
quads++;
}
- calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface, dm->getNumFaces(dm), dm->getNumFaces(dm) + quads, &tridivs, cell_len);
+ calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface, dm->getNumTessFaces(dm), dm->getNumTessFaces(dm) + quads, &tridivs, cell_len);
// count triangle divisions
- for(i = 0; i < dm->getNumFaces(dm) + quads; i++)
+ for(i = 0; i < dm->getNumTessFaces(dm) + quads; i++)
{
divs += (tridivs[3 * i] + 1) * (tridivs[3 * i + 1] + 1) * (tridivs[3 * i + 2] + 1);
}
@@ -340,7 +340,7 @@ static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs)
VECCOPY(&scs->points[i * 3], tmpvec);
}
- for(i = 0, facecounter = 0; i < dm->getNumFaces(dm); i++)
+ for(i = 0, facecounter = 0; i < dm->getNumTessFaces(dm); i++)
{
int again = 0;
do
@@ -1321,7 +1321,7 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM
if(smd->coll->dm)
smd->coll->dm->release(smd->coll->dm);
- smd->coll->dm = CDDM_copy(dm);
+ smd->coll->dm = CDDM_copy(dm, 1);
// rigid movement support
copy_m4_m4(smd->coll->mat_old, smd->coll->mat);
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index ca8df76311d..d197541c620 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -66,6 +66,7 @@ variables on the UI for now
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_threads.h"
+#include "BLI_cellalloc.h"
#include "BKE_curve.h"
#include "BKE_effect.h"
@@ -294,11 +295,11 @@ static ccd_Mesh *ccd_mesh_make(Object *ob, DerivedMesh *dm)
/* first some paranoia checks */
if (!dm) return NULL;
- if (!dm->getNumVerts(dm) || !dm->getNumFaces(dm)) return NULL;
+ if (!dm->getNumVerts(dm) || !dm->getNumTessFaces(dm)) return NULL;
pccd_M = MEM_mallocN(sizeof(ccd_Mesh),"ccd_Mesh");
pccd_M->totvert = dm->getNumVerts(dm);
- pccd_M->totface = dm->getNumFaces(dm);
+ pccd_M->totface = dm->getNumTessFaces(dm);
pccd_M->savety = CCD_SAVETY;
pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f;
pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f;
@@ -327,7 +328,7 @@ static ccd_Mesh *ccd_mesh_make(Object *ob, DerivedMesh *dm)
}
/* alloc and copy faces*/
- pccd_M->mface = dm->dupFaceArray(dm);
+ pccd_M->mface = dm->dupTessFaceArray(dm);
/* OBBs for idea1 */
pccd_M->mima = MEM_mallocN(sizeof(ccdf_minmax)*pccd_M->totface,"ccd_Mesh_Faces_mima");
@@ -390,10 +391,10 @@ static void ccd_mesh_update(Object *ob,ccd_Mesh *pccd_M, DerivedMesh *dm)
/* first some paranoia checks */
if (!dm) return ;
- if (!dm->getNumVerts(dm) || !dm->getNumFaces(dm)) return ;
+ if (!dm->getNumVerts(dm) || !dm->getNumTessFaces(dm)) return ;
if ((pccd_M->totvert != dm->getNumVerts(dm)) ||
- (pccd_M->totface != dm->getNumFaces(dm))) return;
+ (pccd_M->totface != dm->getNumTessFaces(dm))) return;
pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f;
pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f;
@@ -2123,9 +2124,9 @@ static void sb_spring_force(Object *ob,int bpi,BodySpring *bs,float iks,float UN
forcefactor = iks/bs->len;
else
forcefactor = iks;
- kw = (bp1->springweight+bp2->springweight)/2.0f;
- kw = kw * kw;
- kw = kw * kw;
+ kw = (bp1->springweight+bp2->springweight)/2.0f;
+ kw = kw * kw;
+ kw = kw * kw;
switch (bs->springtype){
case SB_EDGE:
case SB_HANDLE:
@@ -3467,7 +3468,7 @@ static void makelatticesprings(Lattice *lt, BodySpring *bs, int dostiff,Object *
if (dostiff) {
- if(w){
+ if(w){
if( v && u ) {
bs->v1 = bpc;
bs->v2 = bpc-dw-dv-1;
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 9c157f57d49..88ca0c33624 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -445,8 +445,8 @@ void sound_seek_scene(struct bContext *C)
AUD_resume(scene->sound_scene_handle);
if(AUD_getStatus(scene->sound_scrub_handle) != AUD_STATUS_INVALID)
AUD_seek(scene->sound_scrub_handle, 0);
- else
- scene->sound_scrub_handle = AUD_pauseAfter(scene->sound_scene_handle, 1 / FPS);
+ //XXX merge EEK! else
+ //scene->sound_scrub_handle = AUD_pauseAfter(scene->sound_scene_handle, 1 / FPS);
}
else
{
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 5697c29db5d..86e901345c4 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -55,7 +55,11 @@
#include "BKE_paint.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
+#include "BKE_tessmesh.h"
+#include "BKE_utildefines.h"
+#include "PIL_time.h"
+#include "BLI_array.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -66,9 +70,10 @@
#include "CCGSubSurf.h"
-static int ccgDM_getVertMapIndex(CCGSubSurf *ss, CCGVert *v);
-static int ccgDM_getEdgeMapIndex(CCGSubSurf *ss, CCGEdge *e);
-static int ccgDM_getFaceMapIndex(CCGSubSurf *ss, CCGFace *f);
+static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
+ int drawInteriorEdges,
+ int useSubsurfUv,
+ DerivedMesh *dm);
///
@@ -155,7 +160,8 @@ static int getEdgeIndex(CCGSubSurf *ss, CCGEdge *e, int x, int edgeSize) {
return edgeBase + x-1;
}
}
-static int getFaceIndex(CCGSubSurf *ss, CCGFace *f, int S, int x, int y, int edgeSize, int gridSize) {
+
+BM_INLINE int getFaceIndex(CCGSubSurf *ss, CCGFace *f, int S, int x, int y, int edgeSize, int gridSize) {
int faceBase = *((int*) ccgSubSurf_getFaceUserData(ss, f));
int numVerts = ccgSubSurf_getFaceNumVerts(f);
@@ -210,10 +216,11 @@ static void get_face_uv_map_vert(UvVertMap *vmap, struct MFace *mf, int fi, CCGV
}
static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, MTFace *tface) {
- MFace *mface = dm->getFaceArray(dm);
+#if 0
+ MFace *mface = dm->getTessFaceArray(dm);
MVert *mvert = dm->getVertArray(dm);
int totvert = dm->getNumVerts(dm);
- int totface = dm->getNumFaces(dm);
+ int totface = dm->getNumTessFaces(dm);
int i, j, seam;
UvMapVert *v;
UvVertMap *vmap;
@@ -303,6 +310,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm,
free_uv_vert_map(vmap);
ccgSubSurf_processSync(ss);
+#endif
return 1;
}
@@ -375,7 +383,6 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result,
MEM_freeN(faceMap);
}
-/* face weighting */
static void calc_ss_weights(int gridFaces,
FaceVertWeight **qweight, FaceVertWeight **tweight)
{
@@ -419,22 +426,496 @@ static void calc_ss_weights(int gridFaces,
}
}
+/* face weighting */
+typedef struct FaceVertWeightEntry {
+ FaceVertWeight *weight;
+ float *w;
+ int valid;
+} FaceVertWeightEntry;
+
+typedef struct WeightTable {
+ FaceVertWeightEntry *weight_table;
+ int len;
+} WeightTable;
+
+static float *get_ss_weights(WeightTable *wtable, int gridCuts, int faceLen)
+{
+ int x, y, i, j;
+ float *w, w1, w2, w4, fac, fac2, fx, fy;
+
+ if (wtable->len <= faceLen) {
+ void *tmp = MEM_callocN(sizeof(FaceVertWeightEntry)*(faceLen+1), "weight table alloc 2");
+
+ if (wtable->len) {
+ memcpy(tmp, wtable->weight_table, sizeof(FaceVertWeightEntry)*wtable->len);
+ MEM_freeN(wtable->weight_table);
+ }
+
+ wtable->weight_table = tmp;
+ wtable->len = faceLen+1;
+ }
+
+ if (!wtable->weight_table[faceLen].valid) {
+ wtable->weight_table[faceLen].valid = 1;
+ wtable->weight_table[faceLen].w = w = MEM_callocN(sizeof(float)*faceLen*faceLen*(gridCuts+2)*(gridCuts+2), "weight table alloc");
+ fac = 1.0 / (float)faceLen;
+
+ for (i=0; i<faceLen; i++) {
+ for (x=0; x<gridCuts+2; x++) {
+ for (y=0; y<gridCuts+2; y++) {
+ fx = 0.5f - (float)x / (float)(gridCuts+1) / 2.0f;
+ fy = 0.5f - (float)y / (float)(gridCuts+1) / 2.0f;
+
+ fac2 = faceLen - 4;
+ w1 = (1.0f - fx) * (1.0f - fy) + (-fac2*fx*fy*fac);
+ w2 = (1.0f - fx + fac2*fx*-fac) * (fy);
+ w4 = (fx) * (1.0 - fy + -fac2*fy*fac);
+
+ fac2 = 1.0 - (w1+w2+w4);
+ fac2 = fac2 / (float)(faceLen-3);
+ for (j=0; j<faceLen; j++)
+ w[j] = fac2;
+
+ w[i] = w1;
+ w[(i-1+faceLen)%faceLen] = w2;
+ w[(i+1)%faceLen] = w4;
+
+ w += faceLen;
+ }
+ }
+ }
+ }
+
+ return wtable->weight_table[faceLen].w;
+}
+
+void free_ss_weights(WeightTable *wtable)
+{
+ int i;
+
+ for (i=0; i<wtable->len; i++) {
+ if (wtable->weight_table[i].valid)
+ MEM_freeN(wtable->weight_table[i].w);
+ }
+}
+
+static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
+ int drawInteriorEdges, int useSubsurfUv,
+ DerivedMesh *dm, struct MultiresSubsurf *ms)
+{
+ DerivedMesh *cgdm, *result;
+ double curt = PIL_check_seconds_timer();
+
+ cgdm = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm);
+ result = CDDM_copy(cgdm, 1);
+
+ printf("subsurf conversion time: %.6lf\n", PIL_check_seconds_timer() - curt);
+
+ cgdm->needsFree = 1;
+ cgdm->release(cgdm);
+
+ CDDM_calc_normals(result);
+
+ return result;
+#if 0
+ DerivedMesh *result;
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int gridFaces = gridSize - 1;
+ int edgeBase, faceBase;
+ int i, j, k, S, x, y, index;
+ int *vertIdx = NULL;
+ BLI_array_declare(vertIdx);
+ CCGVertIterator *vi;
+ CCGEdgeIterator *ei;
+ CCGFaceIterator *fi;
+ CCGFace **faceMap2;
+ CCGEdge **edgeMap2;
+ CCGVert **vertMap2;
+ int totvert, totedge, totface;
+ MVert *mvert;
+ MEdge *med;
+ float *w = NULL;
+ WeightTable wtable;
+ BLI_array_declare(w);
+ MFace *mf;
+ int *origIndex;
+
+ memset(&wtable, 0, sizeof(wtable));
+
+ /* vert map */
+ totvert = ccgSubSurf_getNumVerts(ss);
+ vertMap2 = MEM_mallocN(totvert*sizeof(*vertMap2), "vertmap");
+ vi = ccgSubSurf_getVertIterator(ss);
+ for(; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
+ CCGVert *v = ccgVertIterator_getCurrent(vi);
+
+ vertMap2[GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v))] = v;
+ }
+ ccgVertIterator_free(vi);
+
+ totedge = ccgSubSurf_getNumEdges(ss);
+ edgeMap2 = MEM_mallocN(totedge*sizeof(*edgeMap2), "edgemap");
+ ei = ccgSubSurf_getEdgeIterator(ss);
+ for(; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
+ CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
+
+ edgeMap2[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))] = e;
+ }
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ faceMap2 = MEM_mallocN(totface*sizeof(*faceMap2), "facemap");
+ fi = ccgSubSurf_getFaceIterator(ss);
+ for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(fi);
+
+ faceMap2[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f))] = f;
+ }
+ ccgFaceIterator_free(fi);
+
+ if(ms) {
+ result = MultiresDM_new(ms, dm, ccgSubSurf_getNumFinalVerts(ss),
+ ccgSubSurf_getNumFinalEdges(ss),
+ ccgSubSurf_getNumFinalFaces(ss), 0, 0);
+ }
+ else {
+ if(dm) {
+ result = CDDM_from_template(dm, ccgSubSurf_getNumFinalVerts(ss),
+ ccgSubSurf_getNumFinalEdges(ss),
+ ccgSubSurf_getNumFinalFaces(ss), 0, 0);
+ } else {
+ result = CDDM_new(ccgSubSurf_getNumFinalVerts(ss),
+ ccgSubSurf_getNumFinalEdges(ss),
+ ccgSubSurf_getNumFinalFaces(ss), 0, 0);
+ }
+ }
+
+ // load verts
+ faceBase = i = 0;
+ mvert = CDDM_get_verts(result);
+ origIndex = result->getVertData(result, 0, CD_ORIGINDEX);
+
+ for(index = 0; index < totface; index++) {
+ CCGFace *f = faceMap2[index];
+ int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
+ FaceVertWeight *weight = 0;//get_ss_weights(&wtable, gridFaces-1, numVerts);
+
+ BLI_array_empty(vertIdx);
+
+ for(S = 0; S < numVerts; S++) {
+ CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S);
+ BLI_array_growone(vertIdx);
+
+ vertIdx[S] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
+ }
+
+#if 0
+ DM_interp_vert_data(dm, result, vertIdx, weight[0][0], numVerts, i);
+#endif
+ copy_v3_v3(mvert->co, ccgSubSurf_getFaceCenterData(f));
+ *origIndex = ORIGINDEX_NONE;
+ ++mvert;
+ ++origIndex;
+ i++;
+
+ BLI_array_empty(w);
+ for (x=0; x<numVerts; x++) {
+ BLI_array_growone(w);
+ }
+
+ for(S = 0; S < numVerts; S++) {
+ int prevS = (S - 1 + numVerts) % numVerts;
+ int nextS = (S + 1) % numVerts;
+ int otherS = (numVerts >= 4) ? (S + 2) % numVerts : 3;
+
+ for(x = 1; x < gridFaces; x++) {
+#if 0
+ w[prevS] = weight[x][0][0];
+ w[S] = weight[x][0][1];
+ w[nextS] = weight[x][0][2];
+ w[otherS] = weight[x][0][3];
+
+ DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i);
+#endif
+ copy_v3_v3(mvert->co,
+ ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
+
+ *origIndex = ORIGINDEX_NONE;
+ ++mvert;
+ ++origIndex;
+ i++;
+ }
+ }
+
+ BLI_array_empty(w);
+ for (x=0; x<numVerts; x++) {
+ BLI_array_growone(w);
+ }
+
+ for(S = 0; S < numVerts; S++) {
+ int prevS = (S - 1 + numVerts) % numVerts;
+ int nextS = (S + 1) % numVerts;
+ int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
+
+ for(y = 1; y < gridFaces; y++) {
+ for(x = 1; x < gridFaces; x++) {
+#if 0
+ w[prevS] = weight[y * gridFaces + x][0][0];
+ w[S] = weight[y * gridFaces + x][0][1];
+ w[nextS] = weight[y * gridFaces + x][0][2];
+ w[otherS] = weight[y * gridFaces + x][0][3];
+ DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i);
+#endif
+
+ copy_v3_v3(mvert->co,
+ ccgSubSurf_getFaceGridData(ss, f, S, x, y));
+ *origIndex = ORIGINDEX_NONE;
+ ++mvert;
+ ++origIndex;
+ i++;
+ }
+ }
+ }
+ *((int*)ccgSubSurf_getFaceUserData(ss, f)) = faceBase;
+ faceBase += 1 + numVerts * ((gridSize-2) + (gridSize-2) * (gridSize-2));
+ }
+
+ edgeBase = i;
+ for(index = 0; index < totedge; index++) {
+ CCGEdge *e = edgeMap2[index];
+ int x;
+ int vertIdx[2];
+
+ CCGVert *v;
+ v = ccgSubSurf_getEdgeVert0(e);
+ vertIdx[0] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
+ v = ccgSubSurf_getEdgeVert1(e);
+ vertIdx[1] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
+
+ for(x = 1; x < edgeSize - 1; x++) {
+ float w2[2];
+
+ w2[1] = (float) x / (edgeSize - 1);
+ w2[0] = 1 - w2[1];
+ DM_interp_vert_data(dm, result, vertIdx, w2, 2, i);
+
+ copy_v3_v3(mvert->co, ccgSubSurf_getEdgeData(ss, e, x));
+ *origIndex = ORIGINDEX_NONE;
+ ++mvert;
+ ++origIndex;
+ i++;
+ }
+
+ *((int*)ccgSubSurf_getEdgeUserData(ss, e)) = edgeBase;
+ edgeBase += edgeSize-2;
+ }
+
+ for(index = 0; index < totvert; index++) {
+ CCGVert *v = vertMap2[index];
+ int vertIdx;
+
+ vertIdx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
+
+ DM_copy_vert_data(dm, result, vertIdx, i, 1);
+ copy_v3_v3(mvert->co, ccgSubSurf_getVertData(ss, v));
+
+ *((int*)ccgSubSurf_getVertUserData(ss, v)) = i;
+ *origIndex = ccgDM_getVertMapIndex(ss, v);
+ ++mvert;
+ ++origIndex;
+ i++;
+ }
+
+ // load edges
+ i = 0;
+ med = CDDM_get_edges(result);
+ origIndex = result->getEdgeData(result, 0, CD_ORIGINDEX);
+
+ for(index = 0; index < totface; index++) {
+ CCGFace *f = faceMap2[index];
+ int numVerts = ccgSubSurf_getFaceNumVerts(f);
+
+ for(k = 0; k < numVerts; k++) {
+ for(x = 0; x < gridFaces; x++) {
+ if(drawInteriorEdges) med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+ med->v1 = getFaceIndex(ss, f, k, x, 0, edgeSize, gridSize);
+ med->v2 = getFaceIndex(ss, f, k, x+1, 0, edgeSize, gridSize);
+ *origIndex = ORIGINDEX_NONE;
+ ++med;
+ ++origIndex;
+ i++;
+ }
+
+ for(x = 1; x < gridFaces; x++) {
+ for(y = 0; y < gridFaces; y++) {
+ if(drawInteriorEdges)
+ med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+ med->v1 = getFaceIndex(ss, f, k, x, y, edgeSize, gridSize);
+ med->v2 = getFaceIndex(ss, f, k, x, y + 1,
+ edgeSize, gridSize);
+ *origIndex = ORIGINDEX_NONE;
+ ++med;
+ ++origIndex;
+ i++;
+
+ if(drawInteriorEdges)
+ med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+ med->v1 = getFaceIndex(ss, f, k, y, x, edgeSize, gridSize);
+ med->v2 = getFaceIndex(ss, f, k, y + 1, x,
+ edgeSize, gridSize);
+ *origIndex = ORIGINDEX_NONE;
+ ++med;
+ ++origIndex;
+ i++;
+ }
+ }
+ }
+ }
+
+ for(index = 0; index < totedge; index++) {
+ CCGEdge *e = edgeMap2[index];
+ unsigned int flags = 0;
+ char bweight = 0;
+ int edgeIdx = GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e));
+
+ if(!ccgSubSurf_getEdgeNumFaces(e)) flags |= ME_LOOSEEDGE;
+
+
+ if(edgeIdx != -1 && dm) {
+ MEdge origMed;
+ dm->getEdge(dm, edgeIdx, &origMed);
+
+ flags |= origMed.flag;
+ bweight = origMed.bweight;
+ }
+
+ for(x = 0; x < edgeSize - 1; x++) {
+ med->v1 = getEdgeIndex(ss, e, x, edgeSize);
+ med->v2 = getEdgeIndex(ss, e, x + 1, edgeSize);
+ med->flag = flags;
+ med->bweight = bweight;
+ *origIndex = ccgDM_getEdgeMapIndex(ss, e);
+ ++med;
+ ++origIndex;
+ i++;
+ }
+ }
+
+ // load faces
+ i = 0;
+ mf = CDDM_get_tessfaces(result);
+ origIndex = result->getTessFaceData(result, 0, CD_ORIGINDEX);
+
+ for(index = 0; index < totface; index++) {
+ CCGFace *f = faceMap2[index];
+ int numVerts = ccgSubSurf_getFaceNumVerts(f);
+ int mat_nr;
+ int flag;
+ int mapIndex = ccgDM_getFaceMapIndex(ss, f);
+ int faceIdx = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f));
+
+ if(!ssFromEditmesh) {
+ MFace origMFace;
+ dm->getTessFace(dm, faceIdx, &origMFace);
+
+ mat_nr = origMFace.mat_nr;
+ flag = origMFace.flag;
+ } else {
+ BMFace *ef = ccgSubSurf_getFaceFaceHandle(ss, f);
+ mat_nr = ef->mat_nr;
+ flag = BMFlags_To_MEFlags(ef);
+ }
+
+ for(S = 0; S < numVerts; S++) {
+ FaceVertWeight *weight = 0;//get_ss_weights(&wtable, gridFaces-1, numVerts);
+
+ for(y = 0; y < gridFaces; y++) {
+ for(x = 0; x < gridFaces; x++) {
+ mf->v1 = getFaceIndex(ss, f, S, x + 0, y + 0,
+ edgeSize, gridSize);
+ mf->v2 = getFaceIndex(ss, f, S, x + 0, y + 1,
+ edgeSize, gridSize);
+ mf->v3 = getFaceIndex(ss, f, S, x + 1, y + 1,
+ edgeSize, gridSize);
+ mf->v4 = getFaceIndex(ss, f, S, x + 1, y + 0,
+ edgeSize, gridSize);
+ mf->mat_nr = mat_nr;
+ mf->flag = flag;
+#if 0 //BMESH_TODO
+ if(dm) {
+ int prevS = (S - 1 + numVerts) % numVerts;
+ int nextS = (S + 1) % numVerts;
+ int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
+ FaceVertWeight w;
+
+ for(j = 0; j < 4; ++j) {
+ w[j][prevS] = (*weight)[j][0];
+ w[j][S] = (*weight)[j][1];
+ w[j][nextS] = (*weight)[j][2];
+ w[j][otherS] = (*weight)[j][3];
+ }
+
+ DM_interp_tessface_data(dm, result, &faceIdx, NULL,
+ &w, 1, i);
+ weight++;
+ }
+#endif
+
+ *origIndex = mapIndex;
+ ++mf;
+ ++origIndex;
+ i++;
+ }
+ }
+ }
+ }
+
+ MEM_freeN(faceMap2);
+ MEM_freeN(edgeMap2);
+ MEM_freeN(vertMap2);
+
+ free_ss_weights(&wtable);
+
+ BLI_array_free(vertIdx);
+
+ if(useSubsurfUv) {
+ CustomData *fdata = &result->faceData;
+ CustomData *dmfdata = &dm->faceData;
+ int numlayer = CustomData_number_of_layers(fdata, CD_MTFACE);
+ int dmnumlayer = CustomData_number_of_layers(dmfdata, CD_MTFACE);
+
+ for (i=0; i<numlayer && i<dmnumlayer; i++)
+ set_subsurf_uv(ss, dm, result, i);
+ }
+
+ CDDM_calc_normals(result);
+ CDDM_tessfaces_to_faces(result);
+
+ BLI_array_free(w);
+ return result;
+#endif
+}
+
static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
float (*vertexCos)[3], int useFlatSubdiv)
{
float creaseFactor = (float) ccgSubSurf_getSubdivisionLevels(ss);
- CCGVertHDL fVerts[4];
+ CCGVertHDL *fVerts = NULL;
+ BLI_array_declare(fVerts);
int totvert = dm->getNumVerts(dm);
int totedge = dm->getNumEdges(dm);
- int totface = dm->getNumFaces(dm);
+ int totface = dm->getNumTessFaces(dm);
+ int totpoly = dm->getNumFaces(dm);
int i;
int *index;
MVert *mvert = dm->getVertArray(dm);
MEdge *medge = dm->getEdgeArray(dm);
- MFace *mface = dm->getFaceArray(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
MVert *mv;
MEdge *me;
MFace *mf;
+ DMFaceIter *fiter;
+ DMLoopIter *liter;
ccgSubSurf_initFullSync(ss);
@@ -466,28 +947,31 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
((int*)ccgSubSurf_getEdgeUserData(ss, e))[1] = (index)? *index++: i;
}
-
- mf = mface;
- index = (int *)dm->getFaceDataArray(dm, CD_ORIGINDEX);
- for (i = 0; i < totface; i++, mf++) {
+
+ fiter = dm->newFaceIter(dm);
+ for (i=0; !fiter->done; fiter->step(fiter), i++) {
CCGFace *f;
+ BLI_array_empty(fVerts);
- fVerts[0] = SET_INT_IN_POINTER(mf->v1);
- fVerts[1] = SET_INT_IN_POINTER(mf->v2);
- fVerts[2] = SET_INT_IN_POINTER(mf->v3);
- fVerts[3] = SET_INT_IN_POINTER(mf->v4);
+ index = (int*) fiter->getCDData(fiter, CD_ORIGINDEX, -1);
+ liter = fiter->getLoopsIter(fiter);
+
+ for (; !liter->done; liter->step(liter)) {
+ BLI_array_growone(fVerts);
+ fVerts[BLI_array_count(fVerts)-1] = SET_INT_IN_POINTER(liter->vindex);
+ }
- // this is very bad, means mesh is internally consistent.
- // it is not really possible to continue without modifying
- // other parts of code significantly to handle missing faces.
- // since this really shouldn't even be possible we just bail.
- if(ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), fVerts[3] ? 4 : 3,
+ /* this is very bad, means mesh is internally inconsistent.
+ * it is not really possible to continue without modifying
+ * other parts of code significantly to handle missing faces.
+ * since this really shouldn't even be possible we just bail.*/
+ if(ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), fiter->len,
fVerts, &f) == eCCGError_InvalidValue) {
static int hasGivenError = 0;
if(!hasGivenError) {
- //XXX error("Unrecoverable error in SubSurf calculation,"
- // " mesh is inconsistent.");
+ printf("Unrecoverable error in SubSurf calculation,"
+ " mesh is inconsistent.\n");
hasGivenError = 1;
}
@@ -497,27 +981,30 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
((int*)ccgSubSurf_getFaceUserData(ss, f))[1] = (index)? *index++: i;
}
+ fiter->free(fiter);
ccgSubSurf_processSync(ss);
+
+ BLI_array_free(fVerts);
}
/***/
-static int ccgDM_getVertMapIndex(CCGSubSurf *ss, CCGVert *v) {
+int ccgDM_getVertMapIndex(CCGSubSurf *ss, CCGVert *v) {
return ((int*) ccgSubSurf_getVertUserData(ss, v))[1];
}
-static int ccgDM_getEdgeMapIndex(CCGSubSurf *ss, CCGEdge *e) {
+int ccgDM_getEdgeMapIndex(CCGSubSurf *ss, CCGEdge *e) {
return ((int*) ccgSubSurf_getEdgeUserData(ss, e))[1];
}
-static int ccgDM_getFaceMapIndex(CCGSubSurf *ss, CCGFace *f) {
+int ccgDM_getFaceMapIndex(CCGSubSurf *ss, CCGFace *f) {
return ((int*) ccgSubSurf_getFaceUserData(ss, f))[1];
}
-static void ccgDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) {
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
CCGVertIterator *vi = ccgSubSurf_getVertIterator(ss);
CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
@@ -559,32 +1046,32 @@ static void ccgDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) {
ccgEdgeIterator_free(ei);
ccgVertIterator_free(vi);
}
-static int ccgDM_getNumVerts(DerivedMesh *dm) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+static int cgdm_getNumVerts(DerivedMesh *dm) {
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
- return ccgSubSurf_getNumFinalVerts(ccgdm->ss);
+ return ccgSubSurf_getNumFinalVerts(cgdm->ss);
}
-static int ccgDM_getNumEdges(DerivedMesh *dm) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+static int cgdm_getNumEdges(DerivedMesh *dm) {
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
- return ccgSubSurf_getNumFinalEdges(ccgdm->ss);
+ return ccgSubSurf_getNumFinalEdges(cgdm->ss);
}
-static int ccgDM_getNumFaces(DerivedMesh *dm) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+static int cgdm_getNumTessFaces(DerivedMesh *dm) {
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
- return ccgSubSurf_getNumFinalFaces(ccgdm->ss);
+ return ccgSubSurf_getNumFinalFaces(cgdm->ss);
}
static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
DMGridData *vd;
int i;
memset(mv, 0, sizeof(*mv));
- if((vertNum < ccgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumFaces(ss) > 0)) {
+ if((vertNum < cgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumFaces(ss) > 0)) {
/* this vert comes from face data */
int lastface = ccgSubSurf_getNumFaces(ss) - 1;
CCGFace *f;
@@ -597,10 +1084,10 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
int gridInternalEnd;
i = 0;
- while(i < lastface && vertNum >= ccgdm->faceMap[i + 1].startVert)
+ while(i < lastface && vertNum >= cgdm->faceMap[i + 1].startVert)
++i;
- f = ccgdm->faceMap[i].face;
+ f = cgdm->faceMap[i].face;
numVerts = ccgSubSurf_getFaceNumVerts(f);
gridSideVerts = gridSize - 2;
@@ -609,7 +1096,7 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
gridSideEnd = 1 + numVerts * gridSideVerts;
gridInternalEnd = gridSideEnd + numVerts * gridInternalVerts;
- offset = vertNum - ccgdm->faceMap[i].startVert;
+ offset = vertNum - cgdm->faceMap[i].startVert;
if(offset < 1) {
vd = ccgSubSurf_getFaceCenterData(f);
copy_v3_v3(mv->co, vd->co);
@@ -631,28 +1118,28 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
copy_v3_v3(mv->co, vd->co);
normal_float_to_short_v3(mv->no, vd->no);
}
- } else if((vertNum < ccgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
+ } else if((vertNum < cgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
/* this vert comes from edge data */
CCGEdge *e;
int lastedge = ccgSubSurf_getNumEdges(ss) - 1;
int x;
i = 0;
- while(i < lastedge && vertNum >= ccgdm->edgeMap[i + 1].startVert)
+ while(i < lastedge && vertNum >= cgdm->edgeMap[i + 1].startVert)
++i;
- e = ccgdm->edgeMap[i].edge;
+ e = cgdm->edgeMap[i].edge;
- x = vertNum - ccgdm->edgeMap[i].startVert + 1;
+ x = vertNum - cgdm->edgeMap[i].startVert + 1;
vd = ccgSubSurf_getEdgeData(ss, e, x);
copy_v3_v3(mv->co, vd->co);
normal_float_to_short_v3(mv->no, vd->no);
} else {
/* this vert comes from vert data */
CCGVert *v;
- i = vertNum - ccgdm->vertMap[0].startVert;
+ i = vertNum - cgdm->vertMap[0].startVert;
- v = ccgdm->vertMap[i].vert;
+ v = cgdm->vertMap[i].vert;
vd = ccgSubSurf_getVertData(ss, v);
copy_v3_v3(mv->co, vd->co);
normal_float_to_short_v3(mv->no, vd->no);
@@ -677,13 +1164,13 @@ static void ccgDM_getFinalVertNo(DerivedMesh *dm, int vertNum, float no_r[3])
static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
int i;
memset(med, 0, sizeof(*med));
- if(edgeNum < ccgdm->edgeMap[0].startEdge) {
+ if(edgeNum < cgdm->edgeMap[0].startEdge) {
/* this edge comes from face data */
int lastface = ccgSubSurf_getNumFaces(ss) - 1;
CCGFace *f;
@@ -695,16 +1182,16 @@ static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
int gridInternalEdges;
i = 0;
- while(i < lastface && edgeNum >= ccgdm->faceMap[i + 1].startEdge)
+ while(i < lastface && edgeNum >= cgdm->faceMap[i + 1].startEdge)
++i;
- f = ccgdm->faceMap[i].face;
+ f = cgdm->faceMap[i].face;
/* numVerts = ccgSubSurf_getFaceNumVerts(f); */ /*UNUSED*/
gridSideEdges = gridSize - 1;
gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2;
- offset = edgeNum - ccgdm->faceMap[i].startEdge;
+ offset = edgeNum - cgdm->faceMap[i].startEdge;
grid = offset / (gridSideEdges + gridInternalEdges);
offset %= (gridSideEdges + gridInternalEdges);
@@ -732,18 +1219,18 @@ static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
short *edgeFlag;
unsigned int flags = 0;
- i = (edgeNum - ccgdm->edgeMap[0].startEdge) / (edgeSize - 1);
+ i = (edgeNum - cgdm->edgeMap[0].startEdge) / (edgeSize - 1);
- e = ccgdm->edgeMap[i].edge;
+ e = cgdm->edgeMap[i].edge;
if(!ccgSubSurf_getEdgeNumFaces(e)) flags |= ME_LOOSEEDGE;
- x = edgeNum - ccgdm->edgeMap[i].startEdge;
+ x = edgeNum - cgdm->edgeMap[i].startEdge;
med->v1 = getEdgeIndex(ss, e, x, edgeSize);
med->v2 = getEdgeIndex(ss, e, x+1, edgeSize);
- edgeFlag = (ccgdm->edgeFlags)? &ccgdm->edgeFlags[i]: NULL;
+ edgeFlag = (cgdm->edgeFlags)? &cgdm->edgeFlags[i]: NULL;
if(edgeFlag)
flags |= (*edgeFlag & (ME_SEAM | ME_SHARP))
| ME_EDGEDRAW | ME_EDGERENDER;
@@ -756,8 +1243,8 @@ static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
int gridSize = ccgSubSurf_getGridSize(ss);
int edgeSize = ccgSubSurf_getEdgeSize(ss);
int gridSideEdges = gridSize - 1;
@@ -769,18 +1256,18 @@ static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf)
int grid;
int x, y;
int lastface = ccgSubSurf_getNumFaces(ss) - 1;
- char *faceFlags = ccgdm->faceFlags;
+ char *faceFlags = cgdm->faceFlags;
memset(mf, 0, sizeof(*mf));
+ if (faceNum >= cgdm->dm.numFaceData)
+ return;
- i = 0;
- while(i < lastface && faceNum >= ccgdm->faceMap[i + 1].startFace)
- ++i;
+ i = cgdm->reverseFaceMap[faceNum];
- f = ccgdm->faceMap[i].face;
+ f = cgdm->faceMap[i].face;
/*numVerts = ccgSubSurf_getFaceNumVerts(f);*/ /*UNUSED*/
- offset = faceNum - ccgdm->faceMap[i].startFace;
+ offset = faceNum - cgdm->faceMap[i].startFace;
grid = offset / gridFaces;
offset %= gridFaces;
y = offset / gridSideEdges;
@@ -800,8 +1287,8 @@ static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf)
static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
DMGridData *vd;
int index;
int totvert, totedge, totface;
@@ -811,7 +1298,7 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
totface = ccgSubSurf_getNumFaces(ss);
for(index = 0; index < totface; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
+ CCGFace *f = cgdm->faceMap[index].face;
int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
vd= ccgSubSurf_getFaceCenterData(f);
@@ -840,7 +1327,7 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
totedge = ccgSubSurf_getNumEdges(ss);
for(index = 0; index < totedge; index++) {
- CCGEdge *e = ccgdm->edgeMap[index].edge;
+ CCGEdge *e = cgdm->edgeMap[index].edge;
int x;
for(x = 1; x < edgeSize - 1; x++, i++) {
@@ -853,7 +1340,7 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
totvert = ccgSubSurf_getNumVerts(ss);
for(index = 0; index < totvert; index++) {
- CCGVert *v = ccgdm->vertMap[index].vert;
+ CCGVert *v = cgdm->vertMap[index].vert;
vd= ccgSubSurf_getVertData(ss, v);
copy_v3_v3(mvert[i].co, vd->co);
@@ -864,25 +1351,25 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
int index;
int totedge, totface;
int gridSize = ccgSubSurf_getGridSize(ss);
int edgeSize = ccgSubSurf_getEdgeSize(ss);
int i = 0;
- short *edgeFlags = ccgdm->edgeFlags;
+ short *edgeFlags = cgdm->edgeFlags;
totface = ccgSubSurf_getNumFaces(ss);
for(index = 0; index < totface; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
+ CCGFace *f = cgdm->faceMap[index].face;
int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
for(S = 0; S < numVerts; S++) {
for(x = 0; x < gridSize - 1; x++) {
MEdge *med = &medge[i];
- if(ccgdm->drawInteriorEdges)
+ if(cgdm->drawInteriorEdges)
med->flag = ME_EDGEDRAW | ME_EDGERENDER;
med->v1 = getFaceIndex(ss, f, S, x, 0, edgeSize, gridSize);
med->v2 = getFaceIndex(ss, f, S, x + 1, 0, edgeSize, gridSize);
@@ -894,7 +1381,7 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
MEdge *med;
med = &medge[i];
- if(ccgdm->drawInteriorEdges)
+ if(cgdm->drawInteriorEdges)
med->flag = ME_EDGEDRAW | ME_EDGERENDER;
med->v1 = getFaceIndex(ss, f, S, x, y,
edgeSize, gridSize);
@@ -903,7 +1390,7 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
i++;
med = &medge[i];
- if(ccgdm->drawInteriorEdges)
+ if(cgdm->drawInteriorEdges)
med->flag = ME_EDGEDRAW | ME_EDGERENDER;
med->v1 = getFaceIndex(ss, f, S, y, x,
edgeSize, gridSize);
@@ -917,7 +1404,7 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
totedge = ccgSubSurf_getNumEdges(ss);
for(index = 0; index < totedge; index++) {
- CCGEdge *e = ccgdm->edgeMap[index].edge;
+ CCGEdge *e = cgdm->edgeMap[index].edge;
unsigned int flags = 0;
int x;
int edgeIdx = GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e));
@@ -943,20 +1430,177 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
}
}
+struct cgdm_faceIter;
+
+typedef struct cgdm_loopIter {
+ DMLoopIter head;
+ int curloop;
+ int lindex; //loop index within the mesh, not the face
+ CCGDerivedMesh *cgdm;
+ struct cgdm_faceIter *fiter;
+} cgdm_loopIter;
+
+typedef struct cgdm_faceIter {
+ DMFaceIter head;
+ CCGDerivedMesh *cgdm;
+ MFace *mface, *mf;
+
+ cgdm_loopIter liter;
+ EdgeHash *ehash; /*edge map for populating loopiter->eindex*/
+} cgdm_faceIter;
+
+void cgdm_faceIterStep(void *self)
+{
+ cgdm_faceIter *fiter = self;
+
+ if (!fiter->cgdm || !fiter->cgdm->ss) {
+ fiter->head.done = 1;
+ return;
+ }
+
+ if (fiter->head.index+1 >= ccgSubSurf_getNumFinalFaces(fiter->cgdm->ss)) {
+ fiter->head.done = 1;
+ return;
+ };
+
+ fiter->head.index++;
+
+ fiter->mf++;
+
+ fiter->head.flags = fiter->mface->flag;
+ fiter->head.mat_nr = fiter->mface->mat_nr;
+ fiter->head.len = 4;
+}
+
+void *cgdm_faceIterCData(void *self, int type, int layer)
+{
+ cgdm_faceIter *fiter = self;
+
+ if (layer == -1)
+ return CustomData_get(&fiter->cgdm->dm.polyData, fiter->head.index, type);
+ else
+ return CustomData_get_n(&fiter->cgdm->dm.polyData, type, fiter->head.index, layer);
+}
+
+void cgdm_loopIterStep(void *self)
+{
+ cgdm_loopIter *liter = self;
+ MFace *mf = liter->fiter->mface;
+ int i, v1, v2;
+
+ liter->head.index++;
+ i = liter->head.index;
+
+ if (liter->head.index >= 4) {
+ liter->head.done = 1;
+ return;
+ }
+
+ switch (i) {
+ case 0:
+ v1 = liter->fiter->mf->v1;
+ v2 = liter->fiter->mf->v2;
+ break;
+ case 1:
+ v1 = liter->fiter->mf->v2;
+ v2 = liter->fiter->mf->v3;
+ break;
+ case 2:
+ v1 = liter->fiter->mf->v3;
+ v2 = liter->fiter->mf->v4;
+ break;
+ case 3:
+ v1 = liter->fiter->mf->v4;
+ v2 = liter->fiter->mf->v1;
+ break;
+ }
+
+ liter->head.vindex = v1;
+ liter->head.eindex = GET_INT_FROM_POINTER(BLI_edgehash_lookup(liter->fiter->cgdm->ehash, v1, v2));
+ liter->lindex += 1;
+
+ ccgDM_getFinalVert((DerivedMesh*)liter->cgdm, v1, &liter->head.v);
+}
+
+void *cgdm_loopIterGetVCData(void *self, int type, int layer)
+{
+ cgdm_loopIter *liter = self;
+
+ if (layer == -1)
+ return CustomData_get(&liter->cgdm->dm.vertData, liter->head.vindex, type);
+ else return CustomData_get_n(&liter->cgdm->dm.vertData, type, liter->head.vindex, layer);
+}
+
+void *cgdm_loopIterGetCData(void *self, int type, int layer)
+{
+ cgdm_loopIter *liter = self;
+
+ if (layer == -1)
+ return CustomData_get(&liter->cgdm->dm.loopData, liter->lindex, type);
+ else return CustomData_get_n(&liter->cgdm->dm.loopData, type, liter->lindex, layer);
+}
+
+DMLoopIter *cgdm_faceIterGetLIter(void *self)
+{
+ cgdm_faceIter *fiter = self;
+
+ fiter->liter.head.index = -1;
+ fiter->liter.head.done = 0;
+ fiter->liter.head.step(&fiter->liter);
+
+ return (DMLoopIter*) &fiter->liter;
+}
+
+void cgdm_faceIterFree(void *vfiter)
+{
+ cgdm_faceIter *fiter = vfiter;
+
+ MEM_freeN(fiter->mface);
+ MEM_freeN(fiter);
+}
+
+DMFaceIter *cgdm_newFaceIter(DerivedMesh *dm)
+{
+ cgdm_faceIter *fiter = MEM_callocN(sizeof(cgdm_faceIter), "cgdm_faceIter");
+ MEdge medge;
+ int i, totedge = cgdm_getNumEdges(dm);
+
+ fiter->cgdm = dm;
+ fiter->liter.cgdm = dm;
+ fiter->mface = fiter->mf = dm->dupTessFaceArray(dm);
+ fiter->mf--;
+
+ fiter->head.free = cgdm_faceIterFree;
+ fiter->head.step = cgdm_faceIterStep;
+ fiter->head.index = -1;
+ fiter->head.getCDData = cgdm_faceIterCData;
+ fiter->head.getLoopsIter = cgdm_faceIterGetLIter;
+
+ fiter->liter.fiter = fiter;
+ fiter->liter.head.getLoopCDData = cgdm_loopIterGetCData;
+ fiter->liter.head.getVertCDData = cgdm_loopIterGetVCData;
+ fiter->liter.head.step = cgdm_loopIterStep;
+ fiter->liter.lindex = -1;
+
+ fiter->head.step(fiter);
+
+ return fiter;
+}
+
static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
int index;
int totface;
int gridSize = ccgSubSurf_getGridSize(ss);
int edgeSize = ccgSubSurf_getEdgeSize(ss);
int i = 0;
- char *faceFlags = ccgdm->faceFlags;
+ char *faceFlags = cgdm->faceFlags;
totface = ccgSubSurf_getNumFaces(ss);
for(index = 0; index < totface; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
+ CCGFace *f = cgdm->faceMap[index].face;
int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
int flag = (faceFlags)? faceFlags[index*2]: ME_SMOOTH;
int mat_nr = (faceFlags)? faceFlags[index*2+1]: 0;
@@ -973,6 +1617,11 @@ static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface)
edgeSize, gridSize);
mf->v4 = getFaceIndex(ss, f, S, x + 1, y + 0,
edgeSize, gridSize);
+ if (faceFlags) {
+ mat_nr = faceFlags[index*2+1];
+ mf->flag = faceFlags[index*2];
+ } else mf->flag = flag;
+
mf->mat_nr = mat_nr;
mf->flag = flag;
@@ -983,9 +1632,9 @@ static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface)
}
}
-static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) {
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
int edgeSize = ccgSubSurf_getEdgeSize(ss);
int gridSize = ccgSubSurf_getGridSize(ss);
int i;
@@ -1066,14 +1715,14 @@ static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) {
MEM_freeN(edgeMap2);
MEM_freeN(faceMap2);
}
-static void ccgDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGVertIterator *vi = ccgSubSurf_getVertIterator(ccgdm->ss);
+static void cgdm_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData) {
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGVertIterator *vi = ccgSubSurf_getVertIterator(cgdm->ss);
for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
CCGVert *v = ccgVertIterator_getCurrent(vi);
- DMGridData *vd = ccgSubSurf_getVertData(ccgdm->ss, v);
- int index = ccgDM_getVertMapIndex(ccgdm->ss, v);
+ DMGridData *vd = ccgSubSurf_getVertData(cgdm->ss, v);
+ int index = ccgDM_getVertMapIndex(cgdm->ss, v);
if (index!=-1)
func(userData, index, vd->co, vd->no, NULL);
@@ -1081,9 +1730,9 @@ static void ccgDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData
ccgVertIterator_free(vi);
}
-static void ccgDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData) {
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
@@ -1102,8 +1751,8 @@ static void ccgDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData
}
static void ccgDM_drawVerts(DerivedMesh *dm) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
int edgeSize = ccgSubSurf_getEdgeSize(ss);
int gridSize = ccgSubSurf_getGridSize(ss);
CCGVertIterator *vi;
@@ -1230,8 +1879,8 @@ static void ccgDM_drawEdges(DerivedMesh *dm, int drawLooseEdges, int UNUSED(draw
ccgEdgeIterator_free(ei);
}
static void ccgDM_drawLooseEdges(DerivedMesh *dm) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
@@ -1252,7 +1901,7 @@ static void ccgDM_drawLooseEdges(DerivedMesh *dm) {
ccgEdgeIterator_free(ei);
}
-static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
+void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
{
float a_cX = c[0]-a[0], a_cY = c[1]-a[1], a_cZ = c[2]-a[2];
float b_dX = d[0]-b[0], b_dY = d[1]-b[1], b_dZ = d[2]-b[2];
@@ -1276,7 +1925,6 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
int step = (fast)? gridSize-1: 1;
ccgdm_pbvh_update(ccgdm);
-
if(ccgdm->pbvh && ccgdm->multires.mmd && !fast) {
if(dm->numFaceData) {
/* should be per face */
@@ -1291,6 +1939,8 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
return;
}
+ gridSize = ccgSubSurf_getGridSize(ss);
+
fi = ccgSubSurf_getFaceIterator(ss);
for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
CCGFace *f = ccgFaceIterator_getCurrent(fi);
@@ -1354,21 +2004,21 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
}
/* Only used by non-editmesh types */
-static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs), int (*setDrawOptions)(void *userData, int index), void *userData) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs), int (*setDrawOptions)(void *userData, int index), void *userData) {
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
GPUVertexAttribs gattribs;
DMVertexAttribs attribs= {{{0}}};
- MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE);
+ MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE);
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
int edgeSize = ccgSubSurf_getEdgeSize(ss);
int transp, orig_transp, new_transp;
- char *faceFlags = ccgdm->faceFlags;
+ char *faceFlags = cgdm->faceFlags;
int a, b, i, doDraw, numVerts, matnr, new_matnr, totface;
- ccgdm_pbvh_update(ccgdm);
+ ccgdm_pbvh_update(cgdm);
doDraw = 0;
matnr = -1;
@@ -1398,7 +2048,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, v
totface = ccgSubSurf_getNumFaces(ss);
for(a = 0, i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
+ CCGFace *f = cgdm->faceMap[i].face;
int S, x, y, drawSmooth;
int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f));
int origIndex = ccgDM_getFaceMapIndex(ss, f);
@@ -1509,19 +2159,19 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, v
ccgFaceIterator_free(fi);
}
-static void ccgDM_drawFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs)) {
+static void cgdm_drawFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs)) {
dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
}
-static void ccgDM_drawFacesColored(DerivedMesh *dm, int UNUSED(useTwoSided), unsigned char *col1, unsigned char *col2) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2) {
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
int gridSize = ccgSubSurf_getGridSize(ss);
unsigned char *cp1, *cp2;
int useTwoSide=1;
- ccgdm_pbvh_update(ccgdm);
+ ccgdm_pbvh_update(cgdm);
cp1= col1;
if(col2) {
@@ -1580,27 +2230,27 @@ static void ccgDM_drawFacesColored(DerivedMesh *dm, int UNUSED(useTwoSided), uns
ccgFaceIterator_free(fi);
}
-static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
- int (*drawParams)(MTFace *tface, MCol *mcol, int matnr),
+static void cgdm_drawFacesTex_common(DerivedMesh *dm,
+ int (*drawParams)(MTFace *tface, int has_vcol, int matnr),
int (*drawParamsMapped)(void *userData, int index),
void *userData)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
- MCol *mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL);
- MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
- char *faceFlags = ccgdm->faceFlags;
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
+ MCol *mcol = dm->getTessFaceDataArray(dm, CD_WEIGHT_MCOL);
+ MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
+ char *faceFlags = cgdm->faceFlags;
int i, totface, flag, gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
- ccgdm_pbvh_update(ccgdm);
+ ccgdm_pbvh_update(cgdm);
if(!mcol)
- mcol = dm->getFaceDataArray(dm, CD_MCOL);
+ mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
totface = ccgSubSurf_getNumFaces(ss);
for(i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
+ CCGFace *f = cgdm->faceMap[i].face;
int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
int drawSmooth, index = ccgDM_getFaceMapIndex(ss, f);
int origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f));
@@ -1617,7 +2267,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
}
if(drawParams)
- flag = drawParams(tf, mcol, mat_nr);
+ flag = drawParams(tf, mcol!=NULL, mat_nr);
else if (index != ORIGINDEX_NONE)
flag= (drawParamsMapped)? drawParamsMapped(userData, index): 1;
else
@@ -1720,21 +2370,21 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
}
}
-static void ccgDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
+static void cgdm_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr))
{
- ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
+ cgdm_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
}
-static void ccgDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+static void cgdm_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
{
- ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
+ cgdm_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
}
-static void ccgDM_drawUVEdges(DerivedMesh *dm)
+static void cgdm_drawUVEdges(DerivedMesh *dm)
{
- MFace *mf = dm->getFaceArray(dm);
- MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
+ MFace *mf = dm->getTessFaceArray(dm);
+ MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
int i;
if (tf) {
@@ -1764,22 +2414,22 @@ static void ccgDM_drawUVEdges(DerivedMesh *dm)
}
static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, int (*setMaterial)(int, void *attribs)) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
MCol *mcol= NULL;
int i, gridSize = ccgSubSurf_getGridSize(ss);
- char *faceFlags = ccgdm->faceFlags;
+ char *faceFlags = cgdm->faceFlags;
int gridFaces = gridSize - 1, totface;
if(useColors) {
- mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL);
+ mcol = dm->getTessFaceDataArray(dm, CD_WEIGHT_MCOL);
if(!mcol)
- mcol = dm->getFaceDataArray(dm, CD_MCOL);
+ mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
}
totface = ccgSubSurf_getNumFaces(ss);
for(i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
+ CCGFace *f = cgdm->faceMap[i].face;
int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
int drawSmooth, index = ccgDM_getFaceMapIndex(ss, f);
int origIndex;
@@ -1879,9 +2529,9 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *u
}
}
}
-static void ccgDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) {
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
@@ -1909,9 +2559,9 @@ static void ccgDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *u
ccgEdgeIterator_free(ei);
}
-static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData) {
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
@@ -1940,9 +2590,9 @@ static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(v
ccgEdgeIterator_free(ei);
}
-static void ccgDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData) {
+ CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = cgdm->ss;
CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
@@ -1960,7 +2610,7 @@ static void ccgDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *us
ccgFaceIterator_free(fi);
}
-static void ccgDM_release(DerivedMesh *dm) {
+static void cgdm_release(DerivedMesh *dm) {
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
if (DM_release(dm)) {
@@ -1973,6 +2623,10 @@ static void ccgDM_release(DerivedMesh *dm) {
ccgdm->multires.update(dm);
}
+ if (ccgdm->ehash)
+ BLI_edgehash_free(ccgdm->ehash, NULL);
+
+ if(ccgdm->reverseFaceMap) MEM_freeN(ccgdm->reverseFaceMap);
if(ccgdm->gridFaces) MEM_freeN(ccgdm->gridFaces);
if(ccgdm->gridData) MEM_freeN(ccgdm->gridData);
if(ccgdm->gridAdjacency) MEM_freeN(ccgdm->gridAdjacency);
@@ -1989,12 +2643,66 @@ static void ccgDM_release(DerivedMesh *dm) {
}
}
+void ccg_loops_to_corners(CustomData *fdata, CustomData *ldata,
+ CustomData *pdata, int loopstart, int findex,
+ int polyindex, int numTex, int numCol)
+{
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ int i, j, hasWCol = CustomData_has_layer(ldata, CD_WEIGHT_MLOOPCOL);
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
+ texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i);
+
+ texface->tpage = texpoly->tpage;
+ texface->flag = texpoly->flag;
+ texface->transp = texpoly->transp;
+ texface->mode = texpoly->mode;
+ texface->tile = texpoly->tile;
+ texface->unwrap = texpoly->unwrap;
+
+ mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i);
+ for (j=0; j<4; j++, mloopuv++) {
+ texface->uv[j][0] = mloopuv->uv[0];
+ texface->uv[j][1] = mloopuv->uv[1];
+ }
+ }
+
+ for(i=0; i < numCol; i++){
+ mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, loopstart, i);
+ mcol = CustomData_get_n(fdata, CD_MCOL, findex, i);
+
+ for (j=0; j<4; j++, mloopcol++) {
+ mcol[j].r = mloopcol->r;
+ mcol[j].g = mloopcol->g;
+ mcol[j].b = mloopcol->b;
+ mcol[j].a = mloopcol->a;
+ }
+ }
+
+ if (hasWCol) {
+ mloopcol = CustomData_get(ldata, loopstart, CD_WEIGHT_MLOOPCOL);
+ mcol = CustomData_get(fdata, findex, CD_WEIGHT_MCOL);
+
+ for (j=0; j<4; j++, mloopcol++) {
+ mcol[j].r = mloopcol->r;
+ mcol[j].g = mloopcol->g;
+ mcol[j].b = mloopcol->b;
+ mcol[j].a = mloopcol->a;
+ }
+ }
+}
+
static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type)
{
if(type == CD_ORIGINDEX) {
/* create origindex on demand to save memory */
- CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
- CCGSubSurf *ss= ccgdm->ss;
+ CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
+ CCGSubSurf *ss= cgdm->ss;
int *origindex;
int a, index, totnone, totorig;
@@ -2009,8 +2717,8 @@ static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type)
origindex[a]= ORIGINDEX_NONE;
for(index=0; index<totorig; index++, a++) {
- CCGVert *v = ccgdm->vertMap[index].vert;
- origindex[a] = ccgDM_getVertMapIndex(ccgdm->ss, v);
+ CCGVert *v = cgdm->vertMap[index].vert;
+ origindex[a] = ccgDM_getVertMapIndex(cgdm->ss, v);
}
return origindex;
@@ -2023,8 +2731,8 @@ static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type)
{
if(type == CD_ORIGINDEX) {
/* create origindex on demand to save memory */
- CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
- CCGSubSurf *ss= ccgdm->ss;
+ CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
+ CCGSubSurf *ss= cgdm->ss;
int *origindex;
int a, i, index, totnone, totorig, totedge;
int edgeSize= ccgSubSurf_getEdgeSize(ss);
@@ -2041,7 +2749,7 @@ static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type)
origindex[a]= ORIGINDEX_NONE;
for(index=0; index<totedge; index++) {
- CCGEdge *e= ccgdm->edgeMap[index].edge;
+ CCGEdge *e= cgdm->edgeMap[index].edge;
int mapIndex= ccgDM_getEdgeMapIndex(ss, e);
for(i = 0; i < edgeSize - 1; i++, a++)
@@ -2058,19 +2766,19 @@ static void *ccgDM_get_face_data_layer(DerivedMesh *dm, int type)
{
if(type == CD_ORIGINDEX) {
/* create origindex on demand to save memory */
- CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
- CCGSubSurf *ss= ccgdm->ss;
+ CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
+ CCGSubSurf *ss= cgdm->ss;
int *origindex;
int a, i, index, totface;
int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
DM_add_face_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
- origindex= DM_get_face_data_layer(dm, CD_ORIGINDEX);
+ origindex= DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
totface= ccgSubSurf_getNumFaces(ss);
for(a=0, index=0; index<totface; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
+ CCGFace *f = cgdm->faceMap[index].face;
int numVerts = ccgSubSurf_getFaceNumVerts(f);
int mapIndex = ccgDM_getFaceMapIndex(ss, f);
@@ -2081,19 +2789,19 @@ static void *ccgDM_get_face_data_layer(DerivedMesh *dm, int type)
return origindex;
}
- return DM_get_face_data_layer(dm, type);
+ return DM_get_tessface_data_layer(dm, type);
}
static int ccgDM_getNumGrids(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
+ CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
int index, numFaces, numGrids;
- numFaces= ccgSubSurf_getNumFaces(ccgdm->ss);
+ numFaces= ccgSubSurf_getNumFaces(cgdm->ss);
numGrids= 0;
for(index=0; index<numFaces; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
+ CCGFace *f = cgdm->faceMap[index].face;
numGrids += ccgSubSurf_getFaceNumVerts(f);
}
@@ -2102,11 +2810,11 @@ static int ccgDM_getNumGrids(DerivedMesh *dm)
static int ccgDM_getGridSize(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
- return ccgSubSurf_getGridSize(ccgdm->ss);
+ CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
+ return ccgSubSurf_getGridSize(cgdm->ss);
}
-static int ccgdm_adjacent_grid(CCGSubSurf *ss, int *gridOffset, CCGFace *f, int S, int offset)
+static int cgdm_adjacent_grid(CCGSubSurf *ss, int *gridOffset, CCGFace *f, int S, int offset)
{
CCGFace *adjf;
CCGEdge *e;
@@ -2139,15 +2847,15 @@ static int ccgdm_adjacent_grid(CCGSubSurf *ss, int *gridOffset, CCGFace *f, int
static void ccgdm_create_grids(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
- CCGSubSurf *ss= ccgdm->ss;
+ CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
+ CCGSubSurf *ss= cgdm->ss;
DMGridData **gridData;
DMGridAdjacency *gridAdjacency, *adj;
CCGFace **gridFaces;
int *gridOffset;
int index, numFaces, numGrids, S, gIndex /*, gridSize*/;
- if(ccgdm->gridData)
+ if(cgdm->gridData)
return;
numGrids = ccgDM_getNumGrids(dm);
@@ -2155,10 +2863,10 @@ static void ccgdm_create_grids(DerivedMesh *dm)
/*gridSize = ccgDM_getGridSize(dm);*/ /*UNUSED*/
/* compute offset into grid array for each face */
- gridOffset = MEM_mallocN(sizeof(int)*numFaces, "ccgdm.gridOffset");
+ gridOffset = MEM_mallocN(sizeof(int)*numFaces, "cgdm.gridOffset");
for(gIndex = 0, index = 0; index < numFaces; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
+ CCGFace *f = cgdm->faceMap[index].face;
int numVerts = ccgSubSurf_getFaceNumVerts(f);
gridOffset[index] = gIndex;
@@ -2166,12 +2874,12 @@ static void ccgdm_create_grids(DerivedMesh *dm)
}
/* compute grid data */
- gridData = MEM_mallocN(sizeof(DMGridData*)*numGrids, "ccgdm.gridData");
- gridAdjacency = MEM_mallocN(sizeof(DMGridAdjacency)*numGrids, "ccgdm.gridAdjacency");
- gridFaces = MEM_mallocN(sizeof(CCGFace*)*numGrids, "ccgdm.gridFaces");
+ gridData = MEM_mallocN(sizeof(DMGridData*)*numGrids, "cgdm.gridData");
+ gridAdjacency = MEM_mallocN(sizeof(DMGridAdjacency)*numGrids, "cgdm.gridAdjacency");
+ gridFaces = MEM_mallocN(sizeof(CCGFace*)*numGrids, "cgdm.gridFaces");
for(gIndex = 0, index = 0; index < numFaces; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
+ CCGFace *f = cgdm->faceMap[index].face;
int numVerts = ccgSubSurf_getFaceNumVerts(f);
for(S = 0; S < numVerts; S++, gIndex++) {
@@ -2185,43 +2893,43 @@ static void ccgdm_create_grids(DerivedMesh *dm)
adj->index[0] = gIndex - S + nextS;
adj->rotation[0] = 3;
- adj->index[1] = ccgdm_adjacent_grid(ss, gridOffset, f, prevS, 0);
+ adj->index[1] = cgdm_adjacent_grid(ss, gridOffset, f, prevS, 0);
adj->rotation[1] = 1;
- adj->index[2] = ccgdm_adjacent_grid(ss, gridOffset, f, S, 1);
+ adj->index[2] = cgdm_adjacent_grid(ss, gridOffset, f, S, 1);
adj->rotation[2] = 3;
adj->index[3] = gIndex - S + prevS;
adj->rotation[3] = 1;
}
}
- ccgdm->gridData = gridData;
- ccgdm->gridFaces = gridFaces;
- ccgdm->gridAdjacency = gridAdjacency;
- ccgdm->gridOffset = gridOffset;
+ cgdm->gridData = gridData;
+ cgdm->gridFaces = gridFaces;
+ cgdm->gridAdjacency = gridAdjacency;
+ cgdm->gridOffset = gridOffset;
}
static DMGridData **ccgDM_getGridData(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
+ CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
ccgdm_create_grids(dm);
- return ccgdm->gridData;
+ return cgdm->gridData;
}
static DMGridAdjacency *ccgDM_getGridAdjacency(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
+ CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
ccgdm_create_grids(dm);
- return ccgdm->gridAdjacency;
+ return cgdm->gridAdjacency;
}
static int *ccgDM_getGridOffset(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
+ CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
ccgdm_create_grids(dm);
- return ccgdm->gridOffset;
+ return cgdm->gridOffset;
}
static ListBase *ccgDM_getFaceMap(Object *ob, DerivedMesh *dm)
@@ -2285,50 +2993,73 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
int useSubsurfUv,
DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm");
+ CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "cgdm");
CCGVertIterator *vi;
CCGEdgeIterator *ei;
CCGFaceIterator *fi;
int index, totvert, totedge, totface;
int i;
int vertNum, edgeNum, faceNum;
+ int *vertOrigIndex, *faceOrigIndex, *polyOrigIndex; /* *edgeOrigIndex - as yet, unused */
short *edgeFlags;
char *faceFlags;
- int edgeSize;
+ int *loopidx = NULL, *vertidx = NULL;
+ BLI_array_declare(loopidx);
+ BLI_array_declare(vertidx);
+ int loopindex, loopindex2;
+ int edgeSize, has_edge_origindex;
int gridSize;
- int gridFaces;
+ int gridFaces, gridCuts;
/*int gridSideVerts;*/
int gridSideEdges;
+ int numTex, numCol;
int gridInternalEdges;
- MEdge *medge = NULL;
+ float *w = NULL;
+ WeightTable wtable = {0};
+ MCol *mcol;
+ MEdge *medge = NULL, medge2;
MFace *mface = NULL;
- int *orig_indices;
- FaceVertWeight *qweight, *tweight;
+ MPoly *mpoly = NULL;
DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM,
ccgSubSurf_getNumFinalVerts(ss),
ccgSubSurf_getNumFinalEdges(ss),
+ ccgSubSurf_getNumFinalFaces(ss),
+ ccgSubSurf_getNumFinalFaces(ss)*4,
ccgSubSurf_getNumFinalFaces(ss));
+
+ numTex = CustomData_number_of_layers(&ccgdm->dm.loopData, CD_MLOOPUV);
+ numCol = CustomData_number_of_layers(&ccgdm->dm.loopData, CD_MLOOPCOL);
+
+ if (numTex && CustomData_number_of_layers(&ccgdm->dm.faceData, CD_MTFACE) != numTex)
+ CustomData_from_bmeshpoly(&ccgdm->dm.faceData, &ccgdm->dm.polyData, &ccgdm->dm.loopData, ccgSubSurf_getNumFinalFaces(ss));
+ else if (numCol && CustomData_number_of_layers(&ccgdm->dm.faceData, CD_MCOL) != numCol)
+ CustomData_from_bmeshpoly(&ccgdm->dm.faceData, &ccgdm->dm.polyData, &ccgdm->dm.loopData, ccgSubSurf_getNumFinalFaces(ss));
+
+ ccgdm->dm.getMinMax = cgdm_getMinMax;
+ ccgdm->dm.getNumVerts = cgdm_getNumVerts;
+ ccgdm->dm.getNumEdges = cgdm_getNumEdges;
+ ccgdm->dm.getNumTessFaces = cgdm_getNumTessFaces;
+ ccgdm->dm.getNumFaces = cgdm_getNumTessFaces;
- ccgdm->dm.getMinMax = ccgDM_getMinMax;
- ccgdm->dm.getNumVerts = ccgDM_getNumVerts;
- ccgdm->dm.getNumFaces = ccgDM_getNumFaces;
+ ccgdm->dm.getNumGrids = ccgDM_getNumGrids;
+ ccgdm->dm.getPBVH = ccgDM_getPBVH;
- ccgdm->dm.getNumEdges = ccgDM_getNumEdges;
+ ccgdm->dm.newFaceIter = cgdm_newFaceIter;
ccgdm->dm.getVert = ccgDM_getFinalVert;
ccgdm->dm.getEdge = ccgDM_getFinalEdge;
- ccgdm->dm.getFace = ccgDM_getFinalFace;
+ ccgdm->dm.getTessFace = ccgDM_getFinalFace;
ccgdm->dm.getVertCo = ccgDM_getFinalVertCo;
ccgdm->dm.getVertNo = ccgDM_getFinalVertNo;
ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray;
ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray;
- ccgdm->dm.copyFaceArray = ccgDM_copyFinalFaceArray;
+ ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray;
ccgdm->dm.getVertData = DM_get_vert_data;
ccgdm->dm.getEdgeData = DM_get_edge_data;
- ccgdm->dm.getFaceData = DM_get_face_data;
+ ccgdm->dm.getTessFaceData = DM_get_face_data;
ccgdm->dm.getVertDataArray = ccgDM_get_vert_data_layer;
ccgdm->dm.getEdgeDataArray = ccgDM_get_edge_data_layer;
- ccgdm->dm.getFaceDataArray = ccgDM_get_face_data_layer;
+ ccgdm->dm.getTessFaceDataArray = ccgDM_get_face_data_layer;
ccgdm->dm.getNumGrids = ccgDM_getNumGrids;
ccgdm->dm.getGridSize = ccgDM_getGridSize;
ccgdm->dm.getGridData = ccgDM_getGridData;
@@ -2337,27 +3068,38 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->dm.getFaceMap = ccgDM_getFaceMap;
ccgdm->dm.getPBVH = ccgDM_getPBVH;
- ccgdm->dm.getVertCos = ccgdm_getVertCos;
- ccgdm->dm.foreachMappedVert = ccgDM_foreachMappedVert;
- ccgdm->dm.foreachMappedEdge = ccgDM_foreachMappedEdge;
- ccgdm->dm.foreachMappedFaceCenter = ccgDM_foreachMappedFaceCenter;
+ ccgdm->dm.getTessFace = ccgDM_getFinalFace;
+ ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray;
+ ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray;
+ ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray;
+ ccgdm->dm.getVertData = DM_get_vert_data;
+ ccgdm->dm.getEdgeData = DM_get_edge_data;
+ ccgdm->dm.getTessFaceData = DM_get_face_data;
+ ccgdm->dm.getVertDataArray = DM_get_vert_data_layer;
+ ccgdm->dm.getEdgeDataArray = DM_get_edge_data_layer;
+ ccgdm->dm.getTessFaceDataArray = DM_get_tessface_data_layer;
+
+ ccgdm->dm.getVertCos = cgdm_getVertCos;
+ ccgdm->dm.foreachMappedVert = cgdm_foreachMappedVert;
+ ccgdm->dm.foreachMappedEdge = cgdm_foreachMappedEdge;
+ ccgdm->dm.foreachMappedFaceCenter = cgdm_foreachMappedFaceCenter;
ccgdm->dm.drawVerts = ccgDM_drawVerts;
ccgdm->dm.drawEdges = ccgDM_drawEdges;
ccgdm->dm.drawLooseEdges = ccgDM_drawLooseEdges;
ccgdm->dm.drawFacesSolid = ccgDM_drawFacesSolid;
- ccgdm->dm.drawFacesColored = ccgDM_drawFacesColored;
- ccgdm->dm.drawFacesTex = ccgDM_drawFacesTex;
- ccgdm->dm.drawFacesGLSL = ccgDM_drawFacesGLSL;
+ ccgdm->dm.drawFacesColored = cgdm_drawFacesColored;
+ ccgdm->dm.drawFacesTex = cgdm_drawFacesTex;
+ ccgdm->dm.drawFacesGLSL = cgdm_drawFacesGLSL;
ccgdm->dm.drawMappedFaces = ccgDM_drawMappedFaces;
- ccgdm->dm.drawMappedFacesTex = ccgDM_drawMappedFacesTex;
- ccgdm->dm.drawMappedFacesGLSL = ccgDM_drawMappedFacesGLSL;
- ccgdm->dm.drawUVEdges = ccgDM_drawUVEdges;
+ ccgdm->dm.drawMappedFacesTex = cgdm_drawMappedFacesTex;
+ ccgdm->dm.drawMappedFacesGLSL = cgdm_drawMappedFacesGLSL;
+ ccgdm->dm.drawUVEdges = cgdm_drawUVEdges;
- ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp;
- ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges;
+ ccgdm->dm.drawMappedEdgesInterp = cgdm_drawMappedEdgesInterp;
+ ccgdm->dm.drawMappedEdges = cgdm_drawMappedEdges;
- ccgdm->dm.release = ccgDM_release;
+ ccgdm->dm.release = cgdm_release;
ccgdm->ss = ss;
ccgdm->drawInteriorEdges = drawInteriorEdges;
@@ -2392,139 +3134,186 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
}
ccgFaceIterator_free(fi);
+ ccgdm->reverseFaceMap = MEM_callocN(sizeof(int)*ccgSubSurf_getNumFinalFaces(ss), "reverseFaceMap");
+
edgeSize = ccgSubSurf_getEdgeSize(ss);
gridSize = ccgSubSurf_getGridSize(ss);
gridFaces = gridSize - 1;
- /*gridSideVerts = gridSize - 2;*/ /*UNUSED*/
- /*gridInternalVerts = gridSideVerts * gridSideVerts; */ /*UNUSED*/
+ gridCuts = gridSize - 2;
+ /*gridInternalVerts = gridSideVerts * gridSideVerts; - as yet, unused */
gridSideEdges = gridSize - 1;
gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2;
- calc_ss_weights(gridFaces, &qweight, &tweight);
-
vertNum = 0;
edgeNum = 0;
faceNum = 0;
/* mvert = dm->getVertArray(dm); - as yet unused */
medge = dm->getEdgeArray(dm);
- mface = dm->getFaceArray(dm);
+ mface = dm->getTessFaceArray(dm);
+ mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
+ /*CDDM hack*/
+ edgeFlags = ccgdm->edgeFlags = MEM_callocN(sizeof(short)*totedge, "faceFlags");
faceFlags = ccgdm->faceFlags = MEM_callocN(sizeof(char)*2*totface, "faceFlags");
- orig_indices = (int*)ccgdm->dm.getFaceDataArray(&ccgdm->dm, CD_ORIGINDEX);
- for(index = 0; index < totface; ++index) {
+ vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+ /*edgeOrigIndex = DM_get_edge_data_layer(&cgdm->dm, CD_ORIGINDEX);*/
+ faceOrigIndex = DM_get_tessface_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+
+ polyOrigIndex = DM_get_face_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+
+ if (!CustomData_has_layer(&ccgdm->dm.faceData, CD_MCOL))
+ DM_add_tessface_layer(&ccgdm->dm, CD_MCOL, CD_CALLOC, NULL);
+
+ mcol = DM_get_tessface_data_layer(&ccgdm->dm, CD_MCOL);
+ has_edge_origindex = CustomData_has_layer(&ccgdm->dm.edgeData, CD_ORIGINDEX);
+
+ faceNum = 0;
+ loopindex = loopindex2 = 0; //current loop index
+ for (index = 0; index < totface; index++) {
CCGFace *f = ccgdm->faceMap[index].face;
int numVerts = ccgSubSurf_getFaceNumVerts(f);
int numFinalEdges = numVerts * (gridSideEdges + gridInternalEdges);
int origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f));
- FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight;
- int S, x, y;
- int vertIdx[4];
+ int g2_wid = gridCuts+2;
+ float *w2;
+ int s, x, y;
+
+ w = get_ss_weights(&wtable, gridCuts, numVerts);
ccgdm->faceMap[index].startVert = vertNum;
ccgdm->faceMap[index].startEdge = edgeNum;
ccgdm->faceMap[index].startFace = faceNum;
-
- if(orig_indices)
- orig_indices[faceNum] = origIndex;
+
+ faceFlags[0] = mpoly[origIndex].flag;
+ faceFlags[1] = mpoly[origIndex].mat_nr;
+ faceFlags += 2;
/* set the face base vert */
*((int*)ccgSubSurf_getFaceUserData(ss, f)) = vertNum;
- for(S = 0; S < numVerts; S++) {
- CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S);
+ BLI_array_empty(loopidx);
+ for (s=0; s<numVerts; s++) {
+ BLI_array_growone(loopidx);
+ loopidx[s] = loopindex++;
+ }
+
+ BLI_array_empty(vertidx);
+ for(s = 0; s < numVerts; s++) {
+ CCGVert *v = ccgSubSurf_getFaceVert(ss, f, s);
+
+ BLI_array_growone(vertidx);
+ vertidx[s] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
+ }
+
- vertIdx[S] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
+ /*I think this is for interpolating the center vert?*/
+ w2 = w; // + numVerts*(g2_wid-1)*(g2_wid-1); //numVerts*((g2_wid-1)*g2_wid+g2_wid-1);
+ DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2,
+ numVerts, vertNum);
+ if (vertOrigIndex) {
+ *vertOrigIndex = ORIGINDEX_NONE;
+ ++vertOrigIndex;
}
- DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, weight[0][0],
- numVerts, vertNum);
++vertNum;
- for(S = 0; S < numVerts; S++) {
- int prevS = (S - 1 + numVerts) % numVerts;
- int nextS = (S + 1) % numVerts;
- int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
+ /*interpolate per-vert data*/
+ for(s = 0; s < numVerts; s++) {
for(x = 1; x < gridFaces; x++) {
- float w[4];
- w[prevS] = weight[x][0][0];
- w[S] = weight[x][0][1];
- w[nextS] = weight[x][0][2];
- w[otherS] = weight[x][0][3];
- DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w,
- numVerts, vertNum);
+ w2 = w + s*numVerts*g2_wid*g2_wid + x*numVerts;
+ DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2,
+ numVerts, vertNum);
+
+ if (vertOrigIndex) {
+ *vertOrigIndex = ORIGINDEX_NONE;
+ ++vertOrigIndex;
+ }
+
++vertNum;
}
}
- for(S = 0; S < numVerts; S++) {
- int prevS = (S - 1 + numVerts) % numVerts;
- int nextS = (S + 1) % numVerts;
- int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
+ /*interpolate per-vert data*/
+ for(s = 0; s < numVerts; s++) {
for(y = 1; y < gridFaces; y++) {
for(x = 1; x < gridFaces; x++) {
- float w[4];
- w[prevS] = weight[y * gridFaces + x][0][0];
- w[S] = weight[y * gridFaces + x][0][1];
- w[nextS] = weight[y * gridFaces + x][0][2];
- w[otherS] = weight[y * gridFaces + x][0][3];
- DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w,
- numVerts, vertNum);
+ w2 = w + s*numVerts*g2_wid*g2_wid + (y*g2_wid+x)*numVerts;
+ DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2,
+ numVerts, vertNum);
+
+ if (vertOrigIndex) {
+ *vertOrigIndex = ORIGINDEX_NONE;
+ ++vertOrigIndex;
+ }
+
++vertNum;
}
}
}
- for(S = 0; S < numVerts; S++) {
- int prevS = (S - 1 + numVerts) % numVerts;
- int nextS = (S + 1) % numVerts;
- int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
-
- weight = (numVerts == 4) ? qweight : tweight;
-
- for(y = 0; y < gridFaces; y++) {
- for(x = 0; x < gridFaces; x++) {
- FaceVertWeight w;
- int j;
-
- for(j = 0; j < 4; ++j) {
- w[j][prevS] = (*weight)[j][0];
- w[j][S] = (*weight)[j][1];
- w[j][nextS] = (*weight)[j][2];
- w[j][otherS] = (*weight)[j][3];
+ if (has_edge_origindex) {
+ for(i = 0; i < numFinalEdges; ++i)
+ *(int *)DM_get_edge_data(&ccgdm->dm, edgeNum + i,
+ CD_ORIGINDEX) = ORIGINDEX_NONE;
+ }
+
+ for (s=0; s<numVerts; s++) {
+ /*interpolate per-face data*/
+ for (y=0; y<gridFaces; y++) {
+ for (x=0; x<gridFaces; x++) {
+ w2 = w + s*numVerts*g2_wid*g2_wid + (y*g2_wid+x)*numVerts;
+ CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
+ loopidx, w2, NULL, numVerts, loopindex2);
+ loopindex2++;
+
+ w2 = w + s*numVerts*g2_wid*g2_wid + ((y+1)*g2_wid+(x))*numVerts;
+ CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
+ loopidx, w2, NULL, numVerts, loopindex2);
+ loopindex2++;
+
+ w2 = w + s*numVerts*g2_wid*g2_wid + ((y+1)*g2_wid+(x+1))*numVerts;
+ CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
+ loopidx, w2, NULL, numVerts, loopindex2);
+ loopindex2++;
+
+ w2 = w + s*numVerts*g2_wid*g2_wid + ((y)*g2_wid+(x+1))*numVerts;
+ CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
+ loopidx, w2, NULL, numVerts, loopindex2);
+ loopindex2++;
+
+ /*copy over poly data, e.g. mtexpoly*/
+ CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, origIndex, faceNum, 1);
+
+ /*generate tesselated face data used for drawing*/
+ ccg_loops_to_corners(&ccgdm->dm.faceData, &ccgdm->dm.loopData,
+ &ccgdm->dm.polyData, loopindex2-4, faceNum, faceNum, numTex, numCol);
+
+ /*set original index data*/
+ if (faceOrigIndex) {
+ *faceOrigIndex = origIndex;
+ faceOrigIndex++;
+ }
+ if (polyOrigIndex) {
+ *polyOrigIndex = origIndex;
+ polyOrigIndex++;
}
- DM_interp_face_data(dm, &ccgdm->dm, &origIndex, NULL,
- &w, 1, faceNum);
- weight++;
+ ccgdm->reverseFaceMap[faceNum] = index;
- ++faceNum;
+ faceNum++;
}
}
}
- faceFlags[index*2] = mface[origIndex].flag;
- faceFlags[index*2 + 1] = mface[origIndex].mat_nr;
-
edgeNum += numFinalEdges;
}
- if(useSubsurfUv) {
- CustomData *fdata = &ccgdm->dm.faceData;
- CustomData *dmfdata = &dm->faceData;
- int numlayer = CustomData_number_of_layers(fdata, CD_MTFACE);
- int dmnumlayer = CustomData_number_of_layers(dmfdata, CD_MTFACE);
-
- for (i=0; i<numlayer && i<dmnumlayer; i++)
- set_subsurf_uv(ss, dm, &ccgdm->dm, i);
- }
-
- edgeFlags = ccgdm->edgeFlags = MEM_callocN(sizeof(short)*totedge, "edgeFlags");
-
for(index = 0; index < totedge; ++index) {
CCGEdge *e = ccgdm->edgeMap[index].edge;
int numFinalEdges = edgeSize - 1;
+ int mapIndex = ccgDM_getEdgeMapIndex(ss, e);
int x;
int vertIdx[2];
int edgeIdx = GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e));
@@ -2538,6 +3327,9 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->edgeMap[index].startVert = vertNum;
ccgdm->edgeMap[index].startEdge = edgeNum;
+ if(edgeIdx >= 0 && edgeFlags)
+ edgeFlags[edgeIdx] = medge[edgeIdx].flag;
+
/* set the edge base vert */
*((int*)ccgSubSurf_getEdgeUserData(ss, e)) = vertNum;
@@ -2546,32 +3338,59 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
w[1] = (float) x / (edgeSize - 1);
w[0] = 1 - w[1];
DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w, 2, vertNum);
+ if (vertOrigIndex) {
+ *vertOrigIndex = ORIGINDEX_NONE;
+ ++vertOrigIndex;
+ }
++vertNum;
}
- edgeFlags[index]= medge[edgeIdx].flag;
+ for(i = 0; i < numFinalEdges; ++i) {
+ if (has_edge_origindex) {
+ *(int *)DM_get_edge_data(&ccgdm->dm, edgeNum + i,
+ CD_ORIGINDEX) = mapIndex;
+ }
+ }
edgeNum += numFinalEdges;
}
for(index = 0; index < totvert; ++index) {
CCGVert *v = ccgdm->vertMap[index].vert;
- int vertIdx;
+ int mapIndex = ccgDM_getVertMapIndex(ccgdm->ss, v);
+ int vidx;
- vertIdx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
+ vidx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
ccgdm->vertMap[index].startVert = vertNum;
/* set the vert base vert */
*((int*) ccgSubSurf_getVertUserData(ss, v)) = vertNum;
- DM_copy_vert_data(dm, &ccgdm->dm, vertIdx, vertNum, 1);
+ DM_copy_vert_data(dm, &ccgdm->dm, vidx, vertNum, 1);
+ if (vertOrigIndex) {
+ *vertOrigIndex = mapIndex;
+ ++vertOrigIndex;
+ }
++vertNum;
}
- MEM_freeN(qweight);
- MEM_freeN(tweight);
+ ccgdm->dm.numVertData = vertNum;
+ ccgdm->dm.numEdgeData = edgeNum;
+ ccgdm->dm.numFaceData = faceNum;
+ ccgdm->dm.numLoopData = loopindex2;
+ ccgdm->dm.numPolyData = faceNum;
+
+ BLI_array_free(vertidx);
+ BLI_array_free(loopidx);
+ free_ss_weights(&wtable);
+
+ ccgdm->ehash = BLI_edgehash_new();
+ for (i=0; i<ccgdm->dm.numEdgeData; i++) {
+ ccgDM_getFinalEdge((DerivedMesh*)ccgdm, i, &medge2);
+ BLI_edgehash_insert(ccgdm->ehash, medge2.v1, medge2.v2, SET_INT_IN_POINTER(i));
+ }
return ccgdm;
}
@@ -2588,7 +3407,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
int useAging = smd->flags & eSubsurfModifierFlag_DebugIncr;
int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv;
int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
- CCGDerivedMesh *result;
+ CCGDerivedMesh *result = NULL;
if(editMode) {
int levels= (smd->modifier.scene)? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels): smd->levels;
@@ -2617,7 +3436,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
result->freeSS = 1;
} else {
- int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental);
+ int useIncremental = 1; //(smd->flags & eSubsurfModifierFlag_Incremental);
int useAging = smd->flags & eSubsurfModifierFlag_DebugIncr;
int levels= (smd->modifier.scene)? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels): smd->levels;
CCGSubSurf *ss;
@@ -2661,8 +3480,8 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
result->freeSS = 1;
}
}
-
- return (DerivedMesh*)result;
+
+ return result;
}
void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3])
diff --git a/source/blender/blenkernel/intern/verse_bitmap_node.c b/source/blender/blenkernel/intern/verse_bitmap_node.c
new file mode 100644
index 00000000000..d27f7a13f02
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_bitmap_node.c
@@ -0,0 +1,451 @@
+/**
+ * $Id: verse_bitmap_node.c 12931 2007-12-17 18:20:48Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+
+#include "BIF_verse.h"
+
+#include "BKE_verse.h"
+
+#include "verse.h"
+
+/* function prototypes of static functions */
+static void cb_b_dimension_set(void *user_data, VNodeID node_id, uint16 width, uint16 height, uint16 depth);
+static void cb_b_layer_create(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNBLayerType type);
+static void cb_b_layer_destroy(void *user_data, VNodeID node_id, VLayerID layer_id);
+static void cb_b_tile_set(void *user_data, VNodeID node_id, VLayerID layer_id, uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile);
+
+static void change_layer_dimension(
+ VBitmapLayer *vblayer,
+ unsigned int old_width,
+ unsigned int old_height,
+ unsigned int t_old_width,
+ unsigned int t_old_height);
+static void *alloc_verse_bitmap_layer_data(struct VBitmapLayer *vblayer);
+
+/*
+ * resize/crop verse bitmap layer
+ */
+static void change_layer_dimension(
+ VBitmapLayer *vblayer,
+ unsigned int old_width,
+ unsigned int old_height,
+ unsigned int t_old_width,
+ unsigned int t_old_height)
+{
+ struct VNode *vnode = vblayer->vnode;
+ unsigned int t_width = ((VBitmapData*)(vnode->data))->t_width;
+ unsigned int width = ((VBitmapData*)(vnode->data))->width;
+ unsigned int height = ((VBitmapData*)(vnode->data))->height;
+ unsigned int x, y, i, j;
+
+ i = j = 0;
+
+ /* "copy" old data to new data */
+ if(vblayer->type==VN_B_LAYER_UINT8) {
+ unsigned char *data = (unsigned char*)vblayer->data;
+ /* allocate new verse bitmap layer data */
+ unsigned char *new_data = (unsigned char*)alloc_verse_bitmap_layer_data(vblayer);
+ for(y=0; y<old_height && y<height; y++, i=y*t_width, j=y*t_old_width) {
+ for(x=0; x<old_width && y<width; x++, i++, j++) {
+ new_data[i] = data[j];
+ }
+ }
+ MEM_freeN(vblayer->data);
+ vblayer->data = new_data;
+ }
+}
+
+/*
+ * free data stored in verse bitmap layer
+ */
+void free_bitmap_layer_data(VBitmapLayer *vblayer)
+{
+ struct VerseSession *session = vblayer->vnode->session;
+
+ /* free name of bitmap layer */
+ MEM_freeN(vblayer->name);
+
+ /* unsubscribe from verse bitmap layer */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_b_layer_unsubscribe(vblayer->vnode->id, vblayer->id);
+
+ /* free image data of bitmap layer */
+ if(vblayer->data) MEM_freeN(vblayer->data);
+}
+
+/*
+ * allocate data of verse bitmap layer
+ */
+static void *alloc_verse_bitmap_layer_data(VBitmapLayer *vblayer)
+{
+ struct VNode *vnode = vblayer->vnode;
+ unsigned int t_width = ((VBitmapData*)(vnode->data))->t_width;
+ unsigned int t_height = ((VBitmapData*)(vnode->data))->t_height;
+ unsigned int size;
+ void *data;
+
+ size = t_width*t_height;
+
+ /* allocation of own data stored in verse bitmap layer */
+ switch (vblayer->type) {
+ case VN_B_LAYER_UINT1:
+ data = (void*)MEM_mallocN(sizeof(unsigned char)*size, "VBLayer data uint1");
+ break;
+ case VN_B_LAYER_UINT8:
+ data = (void*)MEM_mallocN(sizeof(unsigned char)*size, "VBLayer data uint8");
+ break;
+ case VN_B_LAYER_UINT16:
+ data = (void*)MEM_mallocN(sizeof(unsigned int)*size, "VBLayer data uint16");
+ break;
+ case VN_B_LAYER_REAL32:
+ data = (void*)MEM_mallocN(sizeof(float)*size, "VBLayer data float16");
+ break;
+ case VN_B_LAYER_REAL64:
+ data = (void*)MEM_mallocN(sizeof(double)*size, "VBLayer data float32");
+ break;
+ default:
+ data = NULL;
+ break;
+ }
+
+ return data;
+}
+
+/*
+ * create verse bitmap layer
+ */
+VBitmapLayer *create_bitmap_layer(
+ VNode *vnode,
+ VLayerID layer_id,
+ const char *name,
+ VNBLayerType type)
+{
+ struct VBitmapLayer *vblayer;
+ unsigned int width = ((VBitmapData*)(vnode->data))->width;
+ unsigned int height = ((VBitmapData*)(vnode->data))->height;
+
+ /* allocate memory for own verse bitmap layer */
+ vblayer = (VBitmapLayer*)MEM_mallocN(sizeof(VBitmapLayer), "Verse Bitmap Layer");
+
+ /* verse bitmap layer will include pointer at parent verse node and own id */
+ vblayer->vnode = vnode;
+ vblayer->id = layer_id;
+
+ /* name of verse layer */
+ vblayer->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "Verse Bitmap Layer name");
+ vblayer->name[0] = '\0';
+ strcpy(vblayer->name, name);
+
+ /* type of data stored in verse bitmap layer */
+ vblayer->type = type;
+
+ /* we can allocate memory for layer data, when we know dimmension of layers; when
+ * we don't know it, then we will allocate this data when we will receive dimmension */
+ if(width==0 || height==0)
+ vblayer->data = NULL;
+ else
+ vblayer->data = alloc_verse_bitmap_layer_data(vblayer);
+
+ vblayer->flag = 0;
+
+ return vblayer;
+}
+
+/*
+ * free data of bitmap node
+ */
+void free_bitmap_node_data(VNode *vnode)
+{
+ if(vnode->data) {
+ struct VBitmapLayer *vblayer = (VBitmapLayer*)((VBitmapData*)(vnode->data))->layers.lb.first;
+
+ /* free all VerseLayer data */
+ while(vblayer) {
+ free_bitmap_layer_data(vblayer);
+ vblayer = vblayer->next;
+ }
+
+ /* free all VerseLayers */
+ BLI_dlist_destroy(&(((VGeomData*)vnode->data)->layers));
+ }
+}
+
+/*
+ * create data of bitmap node
+ */
+VBitmapData *create_bitmap_data()
+{
+ struct VBitmapData *vbitmap;
+
+ vbitmap = (VBitmapData*)MEM_mallocN(sizeof(VBitmapData), "Verse Bitmap Data");
+
+ BLI_dlist_init(&(vbitmap->layers));
+ vbitmap->queue.first = vbitmap->queue.last = NULL;
+
+ vbitmap->width = 0;
+ vbitmap->height = 0;
+ vbitmap->depth = 0;
+
+ vbitmap->image = NULL;
+
+ vbitmap->post_bitmap_dimension_set = post_bitmap_dimension_set;
+ vbitmap->post_bitmap_layer_create = post_bitmap_layer_create;
+ vbitmap->post_bitmap_layer_destroy = post_bitmap_layer_destroy;
+ vbitmap->post_bitmap_tile_set = post_bitmap_tile_set;
+
+ return vbitmap;
+}
+
+/*
+ * callback function, dimension of image was changed, it is neccessary to
+ * crop all layers
+ */
+static void cb_b_dimension_set(
+ void *user_data,
+ VNodeID node_id,
+ uint16 width,
+ uint16 height,
+ uint16 depth)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VBitmapLayer *vblayer;
+ unsigned int old_width, old_height, t_old_width, t_old_height;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+#ifdef VERSE_DEBUG_PRINT
+ printf("\t cb_b_dimension_set()\n");
+#endif
+
+ /* backup old width and height */
+ old_width = ((VBitmapData*)(vnode->data))->width;
+ old_height = ((VBitmapData*)(vnode->data))->height;
+ t_old_width = ((VBitmapData*)(vnode->data))->t_width;
+ t_old_height = ((VBitmapData*)(vnode->data))->t_height;
+
+ /* set up new dimension of layers */
+ ((VBitmapData*)(vnode->data))->width = width;
+ ((VBitmapData*)(vnode->data))->height = height;
+ ((VBitmapData*)(vnode->data))->depth = depth;
+
+ /* we cache t_width because tiles aren't one pixel width */
+ if((width % VN_B_TILE_SIZE)!=0)
+ ((VBitmapData*)(vnode->data))->t_width = (width/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE;
+ else
+ ((VBitmapData*)(vnode->data))->t_width = width;
+
+ /* we cache t_height because tiles aren't one pixel height */
+ if((height % VN_B_TILE_SIZE)!=0)
+ ((VBitmapData*)(vnode->data))->t_height = (height/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE;
+ else
+ ((VBitmapData*)(vnode->data))->t_height = height;
+
+ /* crop resize all layers */
+ vblayer = ((VBitmapData*)vnode->data)->layers.lb.first;
+
+ while(vblayer) {
+ /* when this callback function received after cb_b_layer_create,
+ * then we have to allocate memory for verse bitmap layer data */
+ if(!vblayer->data) vblayer->data = alloc_verse_bitmap_layer_data(vblayer);
+ /* crop/resize all verse bitmap layers */
+ else change_layer_dimension(vblayer, old_width, old_height, t_old_width, t_old_height);
+
+ vblayer = vblayer->next;
+ }
+
+ /* post callback function */
+ ((VBitmapData*)(vnode->data))->post_bitmap_dimension_set(vnode);
+}
+
+/*
+ * callback function, new layer channel of image was created
+ */
+static void cb_b_layer_create(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id,
+ const char *name,
+ VNBLayerType type)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VBitmapLayer *vblayer;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+#ifdef VERSE_DEBUG_PRINT
+ printf("\t cb_b_layer_create()\n");
+#endif
+
+ /* when no layer exists, then new layer will be created */
+ vblayer = create_bitmap_layer(vnode, layer_id, name, type);
+
+ /* add verse bitmap layer to list of layers */
+ BLI_dlist_add_item_index(&((VBitmapData*)vnode->data)->layers, vblayer, layer_id);
+
+ /* post callback function */
+ ((VBitmapData*)(vnode->data))->post_bitmap_layer_create(vblayer);
+
+}
+
+/*
+ * callback function, existing layer of image was destroyed
+ */
+static void cb_b_layer_destroy(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VBitmapLayer *vblayer;
+
+ if(!session) return;
+
+ /* find node of this layer*/
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ vblayer = (VBitmapLayer*)BLI_dlist_find_link(&(((VBitmapData*)vnode->data)->layers), layer_id);
+ if(!vblayer) return;
+
+#ifdef VERSE_DEBUG_PRINT
+ printf("\t cb_b_layer_destroy()\n");
+#endif
+
+ /* remove verse bitmap layer from list of layers */
+ BLI_dlist_rem_item(&(((VBitmapData*)vnode->data)->layers), layer_id);
+
+ /* post callback function */
+ ((VBitmapData*)(vnode->data))->post_bitmap_layer_destroy(vblayer);
+
+ /* free data of verse bitmap layer */
+ free_bitmap_layer_data(vblayer);
+
+ /* free verse bitmap layer */
+ MEM_freeN(vblayer);
+}
+
+/*
+ * callback function, small part (8x8 pixels) was changed
+ */
+static void cb_b_tile_set(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint16 tile_x,
+ uint16 tile_y,
+ uint16 z,
+ VNBLayerType type,
+ const VNBTile *tile)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VBitmapLayer *vblayer;
+ unsigned int x, y, xs, ys, width, height, t_height, t_width, i, j;
+
+ if(!session) return;
+
+ /* try to find verse node in dynamic list nodes */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ /* try to find verse bitmap layer in list of layers */
+ vblayer = (VBitmapLayer*)BLI_dlist_find_link(&(((VBitmapData*)vnode->data)->layers), layer_id);
+ if(!vblayer) return;
+
+ /* we have to have allocated memory for bitmap layer */
+ if(!vblayer->data) return;
+
+ width = ((VBitmapData*)vnode->data)->width;
+ height = ((VBitmapData*)vnode->data)->height;
+
+ /* width of verse image including all tiles */
+ t_height = ((VBitmapData*)vnode->data)->t_height;
+ /* height of verse image including all tiles */
+ t_width = ((VBitmapData*)vnode->data)->t_width;
+
+#ifdef VERSE_DEBUG_PRINT
+ printf("\t cb_b_tile_set()\n");
+#endif
+
+ xs = tile_x*VN_B_TILE_SIZE;
+ ys = tile_y*VN_B_TILE_SIZE;
+
+ /* initial position in one dimension vblayer->data (y_start*width + x_start) */
+ i = ys*t_width + xs;
+ /* intial position in one dimension tile array */
+ j = 0;
+
+ if(type==VN_B_LAYER_UINT8) {
+ unsigned char *data = (unsigned char*)vblayer->data;
+ for(y=ys; y<ys+VN_B_TILE_SIZE && y<height; y++, i=y*t_width+xs)
+ for(x=xs; x<xs+VN_B_TILE_SIZE && x<width; x++, i++, j++)
+ data[i] = (unsigned char)tile->vuint8[j];
+ }
+
+ /* post callback function */
+ ((VBitmapData*)(vnode->data))->post_bitmap_tile_set(vblayer, xs, ys);
+}
+
+/*
+ * set up all callbacks functions for image nodes
+ */
+void set_bitmap_callbacks(void)
+{
+ /* dimension (size) of bitmap was set up or changes (image will be croped) */
+ verse_callback_set(verse_send_b_dimensions_set, cb_b_dimension_set, NULL);
+
+ /* new layer (chanell) of image was added or created */
+ verse_callback_set(verse_send_b_layer_create, cb_b_layer_create, NULL);
+
+ /* existing layer was destroyed */
+ verse_callback_set(verse_send_b_layer_destroy, cb_b_layer_destroy, NULL);
+
+ /* some tile (small part 8x8 pixels of image was changed) */
+ verse_callback_set(verse_send_b_tile_set, cb_b_tile_set, NULL);
+}
+
+#endif
+
diff --git a/source/blender/blenkernel/intern/verse_geometry_node.c b/source/blender/blenkernel/intern/verse_geometry_node.c
new file mode 100644
index 00000000000..0b3f26007a6
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_geometry_node.c
@@ -0,0 +1,2101 @@
+/**
+ * $Id: verse_geometry_node.c 12931 2007-12-17 18:20:48Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_verse.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_verse.h"
+
+#include "verse.h"
+
+/* function prototypes of static functions */
+
+/* test functions for callback functions */
+static char test_polygon_set_corner_uint32(uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+
+/* callback functions */
+static void cb_g_layer_create(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_integer, real64 def_real);
+static void cb_g_layer_destroy(void *user_data, VNodeID node_id, VLayerID layer_id);
+static void cb_g_vertex_set_xyz_real32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 x, real32 y, real32 z);
+static void cb_g_polygon_set_corner_uint32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+static void cb_g_vertex_delete_real32(void *user_data, VNodeID node_id, uint32 vertex_id);
+static void cb_g_polygon_delete(void *user_data, VNodeID node_id, uint32 polygon_id);
+static void cb_g_crease_set_edge(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease);
+static void cb_g_crease_set_vertex(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease);
+
+/* other static functions */
+
+static void free_unneeded_verseverts_of_verseface(struct VNode *vnode, struct VerseFace *vface);
+static void free_verse_vertex(struct VLayer *vlayer, struct VerseVert *vvert);
+static void free_verse_face(struct VLayer *vlayer, struct VerseFace *vface);
+static void free_verse_layer_data(struct VNode *vnode, struct VLayer *vlayer);
+
+static void send_verse_face(struct VerseFace *vface);
+
+static VerseVert* find_verse_vert_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 vertex_id, real32 x, real32 y, real32 z);
+static VerseFace* find_verse_face_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+
+static unsigned short test_incoming_verseface(struct VGeomData *geom, struct VerseFace *vface);
+static void find_unsent_faces(struct VNode *vnode, struct VerseVert *vvert);
+static void find_vlayer_orphans(struct VNode *vnode, struct VerseVert *vvert);
+static void move_face_orphan_to_dlist(struct VNode *vnode, struct VLayer *vlayer, struct VerseFace *vface);
+static void increase_verse_verts_references(struct VerseFace *vface);
+static void recalculate_verseface_normals(struct VNode *vnode);
+
+/* verse edge functions */
+static VerseEdge* find_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1);
+static void insert_verse_edgehash(struct VNode *vnode, struct VerseEdge *vedge);
+static void remove_verse_edgehash(struct VNode *vnode, struct VerseEdge *vedge);
+static void remove_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1);
+static void add_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1);
+static void update_edgehash_of_deleted_verseface(struct VNode *vnode, struct VerseFace *vface);
+static void update_edgehash_of_changed_verseface(struct VNode *vnode, struct VerseFace *vface, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+static void update_edgehash_of_new_verseface(struct VNode *vnode, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+
+/*
+ * recalcute normals of all VerseFaces
+ */
+static void recalculate_verseface_normals(VNode *vnode)
+{
+ struct VLayer *vert_layer, *face_layer;
+ struct VerseFace *vface;
+ struct VerseVert *vvert;
+
+ if(vnode->type != V_NT_GEOMETRY) return;
+
+ vert_layer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ face_layer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ vvert = vert_layer->dl.lb.first;
+ while(vvert) {
+ vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0;
+ vvert = vvert->next;
+ }
+
+ vface = face_layer->dl.lb.first;
+ while(vface) {
+ /* calculate face normals */
+ if(vface->vvert3) {
+ CalcNormFloat4(vface->vvert0->co, vface->vvert1->co,
+ vface->vvert2->co, vface->vvert3->co, vface->no);
+ add_v3_v3v3(vface->vvert3->no, vface->vvert3->no, vface->no);
+ }
+ else
+ CalcNormFloat(vface->vvert0->co, vface->vvert1->co,
+ vface->vvert2->co, vface->no);
+
+ /* calculate vertex normals ... it is averadge of all face normals using the vertex */
+ add_v3_v3v3(vface->vvert0->no, vface->vvert0->no, vface->no);
+ add_v3_v3v3(vface->vvert1->no, vface->vvert1->no, vface->no);
+ add_v3_v3v3(vface->vvert2->no, vface->vvert2->no, vface->no);
+
+ vface = vface->next;
+ }
+
+ /* we have to normalize all vertex normals */
+ vvert = vert_layer->dl.lb.first;
+ while(vvert) {
+ normalize_v3(vvert->no);
+ vvert = vvert->next;
+ }
+}
+
+/*
+ * add created item to the queue and send it if possible
+ */
+void add_item_to_send_queue(ListBase *lb, void *item, short type)
+{
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct VerseVert *vvert;
+ struct VerseFace *vface;
+
+ /* this prevent from adding duplicated faces */
+ if(type==VERSE_FACE) {
+ struct Link *link = (Link*)lb->first;
+ while(link) {
+ if(link==item) {
+ if(((VerseFace*)item)->flag & FACE_SENT) {
+/* printf("\tverse face %d marked as OBSOLETE\n", ((VerseFace*)item)->id);*/
+ ((VerseFace*)item)->flag |= FACE_OBSOLETE;
+ }
+ return;
+ }
+ link = link->next;
+ }
+ }
+
+ /* add item to sending queue (two way dynamic list) */
+ BLI_addtail(lb, item);
+
+ /* send item, when it is possible */
+ switch (type) {
+ case VERSE_NODE: /* only first node in queue can be sent */
+ if(lb->first==lb->last)
+ send_verse_node((VNode*)item);
+ break;
+ case VERSE_LINK: /* both object between have to exist */
+ if(((VLink*)item)->flag & LINK_SEND_READY)
+ send_verse_link((VLink*)item);
+ break;
+ case VERSE_LAYER:
+ if(((VLayer*)item)->vnode->flag & NODE_RECEIVED)
+ send_verse_layer((VLayer*)item);
+ break;
+ case VERSE_VERT:
+ if(((VerseVert*)item)->vlayer->flag & LAYER_RECEIVED)
+ send_verse_vertex((VerseVert*)item);
+ break;
+ case VERSE_FACE: /* all vertexes of face have to be received */
+ if(((VerseFace*)item)->flag & FACE_SEND_READY)
+ send_verse_face((VerseFace*)item);
+ break;
+ case VERSE_TAG:
+ send_verse_tag((VTag*)item);
+ break;
+ case VERSE_TAG_GROUP:
+ send_verse_taggroup((VTagGroup*)item);
+ break;
+ case VERSE_VERT_UINT32: /* parent item has to exist */
+ vnode = (((uint32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 );
+ vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((uint32_item*)item)->id );
+ if(vvert != NULL)
+ send_verse_vert_uint32((uint32_item*)item, type);
+ break;
+ case VERSE_VERT_REAL32: /* parent item has to exist */
+ vnode = (((real32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 );
+ vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((real32_item*)item)->id );
+ if( vvert != NULL)
+ send_verse_vert_real32((real32_item*)item, type);
+ break;
+ case VERSE_VERT_VEC_REAL32: /* parent item has to exist */
+ vnode = (((vec_real32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 );
+ vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((vec_real32_item*)item)->id );
+ if(vvert != NULL)
+ send_verse_vert_vec_real32((vec_real32_item*)item, type);
+ break;
+ case VERSE_FACE_UINT8: /* parent item has to exist */
+ vnode = (((uint8_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((uint8_item*)item)->id );
+ if(vface != NULL)
+ send_verse_face_uint8((uint8_item*)item, type);
+ break;
+ case VERSE_FACE_UINT32: /* parent item has to exist */
+ vnode = (((uint32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((uint32_item*)item)->id );
+ if(vface != NULL)
+ send_verse_face_uint32((uint32_item*)item, type);
+ break;
+ case VERSE_FACE_REAL32: /* parent item has to exist */
+ vnode = (((real32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((real32_item*)item)->id );
+ if(vface != NULL)
+ send_verse_face_real32((real32_item*)item, type);
+ break;
+ case VERSE_FACE_QUAT_UINT32: /* parent item has to exist */
+ vnode = (((quat_uint32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((quat_uint32_item*)item)->id );
+ if(vface != NULL)
+ send_verse_face_corner_quat_uint32((quat_uint32_item*)item, type);
+ break;
+ case VERSE_FACE_QUAT_REAL32: /* parent item has to exist */
+ vnode = (((quat_real32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((quat_real32_item*)item)->id );
+ if(vface != NULL)
+ send_verse_face_corner_quat_real32((quat_real32_item*)item, type);
+ break;
+ }
+}
+
+/*
+ * return VerseLayer with certain content (vertexes, polygons, in the
+ * future: weight, red color, etc.)
+ */
+VLayer* find_verse_layer_type(VGeomData *geom, short content)
+{
+ struct VLayer *vlayer = NULL;
+
+ switch(content) {
+ case VERTEX_LAYER:
+ /* VERTEX_LAYER equals 0 and vertex layer is
+ * always in 1st layer */
+ vlayer = geom->layers.da.items[VERTEX_LAYER];
+ break;
+ case POLYGON_LAYER:
+ /* POLYGON_LAYER equals 1 and vertex layer is
+ * always in 2nd layer */
+ vlayer = geom->layers.da.items[POLYGON_LAYER];
+ break;
+ }
+
+ return vlayer;
+}
+
+/*
+ * increase references of VerseVerts of new VerseFace
+ */
+static void increase_verse_verts_references(VerseFace *vface)
+{
+ if(vface->vvert0) vface->vvert0->counter++;
+ if(vface->vvert1) vface->vvert1->counter++;
+ if(vface->vvert2) vface->vvert2->counter++;
+ if(vface->vvert3) vface->vvert3->counter++;
+}
+
+/*
+ * move VerseFace from list of orphans to dlist of VerseFaces (if VerseFace was only changed
+ * then this VerseFace is only removed from list of orphans)
+ */
+static void move_face_orphan_to_dlist(VNode *vnode, VLayer *vlayer, VerseFace *vface)
+{
+ /* remove vface from list of orphans */
+ BLI_remlink(&(vlayer->orphans), vface);
+ /* increase references of all vertexes beying part of this face*/
+ increase_verse_verts_references(vface);
+
+ if(vface->flag & FACE_RECEIVED) {
+ /* set up vface flag */
+ vface->flag &= ~FACE_RECEIVED;
+ /* move vface to dynamic list of faces */
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id);
+ /* recalculate all vertex and faces normals */
+ recalculate_verseface_normals(vnode);
+ /* post create action (change local data) */
+ ((VGeomData*)vnode->data)->post_polygon_create(vface);
+ }
+ else if(vface->flag & FACE_CHANGED) {
+ /* set up vface flag */
+ vface->flag &= ~FACE_CHANGED;
+ /* move vface to dynamic list of faces */
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id);
+ /* recalculate all vertex and faces normals */
+ recalculate_verseface_normals(vnode);
+ /* post create action (change local data) */
+ ((VGeomData*)vnode->data)->post_polygon_set_corner(vface);
+ }
+}
+
+/*
+ * find all VerseFaces waiting in queue, which needs id of new VerseVert
+ */
+static void find_unsent_faces(VNode *vnode, VerseVert *vvert)
+{
+ VLayer *vlayer;
+ VerseFace *vface, *next_vface;
+
+ vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ if(vlayer) {
+ vface = vlayer->queue.first;
+ while(vface) {
+ next_vface = vface->next;
+ if(vface->vvert0==vvert) {
+ vface->v0 = vvert->id;
+ vface->counter--;
+ }
+ else if(vface->vvert1==vvert) {
+ vface->v1 = vvert->id;
+ vface->counter--;
+ }
+ else if(vface->vvert2==vvert) {
+ vface->v2 = vvert->id;
+ vface->counter--;
+ }
+ else if(vface->vvert3==vvert){
+ vface->v3 = vvert->id;
+ vface->counter--;
+ }
+
+ if(vface->counter<1 && !(vface->flag & FACE_SENT))
+ send_verse_face(vface);
+
+ vface = next_vface;
+ }
+ }
+}
+
+/*
+ * find all VerseFace orphans, which needs incoming VerseVert
+ */
+static void find_vlayer_orphans(VNode *vnode, VerseVert *vvert)
+{
+ VLayer *vlayer;
+ VerseFace *vface, *next_vface;
+ unsigned int vertex_id = vvert->id;
+
+ vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ if(vlayer) {
+ vface = vlayer->orphans.first;
+ while(vface){
+ next_vface = vface->next;
+ if(vface->v0 == vertex_id) {
+ vface->vvert0 = vvert;
+ vface->counter--;
+ }
+ else if(vface->v1 == vertex_id) {
+ vface->vvert1 = vvert;
+ vface->counter--;
+ }
+ else if(vface->v2 == vertex_id) {
+ vface->vvert2 = vvert;
+ vface->counter--;
+ }
+ else if(vface->v3 == vertex_id) {
+ vface->vvert3 = vvert;
+ vface->counter--;
+ }
+ if(vface->counter<1) {
+ /* moving VerseFace orphan to dlist */
+ move_face_orphan_to_dlist(vnode, vlayer, vface);
+ }
+ vface = next_vface;
+ }
+ }
+}
+
+/*
+ * return number of VerseVerts missing to incoming VerseFace, set up pointers
+ * at VerseVerts
+ */
+static unsigned short test_incoming_verseface(VGeomData *geom, VerseFace *vface)
+{
+ struct VLayer *vert_layer;
+ struct VerseVert *vvert;
+ int counter=0;
+
+ vert_layer = find_verse_layer_type(geom, VERTEX_LAYER);
+
+ if(vface->v0 != -1){
+ vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v0);
+ if(vvert==NULL) counter++;
+ else vface->vvert0 = vvert;
+ }
+ if(vface->v1 != -1){
+ vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v1);
+ if(vvert==NULL) counter++;
+ else vface->vvert1 = vvert;
+ }
+ if(vface->v2 != -1){
+ vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v2);
+ if(vvert==NULL) counter++;
+ else vface->vvert2 = vvert;
+ }
+ if(vface->v3 != -1){
+ vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v3);
+ if(vvert==NULL) counter++;
+ else vface->vvert3 = vvert;
+ }
+
+ return counter;
+}
+
+/*
+ * try to find changed VerseFace in sending queue
+ */
+static VerseFace* find_changed_verse_face_in_queue(VLayer *vlayer, uint32 polygon_id)
+{
+ struct VerseFace *vface = vlayer->queue.first;
+
+ while(vface){
+ if(vface->id == polygon_id && vface->flag & FACE_CHANGED) {
+ return vface;
+ }
+ vface = vface->next;
+ }
+ return NULL;
+}
+
+/*
+ * try to find VerseFace in queue
+ */
+static VerseFace* find_verse_face_in_queue(
+ VLayer *vlayer,
+ VNodeID node_id,
+ uint32 polygon_id,
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ struct VerseFace *vface = vlayer->queue.first;
+
+ while(vface){
+ if((vface->v0==v0) && (vface->v1==v1) && (vface->v2==v2) && (vface->v3==v3)){
+ vface->id = polygon_id;
+ vface->vlayer = vlayer;
+ return vface;
+ }
+ vface = vface->next;
+ }
+ return NULL;
+}
+
+/*
+ * try to find VerseVert in queue
+ */
+static VerseVert* find_verse_vert_in_queue(
+ VLayer *vlayer,
+ VNodeID node_id,
+ uint32 vertex_id,
+ real32 x,
+ real32 y,
+ real32 z)
+{
+ struct VerseVert *vvert = vlayer->queue.first;
+
+ while(vvert){
+ if((vvert->vlayer->vnode->id == node_id) && (vvert->co[0] == x) && (vvert->co[1] == y) && (vvert->co[2] == z))
+ {
+ vvert->id = vertex_id;
+ vvert->vlayer = vlayer;
+
+ return vvert;
+ }
+ vvert = vvert->next;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * send quat of float values to verse server (4x32 bits)
+ */
+void send_verse_face_corner_quat_real32(quat_real32_item *item, short type)
+{
+ verse_send_g_polygon_set_corner_real32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value[0],
+ item->value[1],
+ item->value[2],
+ item->value[3]);
+}
+
+/*
+ * send quat of unsigned int values to verse server (4x32 bits)
+ */
+void send_verse_face_corner_quat_uint32(quat_uint32_item *item, short type)
+{
+ verse_send_g_polygon_set_corner_uint32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value[0],
+ item->value[1],
+ item->value[2],
+ item->value[3]);
+}
+
+/*
+ * send float value (32 bits) to verse server
+ */
+void send_verse_face_real32(real32_item *item, short type)
+{
+ verse_send_g_polygon_set_face_real32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value);
+}
+
+/*
+ * send unsigned integer (32 bits) to verse server
+ */
+void send_verse_face_uint32(uint32_item *item, short type)
+{
+ verse_send_g_polygon_set_face_uint32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value);
+}
+
+/*
+ * send unsigned char (8 bits) to verse server
+ */
+void send_verse_face_uint8(uint8_item *item, short type)
+{
+ verse_send_g_polygon_set_face_uint8(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value);
+}
+
+/*
+ * send vector of float values to verse server (3x32 bits)
+ */
+void send_verse_vert_vec_real32(vec_real32_item *item, short type)
+{
+ verse_send_g_vertex_set_xyz_real32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value[0],
+ item->value[1],
+ item->value[2]);
+}
+
+/*
+ * send float value (32 bits) to verse server
+ */
+void send_verse_vert_real32(real32_item *item, short type)
+{
+ verse_send_g_vertex_set_real32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value);
+}
+
+/*
+ * send unsigned integer (32 bits) to verse server
+ */
+void send_verse_vert_uint32(uint32_item *item, short type)
+{
+ verse_send_g_vertex_set_uint32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value);
+}
+
+/*
+ * send delete command to verse server
+ */
+void send_verse_vertex_delete(VerseVert *vvert)
+{
+ verse_session_set(vvert->vlayer->vnode->session->vsession);
+
+ vvert->flag |= VERT_OBSOLETE;
+
+ verse_send_g_vertex_delete_real32(vvert->vlayer->vnode->id, vvert->id);
+}
+
+/*
+ * send VerseLayer to verse server
+ */
+void send_verse_layer(VLayer *vlayer)
+{
+ verse_session_set(vlayer->vnode->session->vsession);
+
+ verse_send_g_layer_create(
+ vlayer->vnode->id,
+ vlayer->id,
+ vlayer->name,
+ vlayer->type,
+ vlayer->def_int,
+ vlayer->def_real);
+}
+
+/*
+ * send VerseVert to verse server
+ */
+void send_verse_vertex(VerseVert *vvert)
+{
+ /* new vertex position will not be sent, when vertex was deleted */
+ if(vvert->flag & VERT_OBSOLETE) return;
+
+ verse_session_set(vvert->vlayer->vnode->session->vsession);
+
+ verse_send_g_vertex_set_xyz_real32(
+ vvert->vlayer->vnode->id,
+ vvert->vlayer->id,
+ vvert->id,
+ vvert->co[0],
+ vvert->co[2],
+ -vvert->co[1]);
+}
+
+/*
+ * send delete command to verse server
+ */
+void send_verse_face_delete(VerseFace *vface)
+{
+ verse_session_set(vface->vlayer->vnode->session->vsession);
+
+ vface->flag |= FACE_DELETED;
+
+ verse_send_g_polygon_delete(vface->vlayer->vnode->id, vface->id);
+}
+
+/*
+ * send VerseFace to verse server
+ */
+static void send_verse_face(VerseFace *vface)
+{
+ verse_session_set(vface->vlayer->vnode->session->vsession);
+
+ vface->flag |= FACE_SENT;
+
+ if(vface->v3 != -1) {
+ verse_send_g_polygon_set_corner_uint32(
+ vface->vlayer->vnode->id,
+ vface->vlayer->id,
+ vface->id,
+ vface->v0,
+ vface->v3, /* verse use clock-wise winding */
+ vface->v2,
+ vface->v1); /* verse use clock-wise winding */
+ }
+ else {
+ verse_send_g_polygon_set_corner_uint32(
+ vface->vlayer->vnode->id,
+ vface->vlayer->id,
+ vface->id,
+ vface->v0,
+ vface->v2, /* verse use clock-wise winding */
+ vface->v1, /* verse use clock-wise winding */
+ vface->v3);
+ }
+}
+
+/*
+ * free VerseVert
+ */
+static void free_verse_vertex(VLayer *vlayer, VerseVert *vvert)
+{
+ /* free VerseVert */
+ BLI_freelinkN(&(vlayer->orphans), vvert);
+}
+
+/*
+ * free VerseFace (and blender face)
+ */
+static void free_verse_face(VLayer *vlayer, VerseFace *vface)
+{
+ /* free VerseFace */
+ BLI_dlist_free_item(&(vlayer->dl), (unsigned int)vface->id);
+}
+
+/*
+ * free VerseLayer data
+ */
+static void free_verse_layer_data(VNode *vnode, VLayer *vlayer)
+{
+ struct VerseFace *vface;
+ struct VerseVert *vvert;
+
+ /* set up EditVert->vvert and EditFace->vface pointers to NULL */
+ switch(vlayer->content) {
+ case VERTEX_LAYER:
+ vvert = (VerseVert*)vlayer->dl.lb.first;
+ while(vvert) {
+ ((VGeomData*)vnode->data)->post_vertex_free_constraint(vvert);
+ vvert = vvert->next;
+ }
+ break;
+ case POLYGON_LAYER:
+ vface = (VerseFace*)vlayer->dl.lb.first;
+ while(vface) {
+ ((VGeomData*)vnode->data)->post_polygon_free_constraint(vface);
+ vface = vface->next;
+ }
+ break;
+ default:
+ break;
+ }
+ /* free Verse Layer name */
+ MEM_freeN(vlayer->name);
+ /* destroy VerseLayer data (vertexes, polygons, etc.) */
+ BLI_dlist_destroy(&(vlayer->dl));
+ /* free unsent data */
+ BLI_freelistN(&(vlayer->queue));
+ /* free orphans */
+ BLI_freelistN(&(vlayer->orphans));
+}
+
+/*
+ * free all unneeded VerseVerts waiting for deleting
+ */
+static void free_unneeded_verseverts_of_verseface(VNode *vnode, VerseFace *vface)
+{
+ struct VLayer *vert_vlayer;
+
+ /* find layer containing vertexes */
+ vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+
+ /* free all "deleted" VerseVert waiting for deleting this VerseFace */
+
+ if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0);
+ free_verse_vertex(vert_vlayer, vface->vvert0);
+ vface->vvert0 = NULL;
+ }
+ if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1);
+ free_verse_vertex(vert_vlayer, vface->vvert1);
+ vface->vvert1 = NULL;
+ }
+ if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2);
+ free_verse_vertex(vert_vlayer, vface->vvert2);
+ vface->vvert2 = NULL;
+ }
+ if((vface->vvert3) && (vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3);
+ free_verse_vertex(vert_vlayer, vface->vvert3);
+ vface->vvert3 = NULL;
+ }
+}
+
+/*
+ * This function create VerseVert and returns pointer on this vertex
+ */
+VerseVert* create_verse_vertex(
+ VLayer *vlayer,
+ uint32 vertex_id,
+ real32 x,
+ real32 y,
+ real32 z)
+{
+ struct VerseVert *vvert;
+
+ vvert = (VerseVert*)MEM_mallocN(sizeof(VerseVert), "VerseVert");
+
+ /* set up pointer on parent node */
+ vvert->vlayer = vlayer;
+ vvert->id = vertex_id;
+ /* position */
+ vvert->co[0] = x;
+ vvert->co[1] = y;
+ vvert->co[2] = z;
+ /* normal */
+ vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0;
+ /* blender internals */
+ vvert->flag = 0;
+ vvert->counter = 0;
+ vvert->vertex = NULL;
+
+ /* increase layer counter of vertexes */
+ vlayer->counter++;
+
+ return vvert;
+}
+
+/*
+ * this function creates fake VerseEdge and returns pointer at this edge
+ */
+VerseEdge *create_verse_edge(uint32 v0, uint32 v1)
+{
+ struct VerseEdge *vedge;
+
+ vedge = (VerseEdge*)MEM_mallocN(sizeof(VerseEdge), "VerseEdge");
+
+ vedge->v0 = v0;
+ vedge->v1 = v1;
+ vedge->counter = 0;
+
+ return vedge;
+}
+
+/*
+ * this function will create new VerseFace and will return pointer on such Face
+ */
+VerseFace* create_verse_face(
+ VLayer *vlayer,
+ uint32 polygon_id,
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ struct VerseFace *vface;
+
+ vface = (VerseFace*)MEM_mallocN(sizeof(VerseFace), "VerseFace");
+
+ /* verse data */
+ vface->vlayer = vlayer;
+ vface->id = polygon_id;
+
+ vface->vvert0 = NULL;
+ vface->vvert1 = NULL;
+ vface->vvert2 = NULL;
+ vface->vvert3 = NULL;
+
+ vface->v0 = v0;
+ vface->v1 = v1;
+ vface->v2 = v2;
+ vface->v3 = v3;
+
+ /* blender data */
+ vface->face = NULL;
+ vface->flag = 0;
+ vface->counter = 4;
+
+ /* increase layer counter of faces */
+ vlayer->counter++;
+
+ return vface;
+}
+
+/*
+ * create and return VerseLayer
+ */
+VLayer *create_verse_layer(
+ VNode *vnode,
+ VLayerID layer_id,
+ const char *name,
+ VNGLayerType type,
+ uint32 def_integer,
+ real64 def_real)
+{
+ struct VLayer *vlayer;
+
+ /* add layer to the DynamicList */
+ vlayer = (VLayer*)MEM_mallocN(sizeof(VLayer), "VerseLayer");
+
+ /* store all relevant info to the vlayer and set up vlayer */
+ vlayer->vnode = vnode;
+ vlayer->id = layer_id;
+ vlayer->name = (char*)MEM_mallocN(sizeof(char)*(sizeof(name)+1),"Verse Layer name");
+ strcpy(vlayer->name, name);
+ vlayer->type = type;
+ vlayer->def_int = def_integer;
+ vlayer->def_real = def_real;
+
+ if((type == VN_G_LAYER_VERTEX_XYZ) && (layer_id == 0))
+ vlayer->content = VERTEX_LAYER;
+ else if((type == VN_G_LAYER_POLYGON_CORNER_UINT32) && (layer_id == 1))
+ vlayer->content = POLYGON_LAYER;
+ else
+ vlayer->content = -1;
+
+ /* initialize DynamicList in the vlayer (vertexes, polygons, etc.)*/
+ BLI_dlist_init(&(vlayer->dl));
+ /* initialization of queue of layer */
+ vlayer->queue.first = vlayer->queue.last = NULL;
+ /* initialization of list of orphans */
+ vlayer->orphans.first = vlayer->orphans.last = NULL;
+ /* initialize number of sent items (vertexes, faces, etc) */
+ vlayer->counter = 0;
+ /* initialize flag */
+ vlayer->flag = 0;
+
+ /* set up methods */
+ vlayer->post_layer_create = post_layer_create;
+ vlayer->post_layer_destroy = post_layer_destroy;
+
+ return vlayer;
+}
+
+/*
+ * create geometry data
+ */
+VGeomData *create_geometry_data(void)
+{
+ struct VGeomData *geom;
+
+ geom = (VGeomData*)MEM_mallocN(sizeof(VGeomData), "VerseGeometryData");
+ BLI_dlist_init(&(geom->layers));
+ geom->vlink = NULL;
+ geom->queue.first = geom->queue.last = NULL;
+ geom->mesh = NULL;
+ geom->editmesh = NULL;
+
+ /* initialize list of fake verse edges and initialize verse edge hash */
+ geom->edges.first = geom->edges.last = NULL;
+ geom->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab");
+
+ /* set up methods */
+ geom->post_vertex_create = post_vertex_create;
+ geom->post_vertex_set_xyz = post_vertex_set_xyz;
+ geom->post_vertex_delete = post_vertex_delete;
+ geom->post_vertex_free_constraint = post_vertex_free_constraint;
+ geom->post_polygon_create = post_polygon_create;
+ geom->post_polygon_set_corner = post_polygon_set_corner;
+ geom->post_polygon_delete = post_polygon_delete;
+ geom->post_polygon_free_constraint = post_polygon_free_constraint;
+ geom->post_geometry_free_constraint = post_geometry_free_constraint;
+ geom->post_polygon_set_uint8 = post_polygon_set_uint8;
+
+ return geom;
+}
+
+/* Create item containing 4 floats */
+static quat_real32_item *create_quat_real32_item(
+ VLayer *vlayer,
+ uint32 item_id,
+ real32 v0,
+ real32 v1,
+ real32 v2,
+ real32 v3)
+{
+ struct quat_real32_item *item;
+
+ item = (quat_real32_item*)MEM_mallocN(sizeof(quat_real32_item), "quat_real32_item");
+
+ item->vlayer = vlayer;
+ item->id = item_id;
+ item->value[0] = v0;
+ item->value[1] = v1;
+ item->value[2] = v2;
+ item->value[3] = v3;
+
+ return item;
+}
+
+/* Create item containing 1 float */
+static real32_item *create_real32_item(VLayer *vlayer, uint32 item_id, real32 value)
+{
+ struct real32_item *item;
+
+ item = (real32_item*)MEM_mallocN(sizeof(real32_item), "real32_item");
+
+ item->vlayer = vlayer;
+ item->id = item_id;
+ item->value = value;
+
+ return item;
+}
+
+/* Create item containing 1 integer */
+static uint32_item *create_uint32_item(VLayer *vlayer, uint32 item_id, uint32 value)
+{
+ struct uint32_item *item;
+
+ item = (uint32_item*)MEM_mallocN(sizeof(uint32_item), "uint32_item");
+
+ item->vlayer = vlayer;
+ item->id = item_id;
+ item->value = value;
+
+ return item;
+}
+
+/* Create item containing 1 byte */
+static uint8_item *create_uint8_item(VLayer *vlayer, uint32 item_id, uint8 value)
+{
+ struct uint8_item *item;
+
+ item = (uint8_item*)MEM_mallocN(sizeof(uint8_item), "uint8_item");
+
+ item->vlayer = vlayer;
+ item->id = item_id;
+ item->value = value;
+
+ return item;
+}
+
+/*
+ * callback function: vertex crease was set
+ */
+static void cb_g_crease_set_vertex(
+ void *user_data,
+ VNodeID node_id,
+ const char *layer,
+ uint32 def_crease)
+{
+}
+
+/*
+ * we have to test corretness of incoming data from verse server
+ * no two vertexes can have the same index
+ */
+static char test_polygon_set_corner_uint32(
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ if((v0==v1) || (v0==v2) || (v0==v3) || (v1==v2) || (v1==v3) || (v2==v3))
+ return 0;
+ else
+ return 1;
+}
+
+/*
+ * try to find verse layer in sending queue of verse geometry node
+ */
+static VLayer *find_vlayer_in_sending_queue(VNode *vnode, VLayerID layer_id)
+{
+ struct VLayer *vlayer;
+
+ /* try to find verse layyer in sending queue */
+ vlayer = ((VGeomData*)vnode->data)->queue.first;
+ while(vlayer) {
+ if(vlayer->id==layer_id) return vlayer;
+ vlayer = vlayer->next;
+ }
+
+ return NULL;
+}
+
+/*
+ * this function will find edge in hash table, hash function isn't too optimal (it needs
+ * lot of memory for every verse node), but it works without any bug
+ */
+static VerseEdge* find_verse_edge(VNode *vnode, uint32 v0, uint32 v1)
+{
+ struct HashVerseEdge *hve;
+
+ if(((VGeomData*)vnode->data)->hash==NULL)
+ ((VGeomData*)vnode->data)->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab");
+
+ hve = ((VGeomData*)vnode->data)->hash + VEDHASH(v0, v1);;
+ while(hve) {
+ /* edge v0---v1 is the same edge as v1---v0 */
+ if(hve->vedge && ((hve->vedge->v0==v0 && hve->vedge->v1==v1) || (hve->vedge->v0==v1 && hve->vedge->v1==v0))) return hve->vedge;
+ hve = hve->next;
+ }
+
+ return NULL;
+}
+
+/*
+ * insert hash of verse edge to hash table
+ */
+static void insert_verse_edgehash(VNode *vnode, VerseEdge *vedge)
+{
+ struct HashVerseEdge *first, *hve;
+
+ if(((VGeomData*)vnode->data)->hash==NULL)
+ ((VGeomData*)vnode->data)->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab");
+
+ first = ((VGeomData*)vnode->data)->hash + VEDHASH(vedge->v0, vedge->v1);
+
+ if(first->vedge==NULL) {
+ first->vedge = vedge;
+ }
+ else {
+ hve = &(vedge->hash);
+ hve->vedge = vedge;
+ hve->next = first->next;
+ first->next = hve;
+ }
+}
+
+/*
+ * remove hash of verse edge from hash table
+ */
+static void remove_verse_edgehash(VNode *vnode, VerseEdge *vedge)
+{
+ struct HashVerseEdge *first, *hve, *prev;
+
+ hve = first = ((VGeomData*)vnode->data)->hash + VEDHASH(vedge->v0, vedge->v1);
+
+ while(hve) {
+ if(hve->vedge == vedge) {
+ if(hve==first) {
+ if(first->next) {
+ hve = first->next;
+ first->vedge = hve->vedge;
+ first->next = hve->next;
+ }
+ else {
+ hve->vedge = NULL;
+ }
+ }
+ else {
+ prev->next = hve->next;
+ }
+ return;
+ }
+ prev = hve;
+ hve = hve->next;
+ }
+}
+
+/*
+ * this function will try to remove existing fake verse edge, when this verse
+ * edge is still used by some faces, then counter will be only decremented
+ */
+static void remove_verse_edge(VNode *vnode, uint32 v0, uint32 v1)
+{
+ struct VerseEdge *vedge;
+
+ vedge = find_verse_edge(vnode, v0, v1);
+ if(vedge) {
+ vedge->counter--;
+ if(vedge->counter==0) {
+ remove_verse_edgehash(vnode, vedge);
+ BLI_freelinkN(&(((VGeomData*)vnode->data)->edges), vedge);
+ }
+ }
+ else {
+ printf("error: remove_verse_edge %d, %d\n", v0, v1);
+ }
+}
+
+/*
+ * this function will try to add new fake verse edge, when no such edge exist,
+ * when such edge exist, then only counter of edge will be incremented
+ */
+static void add_verse_edge(VNode *vnode, uint32 v0, uint32 v1)
+{
+ struct VerseEdge *vedge;
+
+ vedge = find_verse_edge(vnode, v0, v1);
+ if(!vedge) {
+ if(v0!=v1) {
+ vedge = create_verse_edge(v0, v1);
+ BLI_addtail(&(((VGeomData*)vnode->data)->edges), vedge);
+ insert_verse_edgehash(vnode, vedge);
+ }
+ else {
+ printf("error:add_verse_edge: %d, %d\n", v0, v1);
+ return;
+ }
+ }
+ vedge->counter++;
+}
+
+/*
+ * verse face was deleted ... update edge hash
+ */
+static void update_edgehash_of_deleted_verseface(VNode *vnode, VerseFace *vface)
+{
+ uint32 v0, v1, v2, v3; /* verse vertex indexes of deleted verse face */
+
+ v0 = vface->vvert0->id;
+ v1 = vface->vvert1->id;
+ v2 = vface->vvert2->id;
+ v3 = vface->vvert3 ? vface->vvert3->id : -1;
+
+ remove_verse_edge(vnode, v0, v1);
+ remove_verse_edge(vnode, v1, v2);
+ if(v3!=-1) {
+ remove_verse_edge(vnode, v2, v3);
+ remove_verse_edge(vnode, v3, v0);
+ }
+ else {
+ remove_verse_edge(vnode, v2, v0);
+ }
+}
+
+/*
+ * existing verse face was changed ... update edge hash
+ */
+static void update_edgehash_of_changed_verseface(
+ VNode *vnode,
+ VerseFace *vface,
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ uint32 ov0, ov1, ov2, ov3; /* old indexes at verse vertexes*/
+
+ ov0 = vface->vvert0->id;
+ ov1 = vface->vvert1->id;
+ ov2 = vface->vvert2->id;
+ ov3 = vface->vvert3 ? vface->vvert3->id : -1;
+
+ /* 1st edge */
+ if(v0!=ov0 || v1!=ov1) {
+ remove_verse_edge(vnode, ov0, ov1);
+ add_verse_edge(vnode, v0, v1);
+ }
+
+ /* 2nd edge */
+ if(v1!=ov1 || v2!=ov2) {
+ remove_verse_edge(vnode, ov1, ov2);
+ add_verse_edge(vnode, v1, v2);
+ }
+
+ /* 3rd edge */
+ if(v2!=ov2 || v3!=ov3 || v0!=ov0) {
+ if(ov3!=-1) {
+ remove_verse_edge(vnode, ov2, ov3);
+ if(v3!=-1) {
+ add_verse_edge(vnode, v2, v3); /* new 3rd edge (quat->quat) */
+ }
+ else {
+ remove_verse_edge(vnode, ov3, ov0); /* old edge v3,v0 of quat have to be removed */
+ add_verse_edge(vnode, v2, v0); /* new 3rd edge (quat->triangle) */
+ }
+ }
+ else {
+ remove_verse_edge(vnode, ov2, ov0);
+ if(v3!=-1) {
+ add_verse_edge(vnode, v2, v3); /* new 3rd edge (triangle->quat) */
+ }
+ else {
+ add_verse_edge(vnode, v2, v0); /* new 3rd edge (triangle->triangle) */
+ }
+ }
+ }
+
+ /* 4th edge */
+ if(v3!=-1 && (v3!=ov3 || v0!=ov0)) {
+ remove_verse_edge(vnode, ov3, ov0);
+ add_verse_edge(vnode, v3, v0);
+ }
+}
+
+/*
+ * new verse face was created ... update list of edges and edge has
+ */
+static void update_edgehash_of_new_verseface(
+ VNode *vnode,
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ /* when edge already exists, then only its counter is incremented,
+ * look at commentary of add_verse_edge() function */
+ add_verse_edge(vnode, v0, v1);
+ add_verse_edge(vnode, v1, v2);
+ if(v3!=-1) {
+ add_verse_edge(vnode, v2, v3);
+ add_verse_edge(vnode, v3, v0);
+ }
+ else {
+ add_verse_edge(vnode, v2, v0);
+ }
+}
+
+/*
+ * callback function: edge crease was set
+ */
+static void cb_g_crease_set_edge(
+ void *user_data,
+ VNodeID node_id,
+ const char *layer,
+ uint32 def_crease)
+{
+}
+
+/*
+ * callback function: float value for polygon was set up
+ */
+static void cb_g_polygon_set_face_real32(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 polygon_id,
+ real32 value)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct real32_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
+
+ if(item) {
+ item->value = value;
+ }
+ else {
+ item = create_real32_item(vlayer, polygon_id, value);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: int values for polygon was set up
+ */
+static void cb_g_polygon_set_face_uint32(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 polygon_id,
+ uint32 value)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct uint32_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
+
+ if(item) {
+ item->value = value;
+ }
+ else {
+ item = create_uint32_item(vlayer, polygon_id, value);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: uint8 value for polygon was set up
+ */
+static void cb_g_polygon_set_face_uint8(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 polygon_id,
+ uint8 value)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct uint8_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
+
+ if(item) {
+ item->value = value;
+ }
+ else {
+ item = create_uint8_item(vlayer, polygon_id, value);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: float value for polygon corner was set up
+ */
+static void cb_g_polygon_set_corner_real32(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 polygon_id,
+ real32 v0,
+ real32 v1,
+ real32 v2,
+ real32 v3)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct quat_real32_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
+
+ if(item) {
+ item->value[0] = v0;
+ item->value[1] = v1;
+ item->value[2] = v2;
+ item->value[3] = v3;
+ }
+ else {
+ item = create_quat_real32_item(vlayer, polygon_id, v0, v1, v2, v3);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: polygon is deleted
+ */
+static void cb_g_polygon_delete(
+ void *user_data,
+ VNodeID node_id,
+ uint32 polygon_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ VNode *vnode;
+ VLayer *vlayer;
+ VerseFace *vface;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = BLI_dlist_find_link(&(session->nodes), node_id);
+
+ /* find layer containing faces */
+ vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ /* find wanted VerseFace */
+ vface = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
+
+ if(!vface) return;
+
+ /* update edge hash */
+ update_edgehash_of_deleted_verseface(vnode, vface);
+
+ ((VGeomData*)vnode->data)->post_polygon_delete(vface);
+
+ /* decrease references at coresponding VerseVertexes */
+ vface->vvert0->counter--;
+ vface->vvert1->counter--;
+ vface->vvert2->counter--;
+ if(vface->vvert3) vface->vvert3->counter--;
+
+ /* delete unneeded VerseVertexes */
+ free_unneeded_verseverts_of_verseface(vnode, vface);
+
+ free_verse_face(vlayer, vface);
+}
+
+/*
+ * callback function: new polygon (face) created or existing polygon was changed
+ */
+static void cb_g_polygon_set_corner_uint32(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 polygon_id,
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct VerseFace *vface=NULL;
+
+ if(!session) return;
+
+ /* try to find VerseNode */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ /* try to find VerseLayer */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+ if(!vlayer) return;
+
+ /* we have to test coretness of incoming data */
+ if(!test_polygon_set_corner_uint32(v0, v1, v2, v3)) return;
+
+ /* Blender uses different order of vertexes */
+ if(v3!=-1) { /* quat swap */
+ unsigned int v; v = v1; v1 = v3; v3 = v;
+ }
+ else { /* triangle swap */
+ unsigned int v; v = v1; v1 = v2; v2 = v;
+ }
+
+ /* try to find VerseFace */
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)polygon_id);
+
+ /* try to find modified VerseFace */
+ if(!vface) {
+ vface = find_changed_verse_face_in_queue(vlayer, polygon_id);
+ if(vface) {
+ BLI_remlink(&(vlayer->queue), (void*)vface);
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id);
+ }
+ }
+
+ if(!vface) {
+ /* try to find VerseFace in list of VerseVaces created by me and set up polygon and
+ * layer ids */
+ vface = find_verse_face_in_queue(vlayer, node_id, polygon_id, v0, v1, v2, v3);
+
+ /* update edge hash */
+ update_edgehash_of_new_verseface(vnode, v0, v1, v2, v3);
+
+ if(vface){
+ /* I creeated this face ... remove VerseFace from queue */
+ BLI_remlink(&(vlayer->queue), (void*)vface);
+ }
+ else {
+ /* some other client created this face*/
+ vface = create_verse_face(vlayer, polygon_id, v0, v1, v2, v3);
+ }
+
+ vface->flag &= ~FACE_SENT;
+
+ /* return number of missing verse vertexes */
+ vface->counter = test_incoming_verseface((VGeomData*)vnode->data, vface);
+
+ if(vface->counter < 1) {
+ /* when VerseFace received all needed VerseFaces, then it is moved
+ * to list of VerseFaces */
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id);
+ increase_verse_verts_references(vface);
+ recalculate_verseface_normals(vnode);
+ ((VGeomData*)vnode->data)->post_polygon_create(vface);
+ }
+ else {
+ /* when all needed VerseVertexes weren't received, then VerseFace is moved to
+ * the list of orphans waiting on needed vertexes */
+ vface->flag |= FACE_RECEIVED;
+ BLI_addtail(&(vlayer->orphans), (void*)vface);
+ }
+ }
+ else {
+ VLayer *vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ /* VerseVertexes of existing VerseFace were changed (VerseFace will use some different
+ * VerseVertexes or it will use them in different order) */
+
+ /* update fake verse edges */
+ update_edgehash_of_changed_verseface(vnode, vface, v0, v1, v2, v3);
+
+ /* initialize count of unreceived vertexes needed for this face */
+ vface->counter = 4;
+
+ /* 1st corner */
+ if(vface->vvert0->id != v0) {
+ /* decrease references of obsolete vertexes*/
+ vface->vvert0->counter--;
+ /* delete this vertex, when it isn't used by any face and it was marked as deleted */
+ if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0);
+ free_verse_vertex(vert_vlayer, vface->vvert0);
+ }
+ /* try to set up new pointer at verse vertex */
+ vface->v0 = v0;
+ vface->vvert0 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v0);
+ if(vface->vvert0) {
+ /* increase references at new vertex */
+ vface->vvert0->counter++;
+ /* decrease count of needed vertex to receive */
+ vface->counter--;
+ }
+
+ }
+ else
+ /* this corner wasn't changed */
+ vface->counter--;
+
+ /* 2nd corner */
+ if(vface->vvert1->id != v1) {
+ vface->vvert1->counter--;
+ if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1);
+ free_verse_vertex(vert_vlayer, vface->vvert1);
+ }
+ vface->v1 = v1;
+ vface->vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v1);
+ if(vface->vvert1) {
+ vface->vvert1->counter++;
+ vface->counter--;
+ }
+ }
+ else
+ vface->counter--;
+
+ /* 3rd corner */
+ if(vface->vvert2->id != v2) {
+ vface->vvert2->counter--;
+ if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2);
+ free_verse_vertex(vert_vlayer, vface->vvert2);
+ }
+ vface->v2 = v2;
+ vface->vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v2);
+ if(vface->vvert2) {
+ vface->vvert2->counter++;
+ vface->counter--;
+ }
+ }
+ else
+ vface->counter--;
+
+ /* 4th corner */
+ if(vface->vvert3) {
+ if(vface->vvert3->id != v3) {
+ vface->vvert3->counter--;
+ if((vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3);
+ free_verse_vertex(vert_vlayer, vface->vvert3);
+ }
+ vface->v3 = v3;
+ if(v3 != -1) {
+ vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3);
+ if(vface->vvert3) {
+ vface->vvert3->counter++;
+ vface->counter--;
+ }
+ }
+ else {
+ /* this is some special case, this face hase now only 3 corners
+ * quat -> triangle */
+ vface->vvert3 = NULL;
+ vface->counter--;
+ }
+ }
+ }
+ else if(v3 != -1)
+ /* this is some special case, 4th corner of this polygon was created
+ * triangle -> quat */
+ vface->v3 = v3;
+ vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3);
+ if(vface->vvert3) {
+ vface->vvert3->counter++;
+ vface->counter--;
+ }
+ else {
+ vface->v3 = -1;
+ vface->counter--;
+ }
+
+ vface->flag &= ~FACE_SENT;
+ vface->flag |= FACE_CHANGED;
+
+ if(vface->counter<1) {
+ vface->flag &= ~FACE_CHANGED;
+ recalculate_verseface_normals(vnode);
+ ((VGeomData*)vnode->data)->post_polygon_set_corner(vface);
+ }
+ else {
+ /* when all needed VerseVertexes weren't received, then VerseFace is added to
+ * the list of orphans waiting on needed vertexes */
+ BLI_dlist_rem_item(&(vlayer->dl), vface->id);
+ BLI_addtail(&(vlayer->orphans), (void*)vface);
+ }
+ }
+}
+
+/*
+ * callback function: float value was set up for VerseVert with vertex_id
+ */
+static void cb_g_vertex_set_real32(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 vertex_id,
+ real32 value)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct real32_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), vertex_id);
+
+ if(item) {
+ item->value = value;
+ }
+ else {
+ item = create_real32_item(vlayer, vertex_id, value);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: int value was set up for VerseVert with vertex_id
+ */
+static void cb_g_vertex_set_uint32(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 vertex_id,
+ uint32 value)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct uint32_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), vertex_id);
+
+ if(item) {
+ item->value = value;
+ }
+ else {
+ item = create_uint32_item(vlayer, vertex_id, value);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: polygon was deleted
+ */
+static void cb_g_vertex_delete_real32(
+ void *user_data,
+ VNodeID node_id,
+ uint32 vertex_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ VNode *vnode=NULL;
+ VLayer *vert_vlayer=NULL;
+ VerseVert *vvert=NULL;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+
+ vvert = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vertex_id);
+
+ if(!vvert) return;
+
+ if(vvert->counter < 1) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vvert);
+ BLI_dlist_free_item(&(vert_vlayer->dl), (unsigned int)vertex_id);
+ }
+ else {
+ /* some VerseFace(s) still need VerseVert, remove verse vert from
+ * list verse vertexes and put it to list of orphans */
+ vvert->flag |= VERT_DELETED;
+ BLI_dlist_rem_item(&(vert_vlayer->dl), (unsigned int)vertex_id);
+ BLI_addtail(&(vert_vlayer->orphans), vvert);
+ }
+}
+
+/*
+ * callback function: position of one vertex was changed or new vertex was created
+ */
+static void cb_g_vertex_set_xyz_real32(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 vertex_id,
+ real32 x,
+ real32 y,
+ real32 z)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode = NULL;
+ struct VLayer *vlayer = NULL;
+ struct VerseVert *vvert = NULL;
+ real32 tmp;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode)return;
+
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+ if(!vlayer) return;
+
+ /* switch axis orientation */
+ tmp = y;
+ y = -z;
+ z = tmp;
+
+ if(vlayer->id == 0) {
+ /* try to pick up verse vert from DynamicList */
+ vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)vertex_id);
+
+ if(vvert) {
+ if(vvert->flag & VERT_OBSOLETE) return;
+
+ if (vvert->flag & VERT_LOCKED) {
+ /* this application changed position of this vertex */
+ if((vvert->co[0]==x) && (vvert->co[1]==y) && (vvert->co[2]==z)) {
+ /* unlock vertex position */
+ vvert->flag &= ~VERT_LOCKED;
+ /* call post_vertex_set_xyz only, when position of vertex is
+ * obsolete ... the new vertex position will be sent to
+ * verse server */
+ if (vvert->flag & VERT_POS_OBSOLETE) {
+ ((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert);
+ }
+ }
+ }
+ else {
+ /* somebody else changed position of this vertex*/
+ if((vvert->co[0]!=x) || (vvert->co[1]!=y) || (vvert->co[2]!=z)) {
+ vvert->co[0] = x;
+ vvert->co[1] = y;
+ vvert->co[2] = z;
+ recalculate_verseface_normals(vnode);
+ ((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert);
+ }
+ }
+ }
+ else {
+ /* create new verse vert */
+
+ /* test if we are authors of this vertex :-) */
+ vvert = find_verse_vert_in_queue(vlayer, node_id, vertex_id, x, y, z);
+
+ if(vvert) {
+ /* remove vert from queue */
+ BLI_remlink(&(vlayer->queue), (void*)vvert);
+ /* add vvert to the dynamic list */
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id);
+ /* set VerseVert flags */
+ vvert->flag |= VERT_RECEIVED;
+ if(!(vvert->flag & VERT_POS_OBSOLETE))
+ vvert->flag &= ~VERT_LOCKED;
+ /* find VerseFaces orphans */
+ find_vlayer_orphans(vnode, vvert);
+ /* find unsent VerseFaces */
+ find_unsent_faces(vnode, vvert);
+ }
+ else {
+ /* create new VerseVert */
+ vvert = create_verse_vertex(vlayer, vertex_id, x, y, z);
+ /* add VerseVert to list of VerseVerts */
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id);
+ /* set VerseVert flags */
+ vvert->flag |= VERT_RECEIVED;
+ /* find VerseFaces orphans */
+ find_vlayer_orphans(vnode, vvert);
+ }
+
+ ((VGeomData*)vnode->data)->post_vertex_create(vvert);
+ }
+ }
+}
+
+/*
+ * callback function for destroyng of verse layer
+ */
+static void cb_g_layer_destroy(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), node_id);
+ if(!vnode) return;
+
+ vlayer = (VLayer*) BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), layer_id);
+
+ if(vlayer){
+ /* free VerseLayer data */
+ free_verse_layer_data(vnode, vlayer);
+ /* remove VerseLayer from list of verse layers */
+ BLI_dlist_rem_item(&(((VGeomData*)vnode->data)->layers), layer_id);
+ /* do client dependent actions */
+ vlayer->post_layer_destroy(vlayer);
+ /* free vlayer itself */
+ MEM_freeN(vlayer);
+ }
+
+}
+
+/*
+ * callback function: new layer was created
+ */
+static void cb_g_layer_create(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id,
+ const char *name,
+ VNGLayerType type,
+ uint32 def_integer,
+ real64 def_real)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode=NULL;
+ struct VLayer *vlayer=NULL;
+
+ if(!session) return;
+
+ /* find node of this layer*/
+ vnode = BLI_dlist_find_link(&(session->nodes), node_id);
+ if(!vnode) return;
+
+ /* when we created this layer, then subscribe to this layer */
+ if(vnode->owner_id == VN_OWNER_MINE || session->flag & VERSE_AUTOSUBSCRIBE)
+ verse_send_g_layer_subscribe(node_id, layer_id, 0);
+
+ /* try to find */
+ if(vnode->owner_id == VN_OWNER_MINE)
+ vlayer = find_vlayer_in_sending_queue(vnode, layer_id);
+
+ if(vlayer) {
+ /* remove vlayer form sending queue add verse layer to list of verse layers */
+ BLI_remlink(&((VGeomData*)vnode->data)->queue, vlayer);
+ BLI_dlist_add_item_index(&((VGeomData*)vnode->data)->layers, (void*)vlayer, (unsigned int)vlayer->id);
+ /* send all not sent vertexes to verse server
+ * other items waiting in sending queue will be automaticaly sent to verse server,
+ * when verse vertexes will be received from verse server */
+ if((vlayer->type == VN_G_LAYER_VERTEX_XYZ) && (layer_id==0)) {
+ struct VerseVert *vvert = (VerseVert*)vlayer->queue.first;
+ while(vvert) {
+ send_verse_vertex(vvert);
+ vvert = vvert->next;
+ }
+ }
+ }
+ else {
+ /* create new VerseLayer */
+ vlayer = create_verse_layer(vnode, layer_id, name, type, def_integer, def_real);
+ /* add layer to the list of VerseLayers */
+ BLI_dlist_add_item_index(&(((VGeomData*)vnode->data)->layers), (void*)vlayer, (unsigned int)layer_id);
+ }
+
+ vlayer->flag |= LAYER_RECEIVED;
+
+ /* post callback function */
+ vlayer->post_layer_create(vlayer);
+}
+
+/*
+ * this function will send destroy commands for all VerseVertexes and
+ * VerseFaces to verse server, but it will not send destroy commands
+ * for VerseLayers or geometry node, it can be used in other functions
+ * (undo, destroy geom node, some edit mesh commands, ... ), parameter of
+ * this function has to be geometry verse node
+ */
+void destroy_geometry(VNode *vnode)
+{
+ struct VLayer *vert_vlayer, *face_vlayer;
+ struct VerseFace *vface;
+ struct VerseVert *vvert;
+
+ if(vnode->type != V_NT_GEOMETRY) return;
+
+ face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+ vface = face_vlayer->dl.lb.first;
+
+ while(vface) {
+ send_verse_face_delete(vface);
+ vface = vface->next;
+ }
+
+ vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ vvert = vert_vlayer->dl.lb.first;
+
+ while(vvert) {
+ send_verse_vertex_delete(vvert);
+ vvert = vvert->next;
+ }
+
+ /* own destruction of local verse date will be executed, when client will
+ * receive apropriate callback commands from verse server */
+}
+
+/*
+ * free VGeomData
+ */
+void free_geom_data(VNode *vnode)
+{
+ struct VerseSession *session = vnode->session;
+ struct VLayer *vlayer;
+
+ if(vnode->data){
+ vlayer = (VLayer*)((VGeomData*)vnode->data)->layers.lb.first;
+ while(vlayer){
+ /* unsubscribe from layer */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_g_layer_unsubscribe(vnode->id, vlayer->id);
+ /* free VerseLayer data */
+ free_verse_layer_data(vnode, vlayer);
+ /* next layer */
+ vlayer = vlayer->next;
+ }
+ /* free constraint between vnode and mesh */
+ ((VGeomData*)vnode->data)->post_geometry_free_constraint(vnode);
+ /* free all VerseLayers */
+ BLI_dlist_destroy(&(((VGeomData*)vnode->data)->layers));
+ /* free fake verse edges */
+ BLI_freelistN(&((VGeomData*)vnode->data)->edges);
+ /* free edge hash */
+ MEM_freeN(((VGeomData*)vnode->data)->hash);
+ }
+}
+
+void set_geometry_callbacks(void)
+{
+ /* new layer created */
+ verse_callback_set(verse_send_g_layer_create, cb_g_layer_create, NULL);
+ /* layer was destroyed */
+ verse_callback_set(verse_send_g_layer_destroy, cb_g_layer_destroy, NULL);
+
+ /* position of vertex was changed */
+ verse_callback_set(verse_send_g_vertex_set_xyz_real32, cb_g_vertex_set_xyz_real32, NULL);
+ /* vertex was deleted */
+ verse_callback_set(verse_send_g_vertex_delete_real32, cb_g_vertex_delete_real32, NULL);
+
+ /* callback functions for values being associated with vertexes */
+ verse_callback_set(verse_send_g_vertex_set_uint32, cb_g_vertex_set_uint32, NULL);
+ verse_callback_set(verse_send_g_vertex_set_real32, cb_g_vertex_set_real32, NULL);
+
+ /* new polygon was created / vertex(es) of polygon was set */
+ verse_callback_set(verse_send_g_polygon_set_corner_uint32, cb_g_polygon_set_corner_uint32, NULL);
+ /* polygon was deleted */
+ verse_callback_set(verse_send_g_polygon_delete, cb_g_polygon_delete, NULL);
+
+ /* callback functions for values being associated with polygon corners */
+ verse_callback_set(verse_send_g_polygon_set_corner_real32, cb_g_polygon_set_corner_real32, NULL);
+ /* callback functions for values being associated with faces */
+ verse_callback_set(verse_send_g_polygon_set_face_uint8, cb_g_polygon_set_face_uint8, NULL);
+ verse_callback_set(verse_send_g_polygon_set_face_uint32, cb_g_polygon_set_face_uint32, NULL);
+ verse_callback_set(verse_send_g_polygon_set_face_real32, cb_g_polygon_set_face_real32, NULL);
+
+ /* crease of vertex was set */
+ verse_callback_set(verse_send_g_crease_set_vertex, cb_g_crease_set_vertex, NULL);
+ /* crease of edge was set */
+ verse_callback_set(verse_send_g_crease_set_edge, cb_g_crease_set_edge, NULL);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/verse_method.c b/source/blender/blenkernel/intern/verse_method.c
new file mode 100644
index 00000000000..20f7e2c9f9d
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_method.c
@@ -0,0 +1,523 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Nathan Letwory.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+#include "DNA_text_types.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BIF_verse.h"
+
+#include "BKE_bad_level_calls.h"
+#include "BKE_library.h"
+#include "BKE_text.h"
+#include "BKE_verse.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "verse.h"
+
+/* helper struct for creating method descriptions */
+typedef struct VMethodInfo {
+ const char *name;
+ uint8 param_count;
+ const VNOParamType param_type[4];
+ const char *param_name[4];
+ uint16 id;
+} VMethodInfo;
+
+#ifdef VERSECHAT
+/* array with methods for verse chat */
+static VMethodInfo vmethod_info[] = {
+ { "join", 1, { VN_O_METHOD_PTYPE_STRING }, { "channel"}},
+ { "leave", 1, { VN_O_METHOD_PTYPE_STRING }, { "channel"}},
+ { "hear", 3, { VN_O_METHOD_PTYPE_STRING, VN_O_METHOD_PTYPE_STRING, VN_O_METHOD_PTYPE_STRING }, { "channel", "from", "msg"}}
+};
+#endif
+
+/* lookup a method group based on its name */
+struct VMethodGroup *lookup_vmethodgroup_name(ListBase *lb, const char *name) {
+ struct VMethodGroup *vmg;
+
+ for(vmg= lb->first; vmg; vmg= vmg->next)
+ if(strcmp(vmg->name,name)==0) break;
+
+ return vmg;
+}
+
+/* lookup a method group based on its group_id */
+struct VMethodGroup *lookup_vmethodgroup(ListBase *lb, uint16 group_id) {
+ struct VMethodGroup *vmg;
+
+ for(vmg= lb->first; vmg; vmg= vmg->next)
+ if(vmg->group_id==group_id) break;
+
+ return vmg;
+}
+
+/* lookup a method based on its name */
+struct VMethod *lookup_vmethod_name(ListBase *lb, const char *name) {
+ struct VMethod *vm;
+ for(vm= lb->first; vm; vm= vm->next)
+ if(strcmp(vm->name,name)==0) break;
+
+ return vm;
+}
+
+/* lookup a method based on its method_id */
+struct VMethod *lookup_vmethod(ListBase *lb, uint8 method_id) {
+ struct VMethod *vm;
+ for(vm= lb->first; vm; vm= vm->next)
+ if(vm->id==method_id) break;
+
+ return vm;
+}
+
+#ifdef VERSECHAT
+/*
+ * send say command
+ */
+void send_say(const char *chan, const char *utter)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ VNOPackedParams *utterpack;
+ VNOParam args[2];
+
+ vnode= (VNode *)(session->nodes.lb.first);
+
+ for( ; vnode; vnode= vnode->next) {
+ if(strcmp(vnode->name, "tawksrv")==0) {
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
+ if(!vmg) break;
+ vm= lookup_vmethod_name(&(vmg->methods), "say");
+ if(!vm) break;
+ args[0].vstring= (char *)chan;
+ args[1].vstring= (char *)utter;
+ if((utterpack= verse_method_call_pack(vm->param_count, vm->param_type, args))!=NULL) {
+ verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, utterpack);
+ }
+ break;
+ }
+
+ }
+}
+
+/*
+ * send logout command
+ */
+void send_logout(VNode *vnode)
+{
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ VNOPackedParams *pack;
+
+ vnode->chat_flag = CHAT_LOGGED;
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
+ if(!vmg) return;
+ vm= lookup_vmethod_name(&(vmg->methods), "logout");
+ if(!vm) return;
+
+ if((pack= verse_method_call_pack(vm->param_count, vm->param_type, NULL))!=NULL) {
+ verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, pack);
+ }
+ vnode->chat_flag = CHAT_NOTLOGGED;
+}
+
+/*
+ * send join command
+ */
+void send_join(VNode *vnode, const char *chan)
+{
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ VNOPackedParams *join;
+ VNOParam channel[1];
+
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
+ if(!vmg) return;
+ vm= lookup_vmethod_name(&(vmg->methods), "join");
+ if(!vm) return;
+
+ channel[0].vstring= (char *)chan;
+ if((join= verse_method_call_pack(vm->param_count, vm->param_type, channel))!=NULL) {
+ verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, join);
+ }
+}
+
+/*
+ * send leave command
+ */
+void send_leave(VNode *vnode, const char *chan)
+{
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ VNOPackedParams *leave;
+ VNOParam channel[1];
+
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
+ if(!vmg) return;
+ vm= lookup_vmethod_name(&(vmg->methods), "leave");
+ if(!vm) return;
+
+ channel[0].vstring= (char *)chan;
+ if((leave= verse_method_call_pack(vm->param_count, vm->param_type, channel))!=NULL) {
+ verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, leave);
+ }
+}
+
+/*
+ * send login command
+ */
+void send_login(VNode *vnode)
+{
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ VNOPackedParams *login;
+ VNOParam param[1];
+
+ vnode->chat_flag = CHAT_LOGGED;
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
+ if(!vmg) return;
+ vm= lookup_vmethod_name(&(vmg->methods), "login");
+ if(!vm) return;
+
+ param[0].vstring= U.verseuser;
+
+ if((login= verse_method_call_pack(vm->param_count, vm->param_type, param))!=NULL) {
+ verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, login);
+ }
+ vnode->chat_flag = CHAT_LOGGED;
+
+ vnode= lookup_vnode(vnode->session, vnode->session->avatar);
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk-client");
+ if(!vmg)
+ verse_send_o_method_group_create(vnode->session->avatar, ~0, "tawk-client");
+}
+#endif
+
+/*
+ * Free a VMethod
+ */
+void free_verse_method(VMethod *vm) {
+ if(!vm) return;
+
+ MEM_freeN(vm->param_type);
+}
+
+/*
+ * Free methods for VMethodGroup
+ */
+void free_verse_methodgroup(VMethodGroup *vmg)
+{
+ struct VMethod *vm, *tmpvm;
+
+ if(!vmg) return;
+
+ vm= vmg->methods.first;
+ while(vm) {
+ tmpvm=vm->next;
+ free_verse_method(vm);
+ vm= tmpvm;
+ }
+ BLI_freelistN(&(vmg->methods));
+}
+
+/* callback for method group creation */
+static void cb_o_method_group_create(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ const char *name)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ vmg = lookup_vmethodgroup(&(vnode->methodgroups), group_id);
+
+ /* create method group holder in node node_id */
+ if(!vmg) {
+ vmg= MEM_mallocN(sizeof(VMethodGroup), "VMethodGroup");
+ vmg->group_id = group_id;
+ vmg->methods.first = vmg->methods.last = NULL;
+ BLI_addtail(&(vnode->methodgroups), vmg);
+ printf("new method group with name %s (group_id %d) for node %u created\n", name, group_id, node_id);
+ }
+
+ /* this ensures name of an existing group gets updated, in case it is changed */
+ BLI_strncpy(vmg->name, (char *)name, 16);
+
+ /* subscribe to method group */
+ verse_send_o_method_group_subscribe(node_id, group_id);
+
+#ifdef VERSECHAT
+ /* if this is our own method group, register our methods */
+ if(node_id==session->avatar) {
+ verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[0].name,
+ vmethod_info[0].param_count,
+ (VNOParamType *)vmethod_info[0].param_type,
+ (const char **)vmethod_info[0].param_name);
+ b_verse_update();
+ verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[1].name,
+ vmethod_info[1].param_count,
+ (VNOParamType *)vmethod_info[1].param_type,
+ (const char **)vmethod_info[1].param_name);
+ b_verse_update();
+ verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[2].name,
+ vmethod_info[2].param_count,
+ (VNOParamType *)vmethod_info[2].param_type,
+ (const char **)vmethod_info[2].param_name);
+ b_verse_update();
+ }
+#endif
+}
+
+/* callback for method group destruction */
+static void cb_o_method_group_destroy(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ const char *name)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+
+ printf("method group %d destroyed\n", group_id);
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ for(vmg= vnode->methodgroups.first; vmg; vmg= vmg->next)
+ if(vmg->group_id==group_id) break;
+
+ if(!vmg) return; /* method group doesn't exist? */
+
+ vmg->group_id = 0;
+ vmg->name[0] = '\0';
+ vm= vmg->methods.first;
+ while(vm) {
+ /* free vm */
+
+ }
+
+ /* TODO: unsubscribe from method group */
+ BLI_remlink(&(vnode->methodgroups),vmg);
+ MEM_freeN(vmg);
+}
+
+/* callback for method creation */
+static void cb_o_method_create(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ uint16 method_id,
+ const char *name,
+ uint8 param_count,
+ const VNOParamType *param_type,
+ const char *param_name[])
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ unsigned int size;
+ unsigned int i;
+ char *put;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ vmg= lookup_vmethodgroup((&vnode->methodgroups), group_id);
+
+ if(!vmg) return;
+
+ vm= lookup_vmethod((&vmg->methods), method_id);
+
+ if(!vm) {
+ vm= MEM_mallocN(sizeof(VMethod), "VMethod");
+ vm->id= method_id;
+ vm->param_count= param_count;
+ size= param_count* (sizeof(*vm->param_type) + sizeof(*vm->param_name));
+ for(i= 0; i <param_count; i++) {
+ size+=strlen(param_name[i])+1;
+ }
+ vm->param_type= MEM_mallocN(size, "param_type and param_name");
+ memcpy(vm->param_type, param_type, sizeof(VNOParamType)*param_count);
+ vm->param_name= (char **)(vm->param_type + param_count);
+ put= (char *)(vm->param_name + param_count);
+ for(i= 0; i < param_count; i++) {
+ vm->param_name[i]= put;
+ strcpy(put, param_name[i]);
+ put += strlen(param_name[i]) + 1;
+ }
+
+ BLI_addtail(&(vmg->methods), vm);
+#ifdef VERSECHAT
+ if(strcmp(vmethod_info[0].name, name)==0) {
+ vmethod_info[0].id = method_id;
+ }
+#endif
+ printf("method %s in group %d of node %u created\n", name, group_id, node_id);
+ }
+
+ BLI_strncpy(vm->name, (char *)name, 500);
+}
+
+/* callback for method destruction */
+static void cb_o_method_destroy(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ uint16 method_id,
+ const char *name,
+ uint8 param_count,
+ const VNOParamType *param_type,
+ const char *param_name[])
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ for(vmg= vnode->methodgroups.first; vmg; vmg= vmg->next)
+ if(vmg->group_id==group_id) break;
+
+ if(!vmg) return; /* method group doesn't exist? */
+
+ for(vm= vmg->methods.first; vm; vm= vm->next)
+ if(vm->id==method_id) break;
+
+ if(!vm) return;
+
+ BLI_remlink(&(vmg->methods), vm);
+ MEM_freeN(vm->param_type);
+ MEM_freeN(vm);
+}
+
+/* callback for method calls */
+static void cb_o_method_call(void *user_data, VNodeID node_id, uint8 group_id, uint8 method_id, VNodeID sender, VNOPackedParams *params)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ Text *text;
+ int method_idx= -1;
+
+ VNOParam arg[3];
+
+ if(!session) return;
+
+ if(session->avatar!=node_id) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ vmg= lookup_vmethodgroup(&(vnode->methodgroups), group_id);
+ if(!vmg) return;
+
+ vm= lookup_vmethod(&(vmg->methods), method_id);
+ if(!vm) return;
+#ifdef VERSECHAT
+ if(strcmp(vm->name, "join")==0) method_idx=0;
+ if(strcmp(vm->name, "leave")==0) method_idx=1;
+ if(strcmp(vm->name, "hear")==0) method_idx=2;
+ if(method_idx>-1)
+ verse_method_call_unpack(params, vmethod_info[method_idx].param_count, vmethod_info[method_idx].param_type, arg);
+
+ switch(method_idx) {
+ case 0:
+ printf("Joining channel %s\n",arg[0].vstring);
+ text=add_empty_text();
+ text->flags |= TXT_ISCHAT;
+ rename_id(&(text->id), arg[0].vstring);
+ break;
+ case 1:
+ printf("Leaving channel %s\n",arg[0].vstring);
+ break;
+ case 2:
+ {
+ ListBase lb = G.main->text;
+ ID *id= (ID *)lb.first;
+ char showstr[1024];
+ showstr[0]='\0';
+ text = NULL;
+ sprintf(showstr, "%s: %s\n", arg[1].vstring, arg[2].vstring);
+ for(; id; id= id->next) {
+ if(strcmp(id->name+2, arg[0].vstring)==0 && strcmp(arg[0].vstring, "#server")!=0) {
+ text = (Text *)id;
+ break;
+ }
+ }
+ if(text) {
+ txt_insert_buf(text, showstr);
+ txt_move_eof(text, 0);
+ allqueue(REDRAWCHAT, 0);
+ } else {
+ printf("%s> %s: %s\n",arg[0].vstring, arg[1].vstring, arg[2].vstring);
+ }
+ }
+ break;
+ }
+#endif
+}
+
+void set_method_callbacks(void)
+{
+ /* create and destroy method groups */
+ verse_callback_set(verse_send_o_method_group_create, cb_o_method_group_create, NULL);
+ verse_callback_set(verse_send_o_method_group_destroy, cb_o_method_group_destroy, NULL);
+
+ /* create and destroy methods */
+ verse_callback_set(verse_send_o_method_create, cb_o_method_create, NULL);
+ verse_callback_set(verse_send_o_method_destroy, cb_o_method_destroy, NULL);
+
+ /* call methods */
+ verse_callback_set(verse_send_o_method_call, cb_o_method_call, NULL);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/verse_node.c b/source/blender/blenkernel/intern/verse_node.c
new file mode 100644
index 00000000000..682ae773da5
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_node.c
@@ -0,0 +1,750 @@
+/**
+ * $Id: verse_node.c 12931 2007-12-17 18:20:48Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+
+#include "BIF_verse.h"
+
+#include "BKE_verse.h"
+
+#include "verse.h"
+
+/* function prototypes of static functions */
+ /* for tags */
+static void free_verse_tag_data(struct VTag *vtag);
+static struct VTag *find_tag_in_queue(struct VTagGroup *vtaggroup, const char *name);
+static struct VTag *create_verse_tag(struct VTagGroup *vtaggroup, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag);
+ /* for verse tag groups */
+static void free_verse_taggroup_data(struct VTagGroup *taggroup);
+static struct VTagGroup *find_taggroup_in_queue(struct VNode *vnode, const char *name);
+static struct VTagGroup *create_verse_taggroup(VNode *vnode, uint16 group_id, const char *name);
+ /* for verse nodes */
+static void move_verse_node_to_dlist(struct VerseSession *session, VNodeID vnode_id);
+ /* function prototypes of node callback functions */
+static void cb_tag_destroy(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id);
+static void cb_tag_create(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag);
+static void cb_tag_group_destroy(void *user_data, VNodeID node_id, uint16 group_id);
+static void cb_tag_group_create(void *user_data, VNodeID node_id, uint16 group_id, const char *name);
+static void cb_node_name_set(void *user_data, VNodeID node_id, const char *name);
+static void cb_node_destroy(void *user_data, VNodeID node_id);
+static void cb_node_create(void *user_data, VNodeID node_id, uint8 type, VNodeID owner_id);
+
+/*
+ * send new tag to verse server
+ */
+void send_verse_tag(VTag *vtag)
+{
+ verse_send_tag_create(vtag->vtaggroup->vnode->id,
+ vtag->vtaggroup->id,
+ vtag->id,
+ vtag->name,
+ vtag->type,
+ vtag->tag);
+}
+
+/*
+ * free tag data
+ */
+static void free_verse_tag_data(VTag *vtag)
+{
+ /* free name of verse tag */
+ MEM_freeN(vtag->name);
+ /* free value of tag */
+ MEM_freeN(vtag->tag);
+}
+
+/*
+ * try to find tag in sending queue ... if tag will be found, then
+ * this function will removed tag from queue and will return pointer
+ * at this tag
+ */
+static VTag *find_tag_in_queue(VTagGroup *vtaggroup, const char *name)
+{
+ struct VTag *vtag;
+
+ vtag = vtaggroup->queue.first;
+
+ while(vtag) {
+ if(strcmp(vtag->name, name)==0) {
+ BLI_remlink(&(vtaggroup->queue), vtag);
+ break;
+ }
+ vtag = vtag->next;
+ }
+
+ return vtag;
+}
+
+/*
+ * create new verse tag
+ */
+static VTag *create_verse_tag(
+ VTagGroup *vtaggroup,
+ uint16 tag_id,
+ const char *name,
+ VNTagType type,
+ const VNTag *tag)
+{
+ struct VTag *vtag;
+
+ vtag = (VTag*)MEM_mallocN(sizeof(VTag), "VTag");
+
+ vtag->vtaggroup = vtaggroup;
+ vtag->id = tag_id;
+ vtag->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VTag name");
+ strcpy(vtag->name, name);
+ vtag->type = type;
+
+ vtag->tag = (VNTag*)MEM_mallocN(sizeof(VNTag), "VNTag");
+ *vtag->tag = *tag;
+
+ vtag->value = NULL;
+
+ return vtag;
+}
+
+/*
+ * send taggroup to verse server
+ */
+void send_verse_taggroup(VTagGroup *vtaggroup)
+{
+ verse_send_tag_group_create(
+ vtaggroup->vnode->id,
+ vtaggroup->id,
+ vtaggroup->name);
+}
+
+/*
+ * free taggroup data
+ */
+static void free_verse_taggroup_data(VTagGroup *taggroup)
+{
+ struct VerseSession *session = taggroup->vnode->session;
+ struct VTag *vtag;
+
+ vtag = taggroup->tags.lb.first;
+
+ while(vtag) {
+ free_verse_tag_data(vtag);
+ vtag = vtag->next;
+ }
+
+ /* unsubscribe from taggroup */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_tag_group_unsubscribe(taggroup->vnode->id, taggroup->id);
+
+ BLI_dlist_destroy(&(taggroup->tags));
+ MEM_freeN(taggroup->name);
+}
+
+/*
+ * move taggroup from queue to dynamic list with access array,
+ * set up taggroup id and return pointer at this taggroup
+ */
+static VTagGroup *find_taggroup_in_queue(VNode *vnode, const char *name)
+{
+ struct VTagGroup *vtaggroup;
+
+ vtaggroup = vnode->queue.first;
+
+ while(vtaggroup) {
+ if(strcmp(vtaggroup->name, name)==0) {
+ BLI_remlink(&(vnode->queue), vtaggroup);
+ break;
+ }
+ vtaggroup = vtaggroup->next;
+ }
+
+ return vtaggroup;
+}
+
+/*
+ * create new verse group of tags
+ */
+static VTagGroup *create_verse_taggroup(VNode *vnode, uint16 group_id, const char *name)
+{
+ struct VTagGroup *taggroup;
+
+ taggroup = (VTagGroup*)MEM_mallocN(sizeof(VTagGroup), "VTagGroup");
+
+ taggroup->vnode = vnode;
+ taggroup->id = group_id;
+ taggroup->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VTagGroup name");
+ strcpy(taggroup->name, name);
+
+ BLI_dlist_init(&(taggroup->tags));
+ taggroup->queue.first = taggroup->queue.last = NULL;
+
+ taggroup->post_tag_change = post_tag_change;
+ taggroup->post_taggroup_create = post_taggroup_create;
+
+ return taggroup;
+}
+
+/*
+ * move first VerseNode waiting in sending queue to dynamic list of VerseNodes
+ * (it usually happens, when "our" VerseNode was received from verse server)
+ */
+static void move_verse_node_to_dlist(VerseSession *session, VNodeID vnode_id)
+{
+ VNode *vnode;
+
+ vnode = session->queue.first;
+
+ if(vnode) {
+ BLI_remlink(&(session->queue), vnode);
+ BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, vnode_id);
+ }
+}
+
+/*
+ * send VerseNode to verse server
+ */
+void send_verse_node(VNode *vnode)
+{
+ verse_send_node_create(
+ vnode->id,
+ vnode->type,
+ vnode->session->avatar);
+}
+
+/*
+ * free Verse Node data
+ */
+void free_verse_node_data(VNode *vnode)
+{
+ struct VerseSession *session = vnode->session;
+ struct VTagGroup *vtaggroup;
+
+ /* free node data (object, geometry, etc.) */
+ switch(vnode->type){
+ case V_NT_OBJECT:
+ free_object_data(vnode);
+ break;
+ case V_NT_GEOMETRY:
+ free_geom_data(vnode);
+ break;
+ case V_NT_BITMAP:
+ free_bitmap_node_data(vnode);
+ break;
+ default:
+ break;
+ }
+
+ /* free all tag groups in dynamic list with access array */
+ vtaggroup = vnode->taggroups.lb.first;
+ while(vtaggroup) {
+ free_verse_taggroup_data(vtaggroup);
+ vtaggroup = vtaggroup->next;
+ }
+ BLI_dlist_destroy(&(vnode->taggroups));
+
+ /* free all tag groups still waiting in queue */
+ vtaggroup = vnode->queue.first;
+ while(vtaggroup) {
+ free_verse_taggroup_data(vtaggroup);
+ vtaggroup = vtaggroup->next;
+ }
+ BLI_freelistN(&(vnode->queue));
+
+ /* unsubscribe from node */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_node_unsubscribe(vnode->id);
+
+ /* free node name */
+ MEM_freeN(vnode->name);
+ vnode->name = NULL;
+
+ /* free node data */
+ MEM_freeN(vnode->data);
+ vnode->data = NULL;
+
+}
+
+/*
+ * free VerseNode
+ */
+void free_verse_node(VNode *vnode)
+{
+ free_verse_node_data(vnode);
+
+ BLI_dlist_free_item(&(vnode->session->nodes), vnode->id);
+}
+
+/*
+ * Find a Verse Node from session
+ */
+VNode* lookup_vnode(VerseSession *session, VNodeID node_id)
+{
+ struct VNode *vnode;
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ return vnode;
+}
+
+/*
+ * create new Verse Node
+ */
+VNode* create_verse_node(VerseSession *session, VNodeID node_id, uint8 type, VNodeID owner_id)
+{
+ struct VNode *vnode;
+
+ vnode = (VNode*)MEM_mallocN(sizeof(VNode), "VerseNode");
+
+ vnode->session = session;
+ vnode->id = node_id;
+ vnode->owner_id = owner_id;
+ vnode->name = NULL;
+ vnode->type = type;
+
+ BLI_dlist_init(&(vnode->taggroups));
+ vnode->queue.first = vnode->queue.last = NULL;
+ vnode->methodgroups.first = vnode->methodgroups.last = NULL;
+
+ vnode->data = NULL;
+
+ vnode->counter = 0;
+
+ vnode->flag = 0;
+#ifdef VERSECHAT
+ vnode->chat_flag = CHAT_NOTLOGGED;
+#endif
+
+ vnode->post_node_create = post_node_create;
+ vnode->post_node_destroy = post_node_destroy;
+ vnode->post_node_name_set = post_node_name_set;
+
+ return vnode;
+}
+
+/*
+ * callback function: tag was destroyed
+ */
+static void cb_tag_destroy(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ uint16 tag_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VTagGroup *vtaggroup;
+ struct VTag *vtag;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ /* try to find tag group in list of tag groups */
+ vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id);
+
+ if(!vtaggroup) return;
+
+ /* try to find verse tag in dynamic list of tags in tag group */
+ vtag = (VTag*)BLI_dlist_find_link(&(vtaggroup->tags), tag_id);
+
+ if(vtag) {
+ free_verse_tag_data(vtag);
+ BLI_dlist_free_item(&(vtaggroup->tags), vtag->id);
+ }
+}
+
+/*
+ * callback function: new tag was created
+ */
+static void cb_tag_create(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ uint16 tag_id,
+ const char *name,
+ VNTagType type,
+ const VNTag *tag)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VTagGroup *vtaggroup;
+ struct VTag *vtag;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ /* try to find tag group in list of tag groups */
+ vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id);
+
+ if(!vtaggroup) return;
+
+ /* try to find verse tag in dynamic list of tags in tag group */
+ vtag = (VTag*)BLI_dlist_find_link(&(vtaggroup->tags), tag_id);
+
+ if(!vtag) {
+ /* we will try to find vtag in sending queue */
+ vtag = find_tag_in_queue(vtaggroup, name);
+
+ /* when we didn't create this tag, then we will have to create one */
+ if(!vtag) vtag = create_verse_tag(vtaggroup, tag_id, name, type, tag);
+ else vtag->id = tag_id;
+
+ /* add tag to the list of tags in tag group */
+ BLI_dlist_add_item_index(&(vtaggroup->tags), vtag, tag_id);
+
+ /* post change/create method */
+ vtaggroup->post_tag_change(vtag);
+ }
+ else {
+ /* this tag exists, then we will propably change value of this tag */
+ if((vtag->type != type) || (strcmp(vtag->name, name)!=0)) {
+ /* changes of type or name are not allowed and such
+ * stupid changes will be returned back */
+ send_verse_tag(vtag);
+ }
+ else {
+ /* post change/create method */
+ vtaggroup->post_tag_change(vtag);
+ }
+ }
+}
+
+/*
+ * callback function: tag group was destroyed
+ */
+static void cb_tag_group_destroy(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VTagGroup *vtaggroup;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id);
+
+ if(vtaggroup) {
+ free_verse_taggroup_data(vtaggroup);
+ BLI_dlist_free_item(&(vnode->taggroups), vtaggroup->id);
+ }
+}
+
+/*
+ * callback function: new tag group was created
+ */
+static void cb_tag_group_create(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ const char *name)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VTagGroup *vtaggroup;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ /* name of taggroup has to begin with string "blender:" */
+ if(strncmp("blender:", name, 8)) return;
+
+ /* try to find tag group in list of tag groups */
+ vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id);
+
+ if(!vtaggroup) {
+ /* subscribe to tag group (when new tag will be created, then blender will
+ * receive command about it) */
+ verse_send_tag_group_subscribe(vnode->id, group_id);
+ verse_callback_update(0);
+
+ /* try to find taggroup in waiting queue */
+ vtaggroup = find_taggroup_in_queue(vnode, name);
+
+ /* if no taggroup exist, then new has to be created */
+ if(!vtaggroup) vtaggroup = create_verse_taggroup(vnode, group_id, name);
+ else vtaggroup->id = group_id;
+
+ /* add tag group to dynamic list with access array */
+ BLI_dlist_add_item_index(&(vnode->taggroups), (void*)vtaggroup, (unsigned int)group_id);
+
+ /* post create method */
+ vtaggroup->post_taggroup_create(vtaggroup);
+ }
+ else {
+ /* this taggroup exist and somebody try to change its name */
+ if(strcmp(vtaggroup->name, name)!=0) {
+ /* blender doesn't allow such stupid and dangerous things */
+ send_verse_taggroup(vtaggroup);
+ }
+ }
+}
+
+/*
+ * callback function: change name of node
+ */
+static void cb_node_name_set(
+ void *user_data,
+ VNodeID node_id,
+ const char *name)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(vnode && name) {
+ if(!vnode->name) {
+ vnode->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VerseNode name");
+ }
+ else if(strlen(name) > strlen(vnode->name)) {
+ MEM_freeN(vnode->name);
+ vnode->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VerseNode name");
+ }
+ strcpy(vnode->name, name);
+
+ vnode->post_node_name_set(vnode);
+ }
+}
+
+/*
+ * callback function for deleting node
+ */
+static void cb_node_destroy(
+ void *user_data,
+ VNodeID node_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ if(vnode) {
+ /* remove VerseNode from dynamic list */
+ BLI_dlist_rem_item(&(session->nodes), (unsigned int)node_id);
+ /* do post destroy operations */
+ vnode->post_node_destroy(vnode);
+ /* free verse data */
+ free_verse_node_data(vnode);
+ /* free VerseNode */
+ MEM_freeN(vnode);
+ };
+}
+
+
+/*
+ * callback function for new created node
+ */
+static void cb_node_create(
+ void *user_data,
+ VNodeID node_id,
+ uint8 type,
+ VNodeID owner_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode = NULL;
+
+ if(!session) return;
+
+ /* subscribe to node */
+ if((type==V_NT_OBJECT) || (type==V_NT_GEOMETRY) || (type==V_NT_BITMAP))
+ verse_send_node_subscribe(node_id);
+ else
+ return;
+
+ switch(type){
+ case V_NT_OBJECT :
+ if(owner_id==VN_OWNER_MINE) {
+ struct VLink *vlink;
+ /* collect VerseNode from VerseNode queue */
+ move_verse_node_to_dlist(session, node_id);
+ /* send next VerseNode waiting in queue */
+ if(session->queue.first) send_verse_node(session->queue.first);
+ /* get received VerseNode from list of VerseNodes */
+ vnode = BLI_dlist_find_link(&(session->nodes), node_id);
+ /* set up ID */
+ vnode->id = node_id;
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* find unsent link pointing at this VerseNode */
+ vlink = find_unsent_child_vlink(session, vnode);
+ /* send VerseLink */
+ if(vlink) send_verse_link(vlink);
+ /* send name of object node */
+ verse_send_node_name_set(node_id, vnode->name);
+ /* subscribe to changes of object node transformations */
+ verse_send_o_transform_subscribe(node_id, 0);
+ /* send object transformation matrix */
+ send_verse_object_position(vnode);
+ send_verse_object_rotation(vnode);
+ send_verse_object_scale(vnode);
+ }
+ else {
+ /* create new VerseNode */
+ vnode = create_verse_node(session, node_id, type, owner_id);
+ /* add VerseNode to list of nodes */
+ BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id);
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* create object data */
+ vnode->data = create_object_data();
+ /* set up avatar's name */
+ if(node_id == session->avatar) {
+ verse_send_node_name_set(node_id, U.verseuser);
+ }
+ else if(session->flag & VERSE_AUTOSUBSCRIBE) {
+ /* subscribe to changes of object node transformations */
+ verse_send_o_transform_subscribe(node_id, 0);
+ }
+ }
+ break;
+ case V_NT_GEOMETRY :
+ if(owner_id==VN_OWNER_MINE){
+ struct VLink *vlink;
+ struct VLayer *vlayer;
+ /* collect VerseNode from VerseNode queue */
+ move_verse_node_to_dlist(session, node_id);
+ /* send next VerseNode waiting in queue */
+ if(session->queue.first) send_verse_node(session->queue.first);
+ /* get received VerseNode from list of VerseNodes */
+ vnode = BLI_dlist_find_link(&(session->nodes), node_id);
+ /* set up ID */
+ vnode->id = node_id;
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* find unsent link pointing at this VerseNode */
+ vlink = find_unsent_parent_vlink(session, vnode);
+ /* send VerseLink */
+ if(vlink) send_verse_link(vlink);
+ /* send name of geometry node */
+ verse_send_node_name_set(node_id, vnode->name);
+ /* send all not sent layer to verse server */
+ vlayer = (VLayer*)((VGeomData*)vnode->data)->queue.first;
+ if(vlayer) {
+ while(vlayer) {
+ send_verse_layer(vlayer);
+ vlayer = vlayer->next;
+ }
+ }
+ else {
+ /* send two verse layers to verse server */
+/* verse_send_g_layer_create(node_id, 0, "vertex", VN_G_LAYER_VERTEX_XYZ, 0, 0);
+ verse_send_g_layer_create(node_id, 1, "polygon", VN_G_LAYER_POLYGON_CORNER_UINT32, 0, 0);*/
+ }
+ }
+ else {
+ /* create new VerseNode*/
+ vnode = create_verse_node(session, node_id, type, owner_id);
+ /* add VerseNode to dlist of nodes */
+ BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id);
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* create geometry data */
+ vnode->data = (void*)create_geometry_data();
+ }
+ break;
+ case V_NT_BITMAP :
+ if(owner_id==VN_OWNER_MINE) {
+ /* collect VerseNode from VerseNode queue */
+ move_verse_node_to_dlist(session, node_id);
+ /* send next VerseNode waiting in queue */
+ if(session->queue.first) send_verse_node(session->queue.first);
+ /* get received VerseNode from list of VerseNodes */
+ vnode = BLI_dlist_find_link(&(session->nodes), node_id);
+ /* set up ID */
+ vnode->id = node_id;
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* send name of object node */
+ verse_send_node_name_set(node_id, vnode->name);
+ /* send dimension of image to verse server */
+ verse_send_b_dimensions_set(node_id,
+ ((VBitmapData*)vnode->data)->width,
+ ((VBitmapData*)vnode->data)->height,
+ ((VBitmapData*)vnode->data)->depth);
+ }
+ else {
+ /* create new VerseNode*/
+ vnode = create_verse_node(session, node_id, type, owner_id);
+ /* add VerseNode to dlist of nodes */
+ BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id);
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* create bitmap data */
+ vnode->data = (void*)create_bitmap_data();
+ }
+ break;
+ default:
+ vnode = NULL;
+ break;
+ }
+
+ if(vnode) vnode->post_node_create(vnode);
+}
+
+/*
+ * set up all callbacks for verse nodes
+ */
+void set_node_callbacks(void)
+{
+ /* new node created */
+ verse_callback_set(verse_send_node_create, cb_node_create, NULL);
+ /* node was deleted */
+ verse_callback_set(verse_send_node_destroy, cb_node_destroy, NULL);
+ /* name of node was set */
+ verse_callback_set(verse_send_node_name_set, cb_node_name_set, NULL);
+
+ /* new tag group was created */
+ verse_callback_set(verse_send_tag_group_create, cb_tag_group_create, NULL);
+ /* tag group was destroy */
+ verse_callback_set(verse_send_tag_group_destroy, cb_tag_group_destroy, NULL);
+
+ /* new tag was created */
+ verse_callback_set(verse_send_tag_create, cb_tag_create, NULL);
+ /* tag was destroy */
+ verse_callback_set(verse_send_tag_destroy, cb_tag_destroy, NULL);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/verse_object_node.c b/source/blender/blenkernel/intern/verse_object_node.c
new file mode 100644
index 00000000000..fc5a27cd5d9
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_object_node.c
@@ -0,0 +1,620 @@
+/**
+ * $Id: verse_object_node.c 12931 2007-12-17 18:20:48Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BIF_verse.h"
+
+#include "BKE_verse.h"
+#include "BKE_utildefines.h"
+
+#include "verse.h"
+
+/* function prototypes of static functions */
+
+/* callback functions */
+static void cb_o_transform_pos_real32(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const real32 *pos, const real32 *speed, const real32 *accelerate, const real32 *drag_normal, real32 drag);
+static void cb_o_transform_rot_real32(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat32 *temp, const VNQuat32 *speed, const VNQuat32 *accelerate, const VNQuat32 *drag_normal, real32 drag);
+static void cb_o_transform_scale_real32(void *user_data, VNodeID node_id, real32 scale_x, real32 scale_y, real32 scale_z);
+static void cb_o_link_set(void *user_data, VNodeID node_id, uint16 link_id, VNodeID link, const char *label, uint32 target_id);
+static void cb_o_link_destroy(void *user_data, VNodeID node_id,uint16 link_id);
+
+/* other functions */
+static void set_target_node_link_pointer(struct VNode *vnode, struct VLink *vlink);
+static void free_verse_link_data(struct VLink *vlink);
+
+/*
+ * find noy sent VerseLink in queue
+ */
+VLink *find_unsent_child_vlink(VerseSession *session, VNode *vnode)
+{
+ struct VLink *vlink;
+
+ if(vnode->type!=V_NT_OBJECT) return NULL;
+
+ vlink = ((VObjectData*)vnode->data)->queue.first;
+ while(vlink) {
+ if(vlink->target->id != -1) {
+ printf("\t vlink found, vnode target id %d\n", vlink->target->id);
+ return vlink;
+ }
+ vlink = vlink->next;
+ }
+ return NULL;
+}
+
+/*
+ * find unsent VerseLink "pointing at this VerseNode"
+ */
+VLink *find_unsent_parent_vlink(VerseSession *session, VNode *vnode)
+{
+ struct VNode *tmp;
+ struct VLink *vlink;
+
+ tmp = session->nodes.lb.first;
+
+ while(tmp) {
+ if(tmp->type==V_NT_OBJECT) {
+ vlink = ((VObjectData*)tmp->data)->queue.first;
+ while(vlink) {
+ if(vlink->target == vnode)
+ return vlink;
+ vlink = vlink->next;
+ }
+ }
+ tmp = tmp->next;
+ }
+ return NULL;
+}
+
+/*
+ * send object position to verse server
+ */
+void send_verse_object_position(VNode *vnode)
+{
+ float tmp;
+
+ ((VObjectData*)vnode->data)->flag &= ~POS_SEND_READY;
+
+ /* we have to do rotation around x axis (+pi/2) to be
+ compatible with other verse applications */
+ tmp = -((VObjectData*)vnode->data)->pos[1];
+ ((VObjectData*)vnode->data)->pos[1] = ((VObjectData*)vnode->data)->pos[2];
+ ((VObjectData*)vnode->data)->pos[2] = tmp;
+
+ verse_send_o_transform_pos_real32(
+ vnode->id, /* node id */
+ 0, /* time_s ... no interpolation */
+ 0, /* time_f ... no interpolation */
+ ((VObjectData*)vnode->data)->pos,
+ NULL, /* speed ... no interpolation */
+ NULL, /* accelerate ... no interpolation */
+ NULL, /* drag normal ... no interpolation */
+ 0.0); /* drag ... no interpolation */
+}
+
+/*
+ * send object rotation to verse server
+ */
+void send_verse_object_rotation(VNode *vnode)
+{
+ VNQuat32 quat;
+ float q[4] = {cos(-M_PI/4), -sin(-M_PI/4), 0, 0}, v[4], tmp[4];
+
+ /* inverse transformation to transformation in function cb_o_transform_rot_real32 */
+ mul_qt_qtqt(v, ((VObjectData*)vnode->data)->quat, q);
+ q[1]= sin(-M_PI/4);
+ mul_qt_qtqt(tmp, q, v);
+
+ quat.x = tmp[1];
+ quat.y = tmp[2];
+ quat.z = tmp[3];
+ quat.w = tmp[0];
+
+ ((VObjectData*)vnode->data)->flag &= ~ROT_SEND_READY;
+
+ verse_send_o_transform_rot_real32(
+ vnode->id, /* node id */
+ 0, /* time_s ... no interpolation */
+ 0, /* time_f ... no interpolation */
+ &quat,
+ NULL, /* speed ... no interpolation */
+ NULL, /* accelerate ... no interpolation */
+ NULL, /* drag normal ... no interpolation */
+ 0.0); /* drag ... no interpolation */
+}
+
+/*
+ * send object rotation to verse server
+ */
+void send_verse_object_scale(VNode *vnode)
+{
+ float tmp;
+
+ ((VObjectData*)vnode->data)->flag &= ~SCALE_SEND_READY;
+
+ /* we have to do rotation around x axis (+pi/2) to be
+ compatible with other verse applications */
+ tmp = ((VObjectData*)vnode->data)->scale[1];
+ ((VObjectData*)vnode->data)->scale[1] = ((VObjectData*)vnode->data)->scale[2];
+ ((VObjectData*)vnode->data)->scale[2] = tmp;
+
+ verse_send_o_transform_scale_real32(
+ vnode->id,
+ ((VObjectData*)vnode->data)->scale[0],
+ ((VObjectData*)vnode->data)->scale[1],
+ ((VObjectData*)vnode->data)->scale[2]);
+}
+
+/*
+ * send VerseLink to verse server
+ */
+void send_verse_link(VLink *vlink)
+{
+ verse_session_set(vlink->session->vsession);
+
+ verse_send_o_link_set(
+ vlink->source->id,
+ vlink->id,
+ vlink->target->id,
+ vlink->label,
+ vlink->target_id);
+}
+
+/*
+ * set up pointer at VerseLink of target node (geometry node, material node, etc.)
+ */
+static void set_target_node_link_pointer(VNode *vnode, VLink *vlink)
+{
+ switch (vnode->type) {
+ case V_NT_GEOMETRY:
+ ((VGeomData*)vnode->data)->vlink = vlink;
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * free VerseLink and it's label
+ */
+static void free_verse_link_data(VLink *vlink)
+{
+ MEM_freeN(vlink->label);
+}
+
+/*
+ * create new VerseLink
+ */
+VLink *create_verse_link(
+ VerseSession *session,
+ VNode *source,
+ VNode *target,
+ uint16 link_id,
+ uint32 target_id,
+ const char *label)
+{
+ struct VLink *vlink;
+
+ vlink = (VLink*)MEM_mallocN(sizeof(VLink), "VerseLink");
+ vlink->session = session;
+ vlink->source = source;
+ vlink->target = target;
+ vlink->id = link_id;
+ vlink->target_id = target_id;
+
+ set_target_node_link_pointer(target, vlink);
+
+ vlink->label = (char*)MEM_mallocN(sizeof(char)*(strlen(label)+1), "VerseLink label");
+ vlink->label[0] = '\0';
+ strcat(vlink->label, label);
+
+ vlink->flag = 0;
+
+ vlink->post_link_set = post_link_set;
+ vlink->post_link_destroy = post_link_destroy;
+
+ return vlink;
+}
+
+/*
+ * free ObjectData (links, links in queue and lables of links)
+ */
+void free_object_data(VNode *vnode)
+{
+ struct VerseSession *session = vnode->session;
+ struct VObjectData *obj = (VObjectData*)vnode->data;
+ struct VLink *vlink;
+ struct VMethodGroup *vmg;
+
+ if(!obj) return;
+
+ /* free all labels of links in dlist */
+ vlink = obj->links.lb.first;
+ while(vlink){
+ free_verse_link_data(vlink);
+ vlink = vlink->next;
+ }
+
+ /* free all labels of links waiting in queue */
+ vlink = obj->queue.first;
+ while(vlink){
+ free_verse_link_data(vlink);
+ vlink = vlink->next;
+ }
+ /* free dynamic list and sendig queue of links */
+ BLI_dlist_destroy(&(obj->links));
+ BLI_freelistN(&(obj->queue));
+
+ /* free method groups and their methods */
+ for(vmg = vnode->methodgroups.first; vmg; vmg= vmg->next) {
+ free_verse_methodgroup(vmg);
+ }
+ BLI_freelistN(&(vnode->methodgroups));
+
+ /* free constraint between VerseNode and Object */
+ obj->post_object_free_constraint(vnode);
+
+ /* unsubscribe from receiving changes of transformation matrix */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_o_transform_unsubscribe(vnode->id, 0);
+}
+
+/*
+ * create new object data
+ */
+VObjectData *create_object_data(void)
+{
+ VObjectData *obj;
+
+ obj = (VObjectData*)MEM_mallocN(sizeof(VObjectData), "VerseObjectData");
+ obj->object = NULL;
+ BLI_dlist_init(&(obj->links));
+ obj->queue.first = obj->queue.last = NULL;
+ obj->flag = 0;
+
+ /* transformation matrix */
+ obj->pos[0] = obj->pos[1] = obj->pos[2] = 0.0;
+ obj->quat[0] = obj->quat[1] = obj->quat[2] = 0.0; obj->quat[3] = 1;
+ obj->scale[0] = obj->scale[1] = obj->scale[2] = 1.0;
+
+ /* transformation flags */
+ obj->flag |= POS_SEND_READY;
+ obj->flag |= ROT_SEND_READY;
+ obj->flag |= SCALE_SEND_READY;
+
+ /* set up pointers at post callback functions */
+/* obj->post_transform = post_transform;*/
+ obj->post_transform_pos = post_transform_pos;
+ obj->post_transform_rot = post_transform_rot;
+ obj->post_transform_scale = post_transform_scale;
+ obj->post_object_free_constraint = post_object_free_constraint;
+
+ return obj;
+}
+
+/*
+ * callback function:
+ */
+static void cb_o_transform_pos_real32(
+ void *user_data,
+ VNodeID node_id,
+ uint32 time_s,
+ uint32 time_f,
+ const real32 *pos,
+ const real32 *speed,
+ const real32 *accelerate,
+ const real32 *drag_normal,
+ real32 drag)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ float vec[3], dt, tmp;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ ((VObjectData*)vnode->data)->flag |= POS_SEND_READY;
+
+ /* verse server sends automaticaly some stupid default values ...
+ * we have to ignore these values, when we created this object node */
+ if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & POS_RECEIVE_READY) ) {
+ ((VObjectData*)vnode->data)->flag |= POS_RECEIVE_READY;
+ return;
+ }
+
+ dt = time_s + time_f/(0xffff);
+
+ if(pos) {
+ vec[0] = pos[0];
+ vec[1] = pos[1];
+ vec[2] = pos[2];
+ }
+ else {
+ vec[0] = 0.0f;
+ vec[1] = 0.0f;
+ vec[2] = 0.0f;
+ }
+
+ if(speed) {
+ vec[0] += speed[0]*dt;
+ vec[1] += speed[1]*dt;
+ vec[2] += speed[2]*dt;
+ }
+
+ if(accelerate) {
+ vec[0] += accelerate[0]*dt*dt/2;
+ vec[1] += accelerate[1]*dt*dt/2;
+ vec[2] += accelerate[2]*dt*dt/2;
+ }
+
+ /* we have to do rotation around x axis (+pi/2) to be
+ compatible with other verse applications */
+ tmp = vec[1];
+ vec[1] = -vec[2];
+ vec[2] = tmp;
+
+ if( (((VObjectData*)vnode->data)->pos[0] != vec[0]) ||
+ (((VObjectData*)vnode->data)->pos[1] != vec[1]) ||
+ (((VObjectData*)vnode->data)->pos[2] != vec[2]))
+ {
+ ((VObjectData*)vnode->data)->pos[0] = vec[0];
+ ((VObjectData*)vnode->data)->pos[1] = vec[1];
+ ((VObjectData*)vnode->data)->pos[2] = vec[2];
+
+ ((VObjectData*)vnode->data)->post_transform_pos(vnode);
+ }
+}
+
+/*
+ * callback function:
+ */
+static void cb_o_transform_rot_real32(
+ void *user_data,
+ VNodeID node_id,
+ uint32 time_s,
+ uint32 time_f,
+ const VNQuat32 *quat,
+ const VNQuat32 *speed,
+ const VNQuat32 *accelerate,
+ const VNQuat32 *drag_normal,
+ real32 drag)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ float temp[4]={0, 0, 0, 0}, v[4], dt; /* temporary quaternions */
+ float q[4]={cos(M_PI/4), -sin(M_PI/4), 0, 0}; /* conjugate quaternion (represents rotation
+ around x-axis +90 degrees) */
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ ((VObjectData*)vnode->data)->flag |= ROT_SEND_READY;
+
+ /* verse server sends automaticaly some stupid default values ...
+ * we have to ignore these values, when we created this object node */
+ if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & ROT_RECEIVE_READY) ) {
+ ((VObjectData*)vnode->data)->flag |= ROT_RECEIVE_READY;
+ return;
+ }
+
+ dt = time_s + time_f/(0xffff);
+
+ if(quat) {
+ temp[1] = quat->x;
+ temp[2] = quat->y;
+ temp[3] = quat->z;
+ temp[0] = quat->w;
+ }
+
+ if(speed) {
+ temp[1] += speed->x*dt;
+ temp[2] += speed->y*dt;
+ temp[3] += speed->z*dt;
+ temp[0] += speed->w*dt;
+ }
+
+ if(accelerate) {
+ temp[1] += accelerate->x*dt*dt/2;
+ temp[2] += accelerate->y*dt*dt/2;
+ temp[3] += accelerate->z*dt*dt/2;
+ temp[0] += accelerate->w*dt*dt/2;
+ }
+
+ /* following matematical operation transform rotation:
+ *
+ * v' = quaternion * v * conjugate_quaternion
+ *
+ *, where v is original representation of rotation */
+
+ mul_qt_qtqt(v, temp, q);
+ q[1]= sin(M_PI/4); /* normal quaternion */
+ mul_qt_qtqt(temp, q, v);
+
+ if( (((VObjectData*)vnode->data)->quat[0] != temp[0]) ||
+ (((VObjectData*)vnode->data)->quat[1] != temp[1]) ||
+ (((VObjectData*)vnode->data)->quat[2] != temp[2]) ||
+ (((VObjectData*)vnode->data)->quat[3] != temp[3]))
+ {
+ QUATCOPY(((VObjectData*)vnode->data)->quat, temp);
+
+ ((VObjectData*)vnode->data)->post_transform_rot(vnode);
+ }
+}
+
+/*
+ * callback function:
+ */
+static void cb_o_transform_scale_real32(
+ void *user_data,
+ VNodeID node_id,
+ real32 scale_x,
+ real32 scale_y,
+ real32 scale_z)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ real32 tmp;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ ((VObjectData*)vnode->data)->flag |= SCALE_SEND_READY;
+
+ /* verse server sends automaticaly some stupid default values ...
+ * we have to ignore these values, when we created this object node */
+ if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & SCALE_RECEIVE_READY) ) {
+ ((VObjectData*)vnode->data)->flag |= SCALE_RECEIVE_READY;
+ return;
+ }
+
+ /* flip axis (verse spec) */
+ tmp = scale_y;
+ scale_y = scale_z;
+ scale_z = tmp;
+
+ /* z and y axis are flipped here too */
+ if( (((VObjectData*)vnode->data)->scale[0] != scale_x) ||
+ (((VObjectData*)vnode->data)->scale[1] != scale_y) ||
+ (((VObjectData*)vnode->data)->scale[2] != scale_z))
+ {
+ ((VObjectData*)vnode->data)->scale[0] = scale_x;
+ ((VObjectData*)vnode->data)->scale[1] = scale_y;
+ ((VObjectData*)vnode->data)->scale[2] = scale_z;
+
+ ((VObjectData*)vnode->data)->post_transform_scale(vnode);
+ }
+}
+
+/*
+ * callback function: link between object node and some other node was created
+ */
+static void cb_o_link_set(
+ void *user_data,
+ VNodeID node_id,
+ uint16 link_id,
+ VNodeID link,
+ const char *label,
+ uint32 target_id)
+{
+ struct VLink *vlink;
+ struct VNode *source;
+ struct VNode *target;
+
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+
+ if(!session) return;
+
+ source = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ target = BLI_dlist_find_link(&(session->nodes), (unsigned int)link);
+
+ if(!(source && target)) return;
+
+ vlink = ((VObjectData*)source->data)->queue.first;
+
+ if(vlink && (vlink->source==source) && (vlink->target==target)) {
+ /* remove VerseLink from sending queue */
+ BLI_remlink(&(((VObjectData*)source->data)->queue), vlink);
+ /* add VerseLink to dynamic list of VerseLinks */
+ BLI_dlist_add_item_index(&(((VObjectData*)source->data)->links), vlink, (unsigned int)link_id);
+ /* send next link from sending queue */
+ if(((VObjectData*)source->data)->queue.first)
+ send_verse_link(((VObjectData*)source->data)->queue.first);
+ /* set up VerseLink variables */
+ vlink->flag = 0;
+ vlink->id = link_id;
+ vlink->target_id = target_id;
+ }
+ else {
+ /* create new VerseLink */
+ vlink = create_verse_link(session, source, target, link_id, target_id, label);
+ /* add VerseLink to dynamic list of VerseLinks */
+ BLI_dlist_add_item_index(&(((VObjectData*)source->data)->links), vlink, (unsigned int)link_id);
+ }
+
+ target->counter++;
+
+ vlink->post_link_set(vlink);
+}
+
+/*
+ * callback function: destroy link between two VerseNodes
+ */
+static void cb_o_link_destroy(
+ void *user_data,
+ VNodeID node_id,
+ uint16 link_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLink *vlink;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ vlink = BLI_dlist_find_link(&(((VObjectData*)vnode->data)->links), link_id);
+
+ if(vlink) {
+ vlink->target->counter--;
+ free_verse_link_data(vlink);
+ BLI_dlist_free_item(&(((VObjectData*)vnode->data)->links), link_id);
+ }
+
+ vlink->post_link_destroy(vlink);
+}
+
+void set_object_callbacks(void)
+{
+ /* position of object was changed */
+ verse_callback_set(verse_send_o_transform_pos_real32, cb_o_transform_pos_real32, NULL);
+ /* rotation of object was changed */
+ verse_callback_set(verse_send_o_transform_rot_real32, cb_o_transform_rot_real32, NULL);
+ /* size of object was changed */
+ verse_callback_set(verse_send_o_transform_scale_real32, cb_o_transform_scale_real32, NULL);
+ /* new link between nodes was created */
+ verse_callback_set(verse_send_o_link_set, cb_o_link_set, NULL);
+ /* link between nodes was destroyed */
+ verse_callback_set(verse_send_o_link_destroy, cb_o_link_destroy, NULL);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/verse_session.c b/source/blender/blenkernel/intern/verse_session.c
new file mode 100644
index 00000000000..64d6b9885fe
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_session.c
@@ -0,0 +1,480 @@
+/**
+ * $Id: verse_session.c 12931 2007-12-17 18:20:48Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h" /* temp */
+#include "DNA_listBase.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+
+#include "BIF_screen.h"
+#include "BIF_verse.h"
+
+#include "BKE_global.h"
+#include "BKE_verse.h"
+
+struct ListBase session_list={NULL, NULL};
+struct ListBase server_list={NULL, NULL};
+
+static int cb_ping_registered = 0;
+
+/* list of static function prototypes */
+static void cb_connect_terminate(const char *address, const char *bye);
+static void cb_connect_accept(void *user_data, uint32 avatar, void *address, void *connection, const uint8 *host_id);
+static void set_all_callbacks(void);
+static void free_verse_session_data(struct VerseSession *session);
+static void add_verse_server(VMSServer *server);
+static void check_connection_state(struct VerseServer *server);
+
+static void check_connection_state(struct VerseServer *server)
+{
+ struct VerseSession *session;
+ session = session_list.first;
+ while(session) {
+ if(strcmp(server->ip,session->address)==0) {
+ server->flag = session->flag;
+ return;
+ }
+ session = session->next;
+ }
+}
+/*
+ * add verse server to server_list. Prevents duplicate
+ * entries
+ */
+static void add_verse_server(VMSServer *server)
+{
+ struct VerseServer *iter, *niter;
+ VerseServer *newserver;
+ const char *name = verse_ms_field_value(server, "DE");
+ iter = server_list.first;
+
+ while(iter) {
+ niter = iter->next;
+ if(strcmp(iter->ip, server->ip)==0) {
+ return;
+ }
+ iter = niter;
+ }
+
+ newserver = (VerseServer *)MEM_mallocN(sizeof(VerseServer), "VerseServer");
+ newserver->ip = (char *)MEM_mallocN(sizeof(char)*(strlen(server->ip)+1), "VerseServer ip");
+ strcpy(newserver->ip, server->ip);
+
+ if(name) {
+ newserver->name = (char *)MEM_mallocN(sizeof(char)*(strlen(name)+strlen(newserver->ip)+4), "VerseServer name");
+ strcpy(newserver->name, name);
+ strcat(newserver->name, " (");
+ strcat(newserver->name, newserver->ip);
+ strcat(newserver->name, ")");
+ }
+
+ newserver->flag = 0;
+ check_connection_state(newserver);
+
+ printf("Adding new verse server: %s at %s\n", newserver->name, newserver->ip);
+
+ BLI_addtail(&server_list, newserver);
+ post_server_add();
+}
+
+/*
+ * callback function for ping
+ */
+static void cb_ping(void *user, const char *address, const char *message)
+{
+ VMSServer **servers = verse_ms_list_parse(message);
+ if(servers != NULL)
+ {
+ int i;
+
+ for(i = 0; servers[i] != NULL; i++)
+ add_verse_server(servers[i]);
+
+ free(servers);
+ }
+}
+
+/*
+ * callback function for connection terminated
+ */
+static void cb_connect_terminate(const char *address, const char *bye)
+{
+ VerseSession *session = (VerseSession*)current_verse_session();
+
+ if(!session) return;
+
+ /* remove session from list of session */
+ BLI_remlink(&session_list, session);
+ /* do post connect operations */
+ session->post_connect_terminated(session);
+ /* free session data */
+ free_verse_session_data(session);
+ /* free session */
+ MEM_freeN(session);
+}
+
+/*
+ * callback function for accepted connection to verse server
+ */
+static void cb_connect_accept(
+ void *user_data,
+ uint32 avatar,
+ void *address,
+ void *connection,
+ const uint8 *host_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VerseServer *server = server_list.first;
+ uint32 i, mask=0;
+
+ if(!session) return;
+
+ session->flag |= VERSE_CONNECTED;
+ session->flag &= ~VERSE_CONNECTING;
+
+ while(server) {
+ if(strcmp(session->address, server->ip)==0) {
+ server->flag |= VERSE_CONNECTED;
+ server->flag &= ~VERSE_CONNECTING;
+ server->session = session;
+ break;
+ }
+ server = server->next;
+ }
+
+ printf("\tBlender is connected to verse server: %s\n", (char*)address);
+ printf("\tVerseSession->counter: %d\n", session->counter);
+
+ session->avatar = avatar;
+
+ session->post_connect_accept(session);
+
+ for(i = 0; i < V_NT_NUM_TYPES; i++)
+ mask = mask | (1 << i);
+ verse_send_node_index_subscribe(mask);
+ verse_send_node_subscribe(session->avatar); /* subscribe to avatar node, as well */
+
+ /* create our own method group and method */
+ /*verse_send_o_method_group_create(session->avatar, ~0, "tawk-client");*/
+}
+
+/*
+ * set up all callbacks for sessions
+ */
+void set_verse_session_callbacks(void)
+{
+ /* connection */
+ verse_callback_set(verse_send_connect_accept, cb_connect_accept, NULL);
+ /* connection was terminated */
+ verse_callback_set(verse_send_connect_terminate, cb_connect_terminate, NULL);
+
+}
+
+/*
+ * set all callbacks used in Blender
+ */
+static void set_all_callbacks(void)
+{
+ /* set up all callbacks for sessions */
+ set_verse_session_callbacks();
+
+ /* set up callbacks for nodes */
+ set_node_callbacks();
+
+ /* set up all callbacks for object nodes */
+ set_object_callbacks();
+
+ /* set up all callbacks for geometry nodes */
+ set_geometry_callbacks();
+
+ /* set up all callbacks for bitmap nodes */
+ set_bitmap_callbacks();
+
+ /* set up all callbacks for method groups and methods */
+ set_method_callbacks();
+}
+
+/*
+ * this function sends and receive all packets for all sessions
+ */
+void b_verse_update(void)
+{
+ VerseSession *session, *next_session;
+
+ session = session_list.first;
+ while(session){
+ next_session = session->next;
+ verse_session_set(session->vsession);
+ if((session->flag & VERSE_CONNECTED) || (session->flag & VERSE_CONNECTING)) {
+ verse_callback_update(10);
+ session->post_connect_update(session);
+ }
+ session = next_session;
+ }
+ if(cb_ping_registered>0) {
+ verse_callback_update(10);
+ }
+}
+
+/*
+ * returns VerseSession coresponding to vsession pointer
+ */
+VerseSession *versesession_from_vsession(VSession *vsession)
+{
+ struct VerseSession *session;
+
+ session = session_list.first;
+
+ while(session) {
+ if(session->vsession==vsession) return session;
+ session = session->next;
+ }
+
+ return session;
+}
+
+/*
+ * returns pointer at current VerseSession
+ */
+VerseSession *current_verse_session(void)
+{
+ struct VerseSession *session;
+ VSession vsession = verse_session_get();
+
+ session = session_list.first;
+
+ while(session){
+ if(session->vsession == vsession)
+ return session;
+ session = session->next;
+ }
+
+ printf("error: non-existing SESSION occured!\n");
+ return NULL;
+}
+
+/*
+ * free VerseSession
+ */
+static void free_verse_session_data(VerseSession *session)
+{
+ struct VNode *vnode;
+
+ /* free data of all nodes */
+ vnode = session->nodes.lb.first;
+ while(vnode){
+ free_verse_node_data(vnode);
+ vnode = vnode->next;
+ }
+
+ /* free data of nodes waiting in queue */
+ vnode = session->queue.first;
+ while(vnode){
+ free_verse_node_data(vnode);
+ vnode = vnode->next;
+ }
+
+ /* free all VerseNodes */
+ BLI_dlist_destroy(&(session->nodes));
+ /* free all VerseNodes waiting in queque */
+ BLI_freelistN(&(session->queue));
+
+ /* free name of verse host for this session */
+ MEM_freeN(session->address);
+}
+
+/*
+ * free VerseSession
+ */
+void free_verse_session(VerseSession *session)
+{
+ /* remove session from session list*/
+ BLI_remlink(&session_list, session);
+ /* do post terminated operations */
+ session->post_connect_terminated(session);
+ /* free session data (nodes, layers) */
+ free_verse_session_data(session);
+ /* free session */
+ MEM_freeN(session);
+}
+
+/*
+ * create new verse session and return coresponding data structure
+ */
+VerseSession *create_verse_session(
+ const char *name,
+ const char *pass,
+ const char *address,
+ uint8 *expected_key)
+{
+ struct VerseSession *session;
+ VSession *vsession;
+
+ vsession = verse_send_connect(name, pass, address, expected_key);
+
+ if(!vsession) return NULL;
+
+ session = (VerseSession*)MEM_mallocN(sizeof(VerseSession), "VerseSession");
+
+ session->flag = VERSE_CONNECTING;
+
+ session->vsession = vsession;
+ session->avatar = -1;
+
+ session->address = (char*)MEM_mallocN(sizeof(char)*(strlen(address)+1),"session adress name");
+ strcpy(session->address, address);
+
+ session->connection = NULL;
+ session->host_id = NULL;
+ session->counter = 0;
+
+ /* initialize dynamic list of nodes and node queue */
+ BLI_dlist_init(&(session->nodes));
+ session->queue.first = session->queue.last = NULL;
+
+ /* set up all client dependent functions */
+ session->post_connect_accept = post_connect_accept;
+ session->post_connect_terminated = post_connect_terminated;
+ session->post_connect_update = post_connect_update;
+
+ post_server_add();
+
+ return session;
+}
+
+/*
+ * end verse session and free all session data
+ */
+void end_verse_session(VerseSession *session)
+{
+ /* send terminate command to verse server */
+ verse_send_connect_terminate(session->address, "blender: bye bye");
+ /* update callbacks */
+ verse_callback_update(1000);
+ /* send destroy session command to verse server */
+ verse_session_destroy(session->vsession);
+ /* set up flag of verse session */
+ session->flag &= ~VERSE_CONNECTED;
+ /* do post connect operations */
+ session->post_connect_terminated(session);
+ /* free structure of verse session */
+ free_verse_session(session);
+}
+
+void free_all_servers(void)
+{
+ VerseServer *server, *nextserver;
+
+ server = server_list.first;
+
+ while(server) {
+ nextserver = server->next;
+ BLI_remlink(&server_list, server);
+ MEM_freeN(server->name);
+ MEM_freeN(server->ip);
+ MEM_freeN(server);
+ server = nextserver;
+ }
+
+ BLI_freelistN(&server_list);
+}
+
+/*
+ * end connection to all verse hosts (servers) ... free all VerseSessions
+ * free all VerseServers
+ */
+void end_all_verse_sessions(void)
+{
+ VerseSession *session,*nextsession;
+
+ session = session_list.first;
+
+ while(session) {
+ nextsession= session->next;
+ end_verse_session(session);
+ /* end next session */
+ session = nextsession;
+ }
+
+ BLI_freelistN(&session_list);
+
+ free_all_servers();
+}
+
+/*
+ * do a get from ms
+ */
+void b_verse_ms_get(void)
+{
+ if(cb_ping_registered==0) {
+ /* handle ping messages (for master server) */
+ verse_callback_set(verse_send_ping, cb_ping, NULL);
+ add_screenhandler(G.curscreen, SCREEN_HANDLER_VERSE, 1);
+ cb_ping_registered++;
+ }
+ free_all_servers();
+
+ verse_ms_get_send(U.versemaster, VERSE_MS_FIELD_DESCRIPTION, NULL);
+ verse_callback_update(10);
+}
+
+/*
+ * connect to verse host, set up all callbacks, create session
+ */
+void b_verse_connect(char *address)
+{
+ VerseSession *session = NULL;
+
+ /* if no session was created before, then set up all callbacks */
+ if((session_list.first==NULL) && (session_list.last==NULL))
+ set_all_callbacks();
+
+ /* create new session */
+ if(address)
+ session = create_verse_session("Blender", "pass", address, NULL);
+
+ if(session) {
+ /* add new session to the list of sessions */
+ BLI_addtail(&session_list, session);
+
+ /* add verse handler if this is first session */
+ if(session_list.first == session_list.last)
+ add_screenhandler(G.curscreen, SCREEN_HANDLER_VERSE, 1);
+
+ }
+}
+
+#endif
diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h
index dae9c4f6e41..bd760646053 100644
--- a/source/blender/blenkernel/nla_private.h
+++ b/source/blender/blenkernel/nla_private.h
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: nla_private.h 21537 2009-07-11 22:22:53Z gsrb3d $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/blenlib/BLI_arithb.h b/source/blender/blenlib/BLI_arithb.h
new file mode 100644
index 00000000000..dd673ff095e
--- /dev/null
+++ b/source/blender/blenlib/BLI_arithb.h
@@ -0,0 +1,569 @@
+#undef TEST_ACTIVE
+//#define ACTIVE 1
+/**
+ * blenlib/BLI_math.h mar 2001 Nzc
+ *
+ * $Id$
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * */
+
+#ifndef BLI_ARITHB_H
+#define BLI_ARITHB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WIN32
+#define _USE_MATH_DEFINES
+#endif
+
+#include <math.h>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#ifndef M_PI_2
+#define M_PI_2 1.57079632679489661923
+#endif
+#ifndef M_SQRT2
+#define M_SQRT2 1.41421356237309504880
+#endif
+#ifndef M_SQRT1_2
+#define M_SQRT1_2 0.70710678118654752440
+#endif
+#ifndef M_1_PI
+#define M_1_PI 0.318309886183790671538
+#endif
+
+#ifndef M_E
+#define M_E 2.7182818284590452354
+#endif
+#ifndef M_LOG2E
+#define M_LOG2E 1.4426950408889634074
+#endif
+#ifndef M_LOG10E
+#define M_LOG10E 0.43429448190325182765
+#endif
+#ifndef M_LN2
+#define M_LN2 0.69314718055994530942
+#endif
+#ifndef M_LN10
+#define M_LN10 2.30258509299404568402
+#endif
+
+#ifndef sqrtf
+#define sqrtf(a) ((float)sqrt(a))
+#endif
+#ifndef powf
+#define powf(a, b) ((float)pow(a, b))
+#endif
+#ifndef cosf
+#define cosf(a) ((float)cos(a))
+#endif
+#ifndef sinf
+#define sinf(a) ((float)sin(a))
+#endif
+#ifndef acosf
+#define acosf(a) ((float)acos(a))
+#endif
+#ifndef asinf
+#define asinf(a) ((float)asin(a))
+#endif
+#ifndef atan2f
+#define atan2f(a, b) ((float)atan2(a, b))
+#endif
+#ifndef tanf
+#define tanf(a) ((float)tan(a))
+#endif
+#ifndef atanf
+#define atanf(a) ((float)atan(a))
+#endif
+#ifndef floorf
+#define floorf(a) ((float)floor(a))
+#endif
+#ifndef ceilf
+#define ceilf(a) ((float)ceil(a))
+#endif
+#ifndef fabsf
+#define fabsf(a) ((float)fabs(a))
+#endif
+#ifndef logf
+#define logf(a) ((float)log(a))
+#endif
+#ifndef expf
+#define expf(a) ((float)exp(a))
+#endif
+#ifndef fmodf
+#define fmodf(a, b) ((float)fmod(a, b))
+#endif
+
+#ifdef WIN32
+ #ifndef FREE_WINDOWS
+ #define isnan(n) _isnan(n)
+ #define finite _finite
+ #endif
+#endif
+
+#define MAT4_UNITY {{ 1.0, 0.0, 0.0, 0.0},\
+ { 0.0, 1.0, 0.0, 0.0},\
+ { 0.0, 0.0, 1.0, 0.0},\
+ { 0.0, 0.0, 0.0, 1.0}}
+
+#define MAT3_UNITY {{ 1.0, 0.0, 0.0},\
+ { 0.0, 1.0, 0.0},\
+ { 0.0, 0.0, 1.0}}
+
+
+void cent_tri_v3(float *cent, float *v1, float *v2, float *v3);
+void cent_quad_v3(float *cent, float *v1, float *v2, float *v3, float *v4);
+
+void cross_v3_v3v3(float *c, float *a, float *b);
+void project_v3_v3v3(float *c, float *v1, float *v2);
+
+float dot_v3v3(float *v1, float *v2);
+float dot_v2v2(float *v1, float *v2);
+
+float normalize_v3(float *n);
+float normalize_v2(float *n);
+double normalize_dv3(double n[3]);
+
+float Sqrt3f(float f);
+double sqrt3d(double d);
+
+float saacos(float fac);
+float saasin(float fac);
+float sasqrt(float fac);
+float saacosf(float fac);
+float saasinf(float fac);
+float sasqrtf(float fac);
+
+int compare_v3v3(float *v1, float *v2, float limit);
+int compare_v4v4(float *v1, float *v2, float limit);
+float interpf(float target, float origin, float fac);
+
+float normal_tri_v3( float *n,float *v1, float *v2, float *v3);
+float normal_quad_v3( float *n,float *v1, float *v2, float *v3, float *v4);
+
+void CalcNormLong(int *v1, int *v2, int *v3, float *n);
+/* CalcNormShort: is ook uitprodukt - (translates as 'is also out/cross product') */
+void CalcNormShort(short *v1, short *v2, short *v3, float *n);
+float power_of_2(float val);
+
+/**
+ * @section Euler conversion routines (With Custom Order)
+ */
+
+/* Defines for rotation orders
+ * WARNING: must match the eRotationModes in DNA_action_types.h
+ * order matters - types are saved to file!
+ */
+typedef enum eEulerRotationOrders {
+ EULER_ORDER_DEFAULT = 1, /* Blender 'default' (classic) is basically XYZ */
+ EULER_ORDER_XYZ = 1, /* Blender 'default' (classic) - must be as 1 to sync with PoseChannel rotmode */
+ EULER_ORDER_XZY,
+ EULER_ORDER_YXZ,
+ EULER_ORDER_YZX,
+ EULER_ORDER_ZXY,
+ EULER_ORDER_ZYX,
+ /* NOTE: there are about 6 more entries when including duplicated entries too */
+} eEulerRotationOrders;
+
+void eulO_to_quat( float quat[4],float eul[3], short order);
+void quat_to_eulO( float eul[3], short order,float quat[4]);
+
+void eulO_to_mat3( float Mat[3][3],float eul[3], short order);
+void eulO_to_mat4( float Mat[4][4],float eul[3], short order);
+
+void mat3_to_eulO( float eul[3], short order,float Mat[3][3]);
+void mat4_to_eulO( float eul[3], short order,float Mat[4][4]);
+
+void mat3_to_compatible_eulO( float eul[3], float oldrot[3], short order,float mat[3][3]);
+
+void rotate_eulO(float beul[3], short order, char axis, float ang);
+
+/**
+ * @section Euler conversion routines (Blender XYZ)
+ */
+
+void eul_to_mat3( float mat[][3],float *eul);
+void eul_to_mat4( float mat[][4],float *eul);
+
+void mat3_to_eul( float *eul,float tmat[][3]);
+void mat4_to_eul(float *eul,float tmat[][4]);
+
+void eul_to_quat( float *quat,float *eul);
+
+void mat3_to_compatible_eul( float *eul, float *oldrot,float mat[][3]);
+void eulO_to_gimbal_axis(float gmat[][3], float *eul, short order);
+
+
+void compatible_eul(float *eul, float *oldrot);
+void rotate_eul(float *beul, char axis, float ang);
+
+
+/**
+ * @section Quaternion arithmetic routines
+ */
+
+int is_zero_qt(float *q);
+void quat_to_eul( float *eul,float *quat);
+void unit_qt(float *);
+void mul_qt_qtqt(float *, float *, float *);
+void mul_qt_v3(float *q, float *v);
+void mul_qt_fl(float *q, float f);
+void mul_fac_qt_fl(float *q, float fac);
+
+void normalize_qt(float *);
+void axis_angle_to_quat( float *quat,float *vec, float phi);
+
+void sub_qt_qtqt(float *q, float *q1, float *q2);
+void conjugate_qt(float *q);
+void invert_qt(float *q);
+float dot_qtqt(float *q1, float *q2);
+void copy_qt_qt(float *q1, float *q2);
+
+void print_qt(char *str, float q[4]);
+
+void interp_qt_qtqt(float *result, float *quat1, float *quat2, float t);
+void add_qt_qtqt(float *result, float *quat1, float *quat2, float t);
+
+void quat_to_mat3( float m[][3],float *q);
+void quat_to_mat4( float m[][4],float *q);
+
+/**
+ * @section matrix multiplication and copying routines
+ */
+
+void mul_m3_fl(float *m, float f);
+void mul_m4_fl(float *m, float f);
+void mul_mat3_m4_fl(float *m, float f);
+
+void transpose_m3(float mat[][3]);
+void transpose_m4(float mat[][4]);
+
+int invert_m4_m4(float inverse[][4], float mat[][4]);
+void invert_m4_m4(float inverse[][4], float mat[][4]);
+void invert_m4_m4(float *m1, float *m2);
+void invert_m4_m4(float out[][4], float in[][4]);
+void invert_m3_m3(float m1[][3], float m2[][3]);
+
+void copy_m3_m4(float m1[][3],float m2[][4]);
+void copy_m4_m3(float m1[][4], float m2[][3]);
+
+void blend_m3_m3m3(float out[][3], float dst[][3], float src[][3], float srcweight);
+void blend_m4_m4m4(float out[][4], float dst[][4], float src[][4], float srcweight);
+
+float determinant_m2(float a,float b,float c, float d);
+
+float determinant_m3(
+ float a1, float a2, float a3,
+ float b1, float b2, float b3,
+ float c1, float c2, float c3
+);
+
+float determinant_m4(float m[][4]);
+
+void adjoint_m3_m3(float m1[][3], float m[][3]);
+void adjoint_m4_m4(float out[][4], float in[][4]);
+
+void mul_m4_m4m4(float m1[][4], float m2[][4], float m3[][4]);
+void subMat4MulMat4(float *m1, float *m2, float *m3);
+#ifndef TEST_ACTIVE
+void mul_m3_m3m3(float m1[][3], float m3[][3], float m2[][3]);
+#else
+void mul_m3_m3m3(float *m1, float *m3, float *m2);
+#endif
+void mul_m4_m3m4(float (*m1)[4], float (*m3)[3], float (*m2)[4]);
+void copy_m4_m4(float m1[][4], float m2[][4]);
+void swap_m4m4(float m1[][4], float m2[][4]);
+void copy_m3_m3(float m1[][3], float m2[][3]);
+
+void mul_serie_m3(float answ[][3],
+ float m1[][3], float m2[][3], float m3[][3],
+ float m4[][3], float m5[][3], float m6[][3],
+ float m7[][3], float m8[][3]
+);
+
+void mul_serie_m4(float answ[][4], float m1[][4],
+ float m2[][4], float m3[][4], float m4[][4],
+ float m5[][4], float m6[][4], float m7[][4],
+ float m8[][4]
+);
+
+void zero_m4(float *m);
+void zero_m3(float *m);
+
+void unit_m3(float m[][3]);
+void unit_m4(float m[][4]);
+
+/* NOTE: These only normalise the matrix, they don't make it orthogonal */
+void normalize_m3(float mat[][3]);
+void normalize_m4(float mat[][4]);
+
+int is_orthogonal_m3(float mat[][3]);
+void orthogonalize_m3(float mat[][3], int axis); /* axis is the one to keep in place (assumes it is non-null) */
+int is_orthogonal_m4(float mat[][4]);
+void orthogonalize_m4(float mat[][4], int axis); /* axis is the one to keep in place (assumes it is non-null) */
+
+void mul_v3_m4v3(float *in, float mat[][4], float *vec);
+void mul_m4_m4m3(float (*m1)[4], float (*m3)[4], float (*m2)[3]);
+void mul_m3_m3m4(float m1[][3], float m2[][3], float m3[][4]);
+
+void Mat4MulVec(float mat[][4],int *vec);
+void mul_m4_v3(float mat[][4], float *vec);
+void mul_mat3_m4_v3(float mat[][4], float *vec);
+void mul_project_m4_v4(float mat[][4],float *vec);
+void mul_m4_v4(float mat[][4], float *vec);
+void Mat3MulVec(float mat[][3],int *vec);
+void mul_m3_v3(float mat[][3], float *vec);
+void mul_m3_v3_double(float mat[][3], double *vec);
+void mul_transposed_m3_v3(float mat[][3], float *vec);
+
+void add_m3_m3m3(float m1[][3], float m2[][3], float m3[][3]);
+void add_m4_m4m4(float m1[][4], float m2[][4], float m3[][4]);
+
+void VecUpMat3old(float *vec, float mat[][3], short axis);
+void VecUpMat3(float *vec, float mat[][3], short axis);
+
+void copy_v3_v3(float *v1, float *v2);
+int VecLen(int *v1, int *v2);
+float len_v3v3(float v1[3], float v2[3]);
+float len_v3(float *v);
+void mul_v3_fl(float *v1, float f);
+void negate_v3(float *v1);
+
+int compare_len_v3v3(float *v1, float *v2, float limit);
+int compare_v3v3(float *v1, float *v2, float limit);
+int equals_v3v3(float *v1, float *v2);
+int is_zero_v3(float *v);
+
+void print_v3(char *str,float v[3]);
+void print_v4(char *str, float v[4]);
+
+void add_v3_v3v3(float *v, float *v1, float *v2);
+void sub_v3_v3v3(float *v, float *v1, float *v2);
+void mul_v3_v3v3(float *v, float *v1, float *v2);
+void interp_v3_v3v3(float *target, const float *a, const float *b, const float t);
+void interp_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3]);
+void mid_v3_v3v3(float *v, float *v1, float *v2);
+
+void ortho_basis_v3v3_v3( float *v1, float *v2,float *v);
+
+float len_v2v2(float *v1, float *v2);
+float len_v2(float *v);
+void mul_v2_fl(float *v1, float f);
+void add_v2_v2v2(float *v, float *v1, float *v2);
+void sub_v2_v2v2(float *v, float *v1, float *v2);
+void copy_v2_v2(float *v1, float *v2);
+void interp_v2_v2v2(float *target, const float *a, const float *b, const float t);
+void interp_v2_v2v2v2(float p[2], const float v1[2], const float v2[2], const float v3[2], const float w[3]);
+
+void axis_angle_to_quat(float q[4], float axis[3], float angle);
+void quat_to_axis_angle( float axis[3], float *angle,float q[4]);
+void axis_angle_to_eulO( float eul[3], short order,float axis[3], float angle);
+void eulO_to_axis_angle( float axis[3], float *angle,float eul[3], short order);
+void axis_angle_to_mat3( float mat[3][3],float axis[3], float angle);
+void axis_angle_to_mat4( float mat[4][4],float axis[3], float angle);
+void mat3_to_axis_angle( float axis[3], float *angle,float mat[3][3]);
+void mat4_to_axis_angle( float axis[3], float *angle,float mat[4][4]);
+
+void mat3_to_vec_rot( float axis[3], float *angle,float mat[3][3]);
+void mat4_to_vec_rot( float axis[3], float *angle,float mat[4][4]);
+void vec_rot_to_mat3( float mat[][3],float *vec, float phi);
+void vec_rot_to_mat4( float mat[][4],float *vec, float phi);
+
+void rotation_between_vecs_to_quat(float *q, float v1[3], float v2[3]);
+void vec_to_quat( float *q,float *vec, short axis, short upflag);
+void mat3_to_quat_is_ok( float *q,float wmat[][3]);
+
+void reflect_v3_v3v3(float *out, float *v1, float *v2);
+void bisect_v3_v3v3v3(float *v, float *v1, float *v2, float *v3);
+float angle_v2v2(float *v1, float *v2);
+float angle_v3v3v3(float *v1, float *v2, float *v3);
+float angle_normalized_v3v3(float *v1, float *v2);
+
+float angle_v2v2v2(float *v1, float *v2, float *v3);
+float angle_normalized_v2v2(float *v1, float *v2);
+
+void normal_short_to_float_v3(float *out, short *in);
+void normal_float_to_short_v3(short *out, float *in);
+
+float dist_to_line_v2(float *v1, float *v2, float *v3);
+float dist_to_line_segment_v2(float *v1, float *v2, float *v3);
+float dist_to_line_segment_v3(float *v1, float *v2, float *v3);
+void closest_to_line_segment_v3(float *closest, float v1[3], float v2[3], float v3[3]);
+float area_tri_v2(float *v1, float *v2, float *v3);
+float area_quad_v3(float *v1, float *v2, float *v3, float *v4);
+float area_tri_v3(float *v1, float *v2, float *v3);
+float area_poly_v3(int nr, float *verts, float *normal);
+
+/* intersect Line-Line
+ return:
+ -1: colliniar
+ 0: no intersection of segments
+ 1: exact intersection of segments
+ 2: cross-intersection of segments
+*/
+extern short isect_line_line_v2(float *v1, float *v2, float *v3, float *v4);
+extern short isect_line_line_v2_short(short *v1, short *v2, short *v3, short *v4);
+
+/*point in tri, 0 no intersection, 1 intersect */
+int isect_point_tri_v2(float pt[2], float v1[2], float v2[2], float v3[2]);
+/* point in quad, 0 no intersection, 1 intersect */
+int isect_point_quad_v2(float pt[2], float v1[2], float v2[2], float v3[2], float v4[2]);
+
+/* interpolation weights of point in a triangle or quad, v4 may be NULL */
+void interp_weights_face_v3( float *w,float *v1, float *v2, float *v3, float *v4, float *co);
+/* interpolation weights of point in a polygon with >= 3 vertices */
+void interp_weights_poly_v3( float *w,float v[][3], int n, float *co);
+
+void i_lookat(
+ float vx, float vy,
+ float vz, float px,
+ float py, float pz,
+ float twist, float mat[][4]
+);
+
+void i_window(
+ float left, float right,
+ float bottom, float top,
+ float nearClip, float farClip,
+ float mat[][4]
+);
+
+#define BLI_CS_SMPTE 0
+#define BLI_CS_REC709 1
+#define BLI_CS_CIE 2
+
+#define RAD2DEG(_rad) ((_rad)*(180.0/M_PI))
+#define DEG2RAD(_deg) ((_deg)*(M_PI/180.0))
+
+void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b);
+void hex_to_rgb(char *hexcol, float *r, float *g, float *b);
+void rgb_to_yuv(float r, float g, float b, float *ly, float *lu, float *lv);
+void yuv_to_rgb(float y, float u, float v, float *lr, float *lg, float *lb);
+void ycc_to_rgb(float y, float cb, float cr, float *lr, float *lg, float *lb);
+void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr);
+void rgb_to_hsv(float r, float g, float b, float *lh, float *ls, float *lv);
+void xyz_to_rgb(float x, float y, float z, float *r, float *g, float *b, int colorspace);
+int constrain_rgb(float *r, float *g, float *b);
+unsigned int hsv_to_cpack(float h, float s, float v);
+unsigned int rgb_to_cpack(float r, float g, float b);
+void cpack_to_rgb(unsigned int col, float *r, float *g, float *b);
+void minmax_rgb(short c[]);
+
+
+
+void star_m3_v3(float mat[][3],float *vec);
+
+short EenheidsMat(float mat[][3]);
+
+void orthographic_m4( float matrix[][4],float left, float right, float bottom, float top, float nearClip, float farClip);
+void polarview_m4( float Vm[][4],float dist, float azimuth, float incidence, float twist);
+void translate_m4( float mat[][4],float Tx, float Ty, float Tz);
+void i_multmatrix(float icand[][4], float Vm[][4]);
+void rotate_m4( float mat[][4], char axis,float angle);
+
+
+
+void minmax_v3_v3v3(float *min, float *max, float *vec);
+void size_to_mat3( float mat[][3],float *size);
+void size_to_mat4( float mat[][4],float *size);
+
+float mat3_to_scale(float mat[][3]);
+float mat4_to_scale(float mat[][4]);
+
+void print_m3(char *str, float m[][3]);
+void print_m4(char *str, float m[][4]);
+
+/* uit Sig.Proc.85 pag 253 */
+void mat3_to_quat( float *q,float wmat[][3]);
+void mat4_to_quat( float *q,float m[][4]);
+
+void mat3_to_size( float *size,float mat[][3]);
+void mat4_to_size( float *size,float mat[][4]);
+
+void tri_to_quat( float *quat,float *v1, float *v2, float *v3);
+
+void loc_eul_size_to_mat4(float mat[4][4], float loc[3], float eul[3], float size[3]);
+void loc_eulO_size_to_mat4(float mat[4][4], float loc[3], float eul[3], float size[3], short rotOrder);
+void loc_quat_size_to_mat4(float mat[4][4], float loc[3], float quat[4], float size[3]);
+
+void map_to_tube( float *u, float *v,float x, float y, float z);
+void map_to_sphere( float *u, float *v,float x, float y, float z);
+
+int isect_line_line_v3(float v1[3], float v2[3], float v3[3], float v4[3], float i1[3], float i2[3]);
+int isect_line_line_strict_v3(float v1[3], float v2[3], float v3[3], float v4[3], float vi[3], float *lambda);
+int isect_line_tri_v3(float p1[3], float p2[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv);
+int isect_ray_tri_v3(float p1[3], float d[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv);
+int isect_ray_tri_threshold_v3(float p1[3], float d[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv, float threshold);
+int isect_sweeping_sphere_tri_v3(float p1[3], float p2[3], float radius, float v0[3], float v1[3], float v2[3], float *lambda, float *ipoint);
+int isect_axial_line_tri_v3(int axis, float co1[3], float co2[3], float v0[3], float v1[3], float v2[3], float *lambda);
+int isect_aabb_aabb_v3(float min1[3], float max1[3], float min2[3], float max2[3]);
+void interp_cubic_v3( float *x, float *v,float *x1, float *v1, float *x2, float *v2, float t);
+void isect_point_quad_uv_v2(float v0[2], float v1[2], float v2[2], float v3[2], float pt[2], float *uv);
+void isect_point_face_uv_v2(int isquad, float v0[2], float v1[2], float v2[2], float v3[2], float pt[2], float *uv);
+int isect_point_tri_v2(float v1[2], float v2[2], float v3[2], float pt[2]);
+int isect_point_tri_v2_int(int x1, int y1, int x2, int y2, int a, int b);
+int isect_point_tri_prism_v3(float p[3], float v1[3], float v2[3], float v3[3]);
+
+float closest_to_line_v3( float cp[3],float p[3], float l1[3], float l2[3]);
+
+float shell_angle_to_dist(const float angle);
+
+typedef struct DualQuat {
+ float quat[4];
+ float trans[4];
+
+ float scale[4][4];
+ float scale_weight;
+} DualQuat;
+
+void mat4_to_dquat( DualQuat *dq,float basemat[][4], float mat[][4]);
+void dquat_to_mat4( float mat[][4],DualQuat *dq);
+void add_weighted_dq_dq(DualQuat *dqsum, DualQuat *dq, float weight);
+void normalize_dq(DualQuat *dq, float totweight);
+void mul_v3m3_dq( float *co, float mat[][3],DualQuat *dq);
+void copy_dq_dq(DualQuat *dq1, DualQuat *dq2);
+
+/* Tangent stuff */
+typedef struct VertexTangent {
+ float tang[3], uv[2];
+ struct VertexTangent *next;
+} VertexTangent;
+
+void sum_or_add_vertex_tangent(void *arena, VertexTangent **vtang, float *tang, float *uv);
+float *find_vertex_tangent(VertexTangent *vtang, float *uv);
+void tangent_from_uv(float *uv1, float *uv2, float *uv3, float *co1, float *co2, float *co3, float *n, float *tang);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h
new file mode 100644
index 00000000000..b1db2538e6f
--- /dev/null
+++ b/source/blender/blenlib/BLI_array.h
@@ -0,0 +1,99 @@
+/**
+ * Array Library
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/*
+this library needs to be changed to not use macros quite so heavily,
+and to be more of a complete array API. The way arrays are
+exposed to client code as normal C arrays is very useful though, imho.
+it does require some use of macros, however.
+
+anyway, it's used a bit too heavily to simply rewrite as a
+more "correct" solution without macros entirely. I originally wrote this
+to be very easy to use, without the normal pain of most array libraries.
+This was especially helpful when it came to the massive refactors necessary for
+bmesh, and really helped to speed the process up. - joeedh
+
+little array macro library. example of usage:
+
+int *arr = NULL;
+BLI_array_declare(arr);
+int i;
+
+for (i=0; i<10; i++) {
+ BLI_array_growone(arr);
+ arr[i] = something;
+}
+BLI_array_free(arr);
+
+arrays are buffered, using double-buffering (so on each reallocation,
+the array size is doubled). supposedly this should give good Big Oh
+behaviour, though it may not be the best in practice.
+*/
+
+#define BLI_array_declare(arr) int _##arr##_count=0; void *_##arr##_tmp; void *_##arr##_static = NULL
+
+/*this will use stack space, up to maxstatic array elements, befoe
+ switching to dynamic heap allocation*/
+#define BLI_array_staticdeclare(arr, maxstatic) int _##arr##_count=0; void *_##arr##_tmp; char _##arr##_static[maxstatic*sizeof(arr)]
+
+/*this returns the entire size of the array, including any buffering.*/
+#define BLI_array_totalsize_dyn(arr) ((arr)==NULL ? 0 : MEM_allocN_len(arr) / sizeof(*arr))
+#define BLI_array_totalsize(arr) ((signed int)((arr == _##arr##_static && arr != NULL) ? (sizeof(_##arr##_static) / sizeof(*arr)) : BLI_array_totalsize_dyn(arr)))
+
+/*this returns the logical size of the array, not including buffering.*/
+#define BLI_array_count(arr) _##arr##_count
+
+/*grow the array by one. zeroes the new elements.*/
+#define _BLI_array_growone(arr) \
+ BLI_array_totalsize(arr) > _##arr##_count ? ++_##arr##_count : \
+ ((_##arr##_tmp = MEM_callocN(sizeof(*arr)*(_##arr##_count*2+2), #arr " " __FILE__ " ")),\
+ (arr && memcpy(_##arr##_tmp, arr, sizeof(*arr) * _##arr##_count)),\
+ (arr && (arr != (void*)_##arr##_static ? (MEM_freeN(arr), arr) : arr)),\
+ (arr = _##arr##_tmp),\
+ _##arr##_count++)
+
+/*returns length of array*/
+#define BLI_array_growone(arr) (arr==NULL && _##arr##_static != NULL ? ((arr=(void*)_##arr##_static), ++_##arr##_count) : _BLI_array_growone(arr))
+
+ /*appends an item to the array and returns a pointer to the item in the array.
+ item is not a pointer, but actual data value.*/
+#define BLI_array_append(arr, item) (BLI_array_growone(arr), (arr[_##arr##_count-1] = item), (arr+(_##arr##_count-1)))
+
+/*grow an array by a specified number of items.*/
+#define BLI_array_growitems(arr, num) {int _i; for (_i=0; _i<(num); _i++) {BLI_array_growone(arr);}}
+#define BLI_array_free(arr) if (arr && arr != _##arr##_static) MEM_freeN(arr)
+
+#define BLI_array_pop(arr) ((arr&&_##arr##_count) ? arr[--_##arr##_count] : NULL)
+/*resets the logical size of an array to zero, but doesn't
+ free the memory.*/
+#define BLI_array_empty(arr) _##arr##_count=0
+
+/*set the count of the array, doesn't actually increase the allocated array
+ size. don't use this unless you know what you're doing.*/
+#define BLI_array_set_length(arr, count) _##arr##_count = (count)
diff --git a/source/blender/blenlib/BLI_cellalloc.h b/source/blender/blenlib/BLI_cellalloc.h
new file mode 100644
index 00000000000..e0fbc581969
--- /dev/null
+++ b/source/blender/blenlib/BLI_cellalloc.h
@@ -0,0 +1,51 @@
+/**
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2008 by Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/*
+ I wrote this as a hack so vgroups won't be quite so slow. I really
+ should replace it with something else, but I need to spend some time
+ thinking as to what the proper solution would be (other then totally
+ rewriting vgroups, of course).
+
+ this is just a simple allocator that spawns mempools for unique size
+ requests. hardly ideal, I know. *something* like this may be
+ unavoidable, but it should certainly be possible to make it
+ non-global and internal to the vgroup code.
+
+ -joeedh sep. 17 2009
+*/
+
+//BMESH_TODO: kill this library before merging with trunk. it's evil! -joeedh
+
+void *BLI_cellalloc_malloc(long size, const char *tag);
+void *BLI_cellalloc_calloc(long size, const char *tag);
+void BLI_cellalloc_free(void *mem);
+void BLI_cellalloc_printleaks(void);
+int BLI_cellalloc_get_totblock(void);
+void BLI_cellalloc_destroy(void);
+void *BLI_cellalloc_dupalloc(void *mem);
diff --git a/source/blender/blenlib/BLI_edgehash.h b/source/blender/blenlib/BLI_edgehash.h
index fba13035f02..1827d69dcab 100644
--- a/source/blender/blenlib/BLI_edgehash.h
+++ b/source/blender/blenlib/BLI_edgehash.h
@@ -36,6 +36,10 @@
* \brief A general unordered 2-int pair hash table ADT.
*/
+#include "MEM_guardedalloc.h"
+#include "BKE_utildefines.h"
+#include "BLI_mempool.h"
+
struct EdgeHash;
struct EdgeHashIterator;
typedef struct EdgeHash EdgeHash;
@@ -49,22 +53,22 @@ void BLI_edgehash_free (EdgeHash *eh, EdgeHashFreeFP valfreefp);
/* Insert edge (v0,v1) into hash with given value, does
* not check for duplicates.
*/
-void BLI_edgehash_insert (EdgeHash *eh, int v0, int v1, void *val);
+//void BLI_edgehash_insert (EdgeHash *eh, int v0, int v1, void *val);
/* Return value for given edge (v0,v1), or NULL if
* if key does not exist in hash. (If need exists
* to differentiate between key-value being NULL and
* lack of key then see BLI_edgehash_lookup_p().
*/
-void* BLI_edgehash_lookup (EdgeHash *eh, int v0, int v1);
+//void* BLI_edgehash_lookup (EdgeHash *eh, int v0, int v1);
/* Return pointer to value for given edge (v0,v1),
* or NULL if key does not exist in hash.
*/
-void** BLI_edgehash_lookup_p (EdgeHash *eh, int v0, int v1);
+//void** BLI_edgehash_lookup_p (EdgeHash *eh, int v0, int v1);
/* Return boolean true/false if edge (v0,v1) in hash. */
-int BLI_edgehash_haskey (EdgeHash *eh, int v0, int v1);
+//int BLI_edgehash_haskey (EdgeHash *eh, int v0, int v1);
/* Return number of keys in hash. */
int BLI_edgehash_size (EdgeHash *eh);
@@ -99,5 +103,99 @@ void BLI_edgehashIterator_step (EdgeHashIterator *ehi);
/* Determine if an iterator is done. */
int BLI_edgehashIterator_isDone (EdgeHashIterator *ehi);
+/**************inlined code************/
+static unsigned int _ehash_hashsizes[]= {
+ 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209,
+ 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169,
+ 4194319, 8388617, 16777259, 33554467, 67108879, 134217757,
+ 268435459
+};
+
+#define EDGEHASH(v0,v1) ((v0*39)^(v1*31))
+
+/***/
+
+typedef struct EdgeEntry EdgeEntry;
+struct EdgeEntry {
+ EdgeEntry *next;
+ int v0, v1;
+ void *val;
+};
+
+struct EdgeHash {
+ EdgeEntry **buckets;
+ BLI_mempool *epool;
+ int nbuckets, nentries, cursize;
+};
+
+
+BM_INLINE void BLI_edgehash_insert(EdgeHash *eh, int v0, int v1, void *val) {
+ unsigned int hash;
+ EdgeEntry *e= BLI_mempool_alloc(eh->epool);
+
+ if (v1<v0) {
+ v0 ^= v1;
+ v1 ^= v0;
+ v0 ^= v1;
+ }
+ hash = EDGEHASH(v0,v1)%eh->nbuckets;
+
+ e->v0 = v0;
+ e->v1 = v1;
+ e->val = val;
+ e->next= eh->buckets[hash];
+ eh->buckets[hash]= e;
+
+ if (++eh->nentries>eh->nbuckets*3) {
+ EdgeEntry *e, **old= eh->buckets;
+ int i, nold= eh->nbuckets;
+
+ eh->nbuckets= _ehash_hashsizes[++eh->cursize];
+ eh->buckets= MEM_mallocN(eh->nbuckets*sizeof(*eh->buckets), "eh buckets");
+ BMEMSET(eh->buckets, 0, eh->nbuckets*sizeof(*eh->buckets));
+
+ for (i=0; i<nold; i++) {
+ for (e= old[i]; e;) {
+ EdgeEntry *n= e->next;
+
+ hash= EDGEHASH(e->v0,e->v1)%eh->nbuckets;
+ e->next= eh->buckets[hash];
+ eh->buckets[hash]= e;
+
+ e= n;
+ }
+ }
+
+ MEM_freeN(old);
+ }
+}
+
+BM_INLINE void** BLI_edgehash_lookup_p(EdgeHash *eh, int v0, int v1) {
+ unsigned int hash;
+ EdgeEntry *e;
+
+ if (v1<v0) {
+ v0 ^= v1;
+ v1 ^= v0;
+ v0 ^= v1;
+ }
+ hash = EDGEHASH(v0,v1)%eh->nbuckets;
+ for (e= eh->buckets[hash]; e; e= e->next)
+ if (v0==e->v0 && v1==e->v1)
+ return &e->val;
+
+ return NULL;
+}
+
+BM_INLINE void* BLI_edgehash_lookup(EdgeHash *eh, int v0, int v1) {
+ void **value_p = BLI_edgehash_lookup_p(eh,v0,v1);
+
+ return value_p?*value_p:NULL;
+}
+
+BM_INLINE int BLI_edgehash_haskey(EdgeHash *eh, int v0, int v1) {
+ return BLI_edgehash_lookup_p(eh, v0, v1)!=NULL;
+}
+
#endif
diff --git a/source/blender/blenlib/BLI_editVert.h b/source/blender/blenlib/BLI_editVert.h
index b422b79b165..a4fd26d1274 100644
--- a/source/blender/blenlib/BLI_editVert.h
+++ b/source/blender/blenlib/BLI_editVert.h
@@ -45,6 +45,7 @@
struct DerivedMesh;
struct RetopoPaintData;
+struct BLI_mempool;
/* note; changing this also might affect the undo copy in editmesh.c */
typedef struct EditVert
@@ -157,6 +158,8 @@ typedef struct EditMesh
HashEdge *hashedgetab;
/* this is for the editmesh_fastmalloc */
+ struct BLI_mempool *vertpool, *edgepool, *facepool;
+
EditVert *allverts, *curvert;
EditEdge *alledges, *curedge;
EditFace *allfaces, *curface;
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index dcc71fa1258..8f2cd02c35e 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -43,6 +43,10 @@ extern "C" {
#include <stdlib.h>
#include <string.h>
+
+#include "BKE_utildefines.h"
+#include "MEM_guardedalloc.h"
+
#include "BLI_mempool.h"
#include "BLI_blenlib.h"
@@ -75,11 +79,6 @@ typedef struct GHashIterator {
GHash* BLI_ghash_new (GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info);
void BLI_ghash_free (GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
-//BM_INLINE void BLI_ghash_insert (GHash *gh, void *key, void *val);
-//BM_INLINE int BLI_ghash_remove (GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
-//BM_INLINE void* BLI_ghash_lookup (GHash *gh, void *key);
-//BM_INLINE int BLI_ghash_haskey (GHash *gh, void *key);
-
int BLI_ghash_size (GHash *gh);
/* *** */
@@ -154,32 +153,6 @@ int BLI_ghashutil_intcmp(const void *a, const void *b);
/*begin of macro-inlined functions*/
extern unsigned int hashsizes[];
-#if 0
-#define BLI_ghash_insert(gh, _k, _v){\
- unsigned int _hash= (gh)->hashfp(_k)%gh->nbuckets;\
- Entry *_e= BLI_mempool_alloc((gh)->entrypool);\
- _e->key= _k;\
- _e->val= _v;\
- _e->next= (gh)->buckets[_hash];\
- (gh)->buckets[_hash]= _e;\
- if (++(gh)->nentries>(gh)->nbuckets*3) {\
- Entry *_e, **_old= (gh)->buckets;\
- int _i, _nold= (gh)->nbuckets;\
- (gh)->nbuckets= hashsizes[++(gh)->cursize];\
- (gh)->buckets= malloc((gh)->nbuckets*sizeof(*(gh)->buckets));\
- memset((gh)->buckets, 0, (gh)->nbuckets*sizeof(*(gh)->buckets));\
- for (_i=0; _i<_nold; _i++) {\
- for (_e= _old[_i]; _e;) {\
- Entry *_n= _e->next;\
- _hash= (gh)->hashfp(_e->key)%(gh)->nbuckets;\
- _e->next= (gh)->buckets[_hash];\
- (gh)->buckets[_hash]= _e;\
- _e= _n;\
- }\
- }\
- free(_old); } }
-#endif
-
/*---------inlined functions---------*/
BM_INLINE void BLI_ghash_insert(GHash *gh, void *key, void *val) {
unsigned int hash= gh->hashfp(key)%gh->nbuckets;
@@ -271,5 +244,4 @@ BM_INLINE int BLI_ghash_haskey(GHash *gh, void *key) {
#ifdef __cplusplus
}
#endif
-
#endif
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index fe09706cb3d..cc443621fa9 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -87,6 +87,12 @@ void linearrgb_to_srgb_rgba_buf(float *col, int tot);
void srgb_to_linearrgb_rgba_rgba_buf(float *col_to, float *col_from, int tot);
void linearrgb_to_srgb_rgba_rgba_buf(float *col_to, float *col_from, int tot);
+/* rgba buffer convenience functions */
+void srgb_to_linearrgb_rgba_buf(float *col, int tot);
+void linearrgb_to_srgb_rgba_buf(float *col, int tot);
+void srgb_to_linearrgb_rgba_rgba_buf(float *col_to, float *col_from, int tot);
+void linearrgb_to_srgb_rgba_rgba_buf(float *col_to, float *col_from, int tot);
+
/************************** Other *************************/
int constrain_rgb(float *r, float *g, float *b);
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 5f26bff0ad9..1f56694f85b 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -40,6 +40,8 @@ extern "C" {
#ifdef BLI_MATH_INLINE_H
#include "intern/math_vector_inline.c"
+#else
+#define MINLINE
#endif
/************************************* Init ***********************************/
diff --git a/source/blender/blenlib/BLI_mempool.h b/source/blender/blenlib/BLI_mempool.h
index 4ea48929efb..5aa9c196b39 100644
--- a/source/blender/blenlib/BLI_mempool.h
+++ b/source/blender/blenlib/BLI_mempool.h
@@ -29,18 +29,120 @@
#ifndef BLI_MEMPOOL_H
#define BLI_MEMPOOL_H
-/** \file BLI_storage.h
+/** \file BLI_mempool.h
* \ingroup bli
* \author Geoffrey Bantle
* \brief Simple fast memory allocator.
*/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
struct BLI_mempool;
-struct BLI_mempool *BLI_mempool_create(int esize, int tote, int pchunk, int use_sysmalloc);
-void *BLI_mempool_alloc(struct BLI_mempool *pool);
-void *BLI_mempool_calloc(struct BLI_mempool *pool);
-void BLI_mempool_free(struct BLI_mempool *pool, void *addr);
-void BLI_mempool_destroy(struct BLI_mempool *pool);
+#include "BKE_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_blenlib.h"
+#include <string.h>
+
+typedef struct BLI_freenode{
+ struct BLI_freenode *next;
+ int freeword; /*used to identify this as a freed node*/
+}BLI_freenode;
+
+typedef struct BLI_mempool_chunk{
+ struct BLI_mempool_chunk *next, *prev;
+ void *data;
+}BLI_mempool_chunk;
+
+typedef struct BLI_mempool{
+ struct ListBase chunks;
+ int esize, csize, pchunk; /*size of elements and chunks in bytes and number of elements per chunk*/
+ BLI_freenode *free; /*free element list. Interleaved into chunk datas.*/
+ int totalloc, totused; /*total number of elements allocated in total, and currently in use*/
+ int use_sysmalloc, allow_iter;
+}BLI_mempool;
+
+/*allow_iter allows iteration on this mempool. note: this requires that the
+ first four bytes of the elements never contain the character string
+ 'free'. use with care.*/
+
+BLI_mempool *BLI_mempool_create(int esize, int tote, int pchunk,
+ int use_sysmalloc, int allow_iter);
+//void *BLI_mempool_alloc(BLI_mempool *pool);
+void *BLI_mempool_calloc(BLI_mempool *pool);
+void BLI_mempool_free(BLI_mempool *pool, void *addr);
+void BLI_mempool_destroy(BLI_mempool *pool);
+int BLI_mempool_count(BLI_mempool *pool);
+
+/** iteration stuff. note: this may easy to produce bugs with **/
+/*private structure*/
+typedef struct BLI_mempool_iter {
+ BLI_mempool *pool;
+ struct BLI_mempool_chunk *curchunk;
+ int curindex;
+} BLI_mempool_iter;
+
+/*allow iteration on this mempool. note: this requires that the
+ first four bytes of the elements never contain the character string
+ 'free'. use with care.*/
+void BLI_mempool_allow_iter(BLI_mempool *pool);
+void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter);
+void *BLI_mempool_iterstep(BLI_mempool_iter *iter);
+
+/************ inlined stuff ***********/
+#define FREEWORD MAKE_ID('f', 'r', 'e', 'e')
+#include "MEM_guardedalloc.h"
+
+BM_INLINE void *BLI_mempool_alloc(BLI_mempool *pool) {
+ void *retval=NULL;
+ BLI_freenode *curnode=NULL;
+ char *addr=NULL;
+ int j;
+
+ if (!pool) return NULL;
+
+ pool->totused++;
+
+ if(!(pool->free)){
+ /*need to allocate a new chunk*/
+ BLI_mempool_chunk *mpchunk = pool->use_sysmalloc ? (BLI_mempool_chunk*)malloc(sizeof(BLI_mempool_chunk)) : (BLI_mempool_chunk*)MEM_mallocN(sizeof(BLI_mempool_chunk), "BLI_Mempool Chunk");
+ mpchunk->next = mpchunk->prev = NULL;
+ mpchunk->data = pool->use_sysmalloc ? malloc(pool->csize) : MEM_mallocN(pool->csize, "BLI_Mempool Chunk Data");
+ BLI_addtail(&(pool->chunks), mpchunk);
+
+ pool->free = (BLI_freenode*)mpchunk->data; /*start of the list*/
+ if (pool->allow_iter)
+ pool->free->freeword = FREEWORD;
+ for(addr = (char*)mpchunk->data, j=0; j < pool->pchunk; j++){
+ curnode = ((BLI_freenode*)addr);
+ addr += pool->esize;
+ curnode->next = (BLI_freenode*)addr;
+
+ if (pool->allow_iter) {
+ curnode->freeword = FREEWORD;
+ if (j != pool->pchunk-1)
+ curnode->next->freeword = FREEWORD;
+ }
+ }
+ curnode->next = NULL; /*terminate the list*/
+
+ pool->totalloc += pool->pchunk;
+ }
+
+ retval = pool->free;
+ if (pool->allow_iter)
+ pool->free->freeword = 0x7FFFFFFF;
+
+ pool->free = pool->free->next;
+ //memset(retval, 0, pool->esize);
+ return retval;
+}
+
+#ifdef __cplusplus
+}
+#endif
#endif
diff --git a/source/blender/blenlib/BLI_smallhash.h b/source/blender/blenlib/BLI_smallhash.h
new file mode 100755
index 00000000000..2ab365eea0e
--- /dev/null
+++ b/source/blender/blenlib/BLI_smallhash.h
@@ -0,0 +1,205 @@
+/**
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BLI_SMALLHASH_H
+#define BLI_SMALLHASH_H
+
+/*******a light stack-friendly hash library******
+ * (it uses stack space for smallish hash tables) */
+
+/*based on a doubling non-chaining approach */
+
+#include "MEM_guardedalloc.h"
+#include "BLO_sys_types.h"
+#include "BLI_utildefines.h"
+
+extern unsigned int hashsizes[];
+#define NONHASH -25436536
+typedef struct entry {intptr_t key; void *val;} entry;
+
+#define SMSTACKSIZE 521
+typedef struct SmallHash {
+ entry *table, _stacktable[SMSTACKSIZE], _copytable[SMSTACKSIZE];
+ entry *stacktable, *copytable;
+ int used;
+ int curhash;
+ int size;
+} SmallHash;
+
+/*CELL_UNUSED means this cell is inside a key series, while CELL_FREE
+ means this cell terminates a key series.
+
+ no chance of anyone shoving INT32_MAX-2 into a *val pointer, I
+ imagine. hopefully. */
+#define CELL_UNUSED ((void*)0x7FFFFFFF)
+#define CELL_FREE ((void*)0x7FFFFFFD)
+
+#define NONZERO(n) ((n) + !(n))
+#define HASHNEXT(h, hoff) ((h) + ((hoff=NONZERO(hoff*2)+1), hoff))
+
+BM_INLINE void BLI_smallhash_init(SmallHash *hash)
+{
+ int i;
+
+ memset(hash, 0, sizeof(*hash));
+
+ hash->table = hash->_stacktable;
+ hash->curhash = 2;
+ hash->size = hashsizes[hash->curhash];
+
+ hash->copytable = hash->_copytable;
+ hash->stacktable = hash->_stacktable;
+
+ for (i=0; i<hash->size; i++) {
+ hash->table[i].val = CELL_FREE;
+ }
+}
+
+/*NOTE: does *not* free *hash itself! only the direct data!*/
+BM_INLINE void BLI_smallhash_release(SmallHash *hash)
+{
+ if (!hash)
+ return;
+
+ if (hash->table != hash->stacktable)
+ MEM_freeN(hash->table);
+}
+
+BM_INLINE void BLI_smallhash_insert(SmallHash *hash, intptr_t key, void *item)
+{
+ int h, hoff=1;
+
+ if (hash->size < hash->used*3) {
+ int newsize = hashsizes[++hash->curhash];
+ entry *tmp;
+ int i = 0;
+
+ if (hash->table != hash->stacktable || newsize > SMSTACKSIZE) {
+ tmp = MEM_callocN(sizeof(*hash->table)*newsize, "new hashkeys");
+ } else {
+ SWAP(entry*, hash->stacktable, hash->copytable);
+ tmp = hash->stacktable;
+ }
+
+ SWAP(entry*, tmp, hash->table);
+
+ hash->size = newsize;
+
+ for (i=0; i<hash->size; i++) {
+ hash->table[i].val = CELL_FREE;
+ }
+
+ for (i=0; i<hashsizes[hash->curhash-1]; i++) {
+ if (ELEM(tmp[i].val, CELL_UNUSED, CELL_FREE))
+ continue;
+
+ h = tmp[i].key; hoff = 1;
+ while (!ELEM(hash->table[h % newsize].val, CELL_UNUSED, CELL_FREE))
+ h = HASHNEXT(h, hoff);
+
+ h %= newsize;
+
+ hash->table[h].key = tmp[i].key;
+ hash->table[h].val = tmp[i].val;
+ }
+
+ if (tmp != hash->stacktable && tmp != hash->copytable) {
+ MEM_freeN(tmp);
+ }
+ }
+
+ h = key; hoff = 1;
+ while (!ELEM(hash->table[h % hash->size].val, CELL_UNUSED, CELL_FREE))
+ h = HASHNEXT(h, hoff);
+
+ h %= hash->size;
+ hash->table[h].key = key;
+ hash->table[h].val = item;
+
+ hash->used++;
+}
+
+BM_INLINE void BLI_smallhash_remove(SmallHash *hash, intptr_t key)
+{
+ int h = key, hoff=1;
+
+ while (hash->table[h % hash->size].key != key
+ || hash->table[h % hash->size].val == CELL_UNUSED)
+ {
+ if (hash->table[h % hash->size].val == CELL_FREE)
+ return;
+ h = HASHNEXT(h, hoff);
+ }
+
+ h %= hash->size;
+ hash->table[h].key = 0;
+ hash->table[h].val = CELL_UNUSED;
+}
+
+BM_INLINE void *BLI_smallhash_lookup(SmallHash *hash, intptr_t key)
+{
+ int h = key, hoff=1;
+
+ if (!hash->table)
+ return NULL;
+
+ while (hash->table[h % hash->size].key != key
+ || hash->table[h % hash->size].val == CELL_UNUSED)
+ {
+ if (hash->table[h % hash->size].val == CELL_FREE)
+ return NULL;
+ h = HASHNEXT(h, hoff);
+ }
+
+ return hash->table[h % hash->size].val;
+}
+
+
+BM_INLINE int BLI_smallhash_haskey(SmallHash *hash, intptr_t key)
+{
+ int h = key, hoff=1;
+
+ if (!hash->table)
+ return 0;
+
+ while (hash->table[h % hash->size].key != key
+ || hash->table[h % hash->size].val == CELL_UNUSED)
+ {
+ if (hash->table[h % hash->size].val == CELL_FREE)
+ return 0;
+ h = HASHNEXT(h, hoff);
+ }
+
+ return 1;
+}
+
+BM_INLINE int BLI_smallhash_count(SmallHash *hash)
+{
+ return hash->used;
+}
+
+#endif // BLI_SMALLHASH_H
diff --git a/source/blender/blenlib/BLI_sparsemap.h b/source/blender/blenlib/BLI_sparsemap.h
new file mode 100755
index 00000000000..0c892997dd4
--- /dev/null
+++ b/source/blender/blenlib/BLI_sparsemap.h
@@ -0,0 +1,73 @@
+#if 0
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ *
+ * Contributor(s): Joseph Eagar (original author)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "BLI_math_inline.h"
+
+typedef struct SparseMap {
+ int max;
+ int blocksize;
+ void **blocks;
+ int totblock;
+} SparseMap;
+
+MALWAYS_INLINE SparseMap *BLI_sparsemap_new(int blocksize, char *name)
+{
+ SparseMap *sm = MEM_callocN(sizeof(SparseMap), name);
+
+ sm->blocksize = blocksize;
+ return sm;
+}
+
+MALWAYS_INLINE void BLI_sparsemap_free(SparseMap *sm)
+{
+ if (sm->blocks)
+ MEM_freeN(sm->blocks);
+
+ MEM_freeN(sm);
+}
+
+MALWAYS_INLINE void BLI_sparsemap_set(SparseMap *sm, int index, void *ptr)
+{
+ if (index >= sm->max || (sm->blocks && !sm->blocks[index/sm->blocksize])) {
+ int totblock = MAX2((index+1)/sm->blocksize, 2);
+ void *blocks = MEM_callocN(sizeof(void*)*totblock);
+
+ if (sm->blocks)
+ memcpy(blocks, sm->blocks, sizeof(void*)*sm->totblock);
+ sm->totblock = totblock;
+ MEM_freeN(sm->blocks);
+ sm->blocks = blocks;
+ }
+
+ if (!sm->blocks[index/sm->blocksize]) {
+ sm->blocks[index/sm->blocksize] = MEM_mallocN(sizeof(void*)*sm->blocksize);
+ }
+
+ sm->blocks[index/sm->blocksize] = ptr;
+}
+#endif
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index d5ed8956f7a..ff024fc9ea4 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -46,6 +46,7 @@ set(SRC
intern/BLI_linklist.c
intern/BLI_memarena.c
intern/BLI_mempool.c
+ intern/BLI_cellalloc.c
intern/DLRB_tree.c
intern/boxpack2d.c
intern/bpath.c
diff --git a/source/blender/blenlib/SConscript b/source/blender/blenlib/SConscript
index 00caf8cd01d..b84c6866192 100644
--- a/source/blender/blenlib/SConscript
+++ b/source/blender/blenlib/SConscript
@@ -5,9 +5,15 @@ sources = env.Glob('intern/*.c')
cflags=''
incs = '. ../makesdna ../blenkernel #/intern/guardedalloc #/intern/ghost ../editors/include ../gpu ../blenloader'
+incs += ' ../windowmanager ../bmesh #/extern/glew/include'
+
incs += ' ' + env['BF_FREETYPE_INC']
incs += ' ' + env['BF_ZLIB_INC']
+<<<<<<< .working
+defs = 'GLEW_STATIC'
+=======
defs = []
+>>>>>>> .merge-right.r35190
if env['WITH_BF_BINRELOC']:
cflags='-pthread'
diff --git a/source/blender/blenlib/intern/BLI_cellalloc.c b/source/blender/blenlib/intern/BLI_cellalloc.c
new file mode 100644
index 00000000000..14237a1285b
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_cellalloc.c
@@ -0,0 +1,198 @@
+/**
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2008 by Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/*
+ Simple, fast memory allocator that uses many BLI_mempools for allocation.
+ this is meant to be used by lots of relatively small objects.
+
+ this is a temporary and inperfect fix for performance issues caused
+ by vgroups. it needs to be replaced with something better, preferably
+ integrated into guardedalloc.
+*/
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+
+#include "DNA_listBase.h"
+#include "BLI_mempool.h"
+
+#include <string.h>
+
+static BLI_mempool **pools;
+static int totpool = 0;
+ListBase active_mem = {NULL, NULL};
+static int celltotblock = 0;
+
+#define MEMIDCHECK ('a' | ('b' << 4) | ('c' << 8) | ('d' << 12))
+
+typedef struct MemHeader {
+ struct MemHeader *next, *prev;
+
+ int size;
+ char *tag;
+ int idcheck;
+} MemHeader;
+
+//#define USE_GUARDEDALLOC
+
+void *BLI_cellalloc_malloc(long size, char *tag)
+{
+ MemHeader *memh;
+ int slot = size + sizeof(MemHeader);
+
+#ifdef USE_GUARDEDALLOC
+ return MEM_mallocN(size, tag);
+#endif
+ if (!slot)
+ return NULL;
+
+ /*stupid optimization trick.
+ round up to nearest 16 bytes boundary.
+ this is to reduce the number of potential
+ pools. hopefully it'll help.*/
+ slot += 16 - (slot & 15);
+
+ if (slot >= totpool) {
+ void *tmp;
+
+ tmp = calloc(1, sizeof(void*)*(slot+1));
+ if (pools) {
+ memcpy(tmp, pools, totpool*sizeof(void*));
+ }
+
+ pools = tmp;
+ totpool = slot+1;
+ }
+
+ if (!pools[slot]) {
+ pools[slot] = BLI_mempool_create(slot, 1, 128, 1, 0);
+ }
+
+ memh = BLI_mempool_alloc(pools[slot]);
+ memh->size = size;
+ memh->idcheck = MEMIDCHECK;
+ memh->tag = tag;
+ BLI_addtail(&active_mem, memh);
+ celltotblock++;
+
+ return memh + 1;
+}
+
+void *BLI_cellalloc_calloc(long size, char *tag)
+{
+ void *mem = BLI_cellalloc_malloc(size, tag);
+ BMEMSET(mem, 0, size);
+
+ return mem;
+}
+
+void BLI_cellalloc_free(void *mem)
+{
+ MemHeader *memh = mem;
+ int slot;
+
+#ifdef USE_GUARDEDALLOC
+ MEM_freeN(mem);
+ return;
+#endif
+ if (!memh)
+ return;
+
+ memh--;
+ if (memh->idcheck != MEMIDCHECK) {
+ printf("Error in BLI_cellalloc: attempt to free invalid block.\n");
+ return;
+ }
+
+ slot = memh->size + sizeof(MemHeader);
+ slot += 16 - (slot & 15);
+
+ if (memh->size > 0 && slot < totpool) {
+ BLI_remlink(&active_mem, memh);
+ BLI_mempool_free(pools[slot], memh);
+ celltotblock--;
+ } else {
+ printf("Error in BLI_cellalloc: attempt to free corrupted block.\n");
+ }
+}
+
+void *BLI_cellalloc_dupalloc(void *mem)
+{
+ MemHeader *memh = mem;
+ void *tmp;
+
+#ifdef USE_GUARDEDALLOC
+ MEM_freeN(mem);
+ return NULL;
+#endif
+ if (!memh)
+ return NULL;
+
+ memh--;
+ if (memh->idcheck != MEMIDCHECK) {
+ printf("Error in BLI_cellalloc: attempt to free invalid block.\n");
+ return NULL;
+ }
+
+ tmp = BLI_cellalloc_malloc(memh->size, memh->tag);
+ memcpy(tmp, mem, memh->size);
+
+ return tmp;
+}
+
+void BLI_cellalloc_printleaks(void)
+{
+ MemHeader *memh;
+
+ if (!active_mem.first) return;
+
+ for (memh=active_mem.first; memh; memh=memh->next) {
+ printf("%s %d %p\n", memh->tag, memh->size, memh+1);
+ }
+}
+
+int BLI_cellalloc_get_totblock(void)
+{
+ return celltotblock;
+}
+
+void BLI_cellalloc_destroy(void)
+{
+ int i;
+
+ for (i=0; i<totpool; i++) {
+ if (pools[i]) {
+ BLI_mempool_destroy(pools[i]);
+ pools[i] = NULL;
+ }
+ }
+}
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index df78c9fb7d2..9148e356e2a 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -50,7 +50,7 @@ GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) {
GHash *gh= MEM_mallocN(sizeof(*gh), info);
gh->hashfp= hashfp;
gh->cmpfp= cmpfp;
- gh->entrypool = BLI_mempool_create(sizeof(Entry), 64, 64, 0);
+ gh->entrypool = BLI_mempool_create(sizeof(Entry), 64, 64, 1, 0);
gh->cursize= 0;
gh->nentries= 0;
diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c
index 449195fefd1..60882e7f1b6 100644
--- a/source/blender/blenlib/intern/BLI_mempool.c
+++ b/source/blender/blenlib/intern/BLI_mempool.c
@@ -21,7 +21,7 @@
*
* The Original Code is: all of this file.
*
- * Contributor(s): none yet.
+ * Contributor(s): Geoffery Bantle
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -31,47 +31,48 @@
*/
#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
#include "BLI_mempool.h"
-#include <string.h>
+#include "BLI_utildefines.h"
-typedef struct BLI_freenode{
- struct BLI_freenode *next;
-}BLI_freenode;
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
-typedef struct BLI_mempool_chunk{
- struct BLI_mempool_chunk *next, *prev;
- void *data;
-}BLI_mempool_chunk;
+#include <string.h>
-typedef struct BLI_mempool{
- struct ListBase chunks;
- int esize, csize, pchunk; /*size of elements and chunks in bytes and number of elements per chunk*/
- struct BLI_freenode *free; /*free element list. Interleaved into chunk datas.*/
- int totalloc, totused; /*total number of elements allocated in total, and currently in use*/
- int use_sysmalloc;
-}BLI_mempool;
+#define BLI_MEMPOOL_INTERN
+#include "BLI_mempool.h"
-BLI_mempool *BLI_mempool_create(int esize, int tote, int pchunk, int use_sysmalloc)
+BLI_mempool *BLI_mempool_create(int esize, int tote, int pchunk,
+ int use_sysmalloc, int allow_iter)
{ BLI_mempool *pool = NULL;
BLI_freenode *lasttail = NULL, *curnode = NULL;
int i,j, maxchunks;
char *addr;
- if (esize < sizeof(void*))
- esize = sizeof(void*);
+ if (esize < sizeof(void*)*2)
+ esize = sizeof(void*)*2;
+ if (esize < sizeof(void*)*2)
+ esize = sizeof(void*)*2;
+
/*allocate the pool structure*/
pool = use_sysmalloc ? malloc(sizeof(BLI_mempool)) : MEM_mallocN(sizeof(BLI_mempool), "memory pool");
- pool->esize = esize;
+ pool->esize = allow_iter ? MAX2(esize, sizeof(BLI_freenode)) : esize;
pool->use_sysmalloc = use_sysmalloc;
pool->pchunk = pchunk;
pool->csize = esize * pchunk;
pool->chunks.first = pool->chunks.last = NULL;
pool->totused= 0;
+ pool->allow_iter= allow_iter;
maxchunks = tote / pchunk + 1;
-
+ if (maxchunks==0) maxchunks = 1;
+
/*allocate the actual chunks*/
for(i=0; i < maxchunks; i++){
BLI_mempool_chunk *mpchunk = use_sysmalloc ? malloc(sizeof(BLI_mempool_chunk)) : MEM_mallocN(sizeof(BLI_mempool_chunk), "BLI_Mempool Chunk");
@@ -79,30 +80,49 @@ BLI_mempool *BLI_mempool_create(int esize, int tote, int pchunk, int use_sysmall
mpchunk->data = use_sysmalloc ? malloc(pool->csize) : MEM_mallocN(pool->csize, "BLI Mempool Chunk Data");
BLI_addtail(&(pool->chunks), mpchunk);
- if(i==0) pool->free = mpchunk->data; /*start of the list*/
+ if(i==0) {
+ pool->free = mpchunk->data; /*start of the list*/
+ if (pool->allow_iter)
+ pool->free->freeword = FREEWORD;
+ }
+
/*loop through the allocated data, building the pointer structures*/
for(addr = mpchunk->data, j=0; j < pool->pchunk; j++){
curnode = ((BLI_freenode*)addr);
addr += pool->esize;
curnode->next = (BLI_freenode*)addr;
+ if (pool->allow_iter) {
+ if (j != pool->pchunk-1)
+ curnode->next->freeword = FREEWORD;
+ curnode->freeword = FREEWORD;
+ }
}
/*final pointer in the previously allocated chunk is wrong.*/
- if(lasttail) lasttail->next = mpchunk->data;
+ if(lasttail) {
+ lasttail->next = mpchunk->data;
+ if (pool->allow_iter)
+ lasttail->freeword = FREEWORD;
+ }
+
/*set the end of this chunks memoryy to the new tail for next iteration*/
lasttail = curnode;
pool->totalloc += pool->pchunk;
}
+
/*terminate the list*/
curnode->next = NULL;
return pool;
}
+#if 0
void *BLI_mempool_alloc(BLI_mempool *pool){
void *retval=NULL;
BLI_freenode *curnode=NULL;
char *addr=NULL;
int j;
-
+
+ if (!pool) return NULL;
+
pool->totused++;
if(!(pool->free)){
@@ -113,10 +133,18 @@ void *BLI_mempool_alloc(BLI_mempool *pool){
BLI_addtail(&(pool->chunks), mpchunk);
pool->free = mpchunk->data; /*start of the list*/
+ if (pool->allow_iter)
+ pool->free->freeword = FREEWORD;
for(addr = mpchunk->data, j=0; j < pool->pchunk; j++){
curnode = ((BLI_freenode*)addr);
addr += pool->esize;
curnode->next = (BLI_freenode*)addr;
+
+ if (pool->allow_iter) {
+ curnode->freeword = FREEWORD;
+ if (j != pool->pchunk-1)
+ curnode->next->freeword = FREEWORD;
+ }
}
curnode->next = NULL; /*terminate the list*/
@@ -124,15 +152,19 @@ void *BLI_mempool_alloc(BLI_mempool *pool){
}
retval = pool->free;
+ if (pool->allow_iter)
+ pool->free->freeword = 0x7FFFFFFF;
+
pool->free = pool->free->next;
//memset(retval, 0, pool->esize);
return retval;
}
+#endif
void *BLI_mempool_calloc(BLI_mempool *pool){
void *retval=NULL;
retval = BLI_mempool_alloc(pool);
- memset(retval, 0, pool->esize);
+ BMEMSET(retval, 0, pool->esize);
return retval;
}
@@ -142,7 +174,9 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr){ //doesnt protect against d
BLI_freenode *curnode=NULL;
char *tmpaddr=NULL;
int i;
-
+
+ if (pool->allow_iter)
+ newhead->freeword = FREEWORD;
newhead->next = pool->free;
pool->free = newhead;
@@ -175,6 +209,50 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr){ //doesnt protect against d
}
}
+void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter)
+{
+ if (!pool->allow_iter) {
+ fprintf(stderr, "evil! you can't iterate over this mempool!\n");
+ iter->curchunk = NULL;
+ iter->curindex = 0;
+
+ return;
+ }
+
+ iter->pool = pool;
+ iter->curchunk = pool->chunks.first;
+ iter->curindex = 0;
+}
+
+static void *bli_mempool_iternext(BLI_mempool_iter *iter)
+{
+ void *ret = NULL;
+
+ if (!iter->curchunk || !iter->pool->totused) return NULL;
+
+ ret = ((char*)iter->curchunk->data) + iter->pool->esize*iter->curindex;
+
+ iter->curindex++;
+
+ if (iter->curindex >= iter->pool->pchunk) {
+ iter->curchunk = iter->curchunk->next;
+ iter->curindex = 0;
+ }
+
+ return ret;
+}
+
+void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
+{
+ BLI_freenode *ret;
+
+ do {
+ ret = bli_mempool_iternext(iter);
+ } while (ret && ret->freeword == FREEWORD);
+
+ return ret;
+}
+
void BLI_mempool_destroy(BLI_mempool *pool)
{
BLI_mempool_chunk *mpchunk=NULL;
diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c
index 1ce3f179558..f885f7e5b22 100644
--- a/source/blender/blenlib/intern/edgehash.c
+++ b/source/blender/blenlib/intern/edgehash.c
@@ -22,7 +22,7 @@
*
* The Original Code is: none of this file.
*
- * Contributor(s): Daniel Dunbar
+ * Contributor(s): Daniel Dunbar, Joseph Eagar
*
* ***** END GPL LICENSE BLOCK *****
* A general (pointer -> pointer) hash table ADT
@@ -33,112 +33,20 @@
#include "MEM_guardedalloc.h"
#include "BLI_edgehash.h"
-
-/***/
-
-static unsigned int hashsizes[]= {
- 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209,
- 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169,
- 4194319, 8388617, 16777259, 33554467, 67108879, 134217757,
- 268435459
-};
-
-#define EDGEHASH(v0,v1) ((v0*39)^(v1*31))
-
-/***/
-
-typedef struct Entry Entry;
-struct Entry {
- Entry *next;
- int v0, v1;
- void *val;
-};
-
-struct EdgeHash {
- Entry **buckets;
- int nbuckets, nentries, cursize;
-};
+#include "BLI_mempool.h"
/***/
EdgeHash *BLI_edgehash_new(void) {
- EdgeHash *eh= MEM_mallocN(sizeof(*eh), "EdgeHash");
+ EdgeHash *eh= MEM_callocN(sizeof(*eh), "EdgeHash");
eh->cursize= 0;
eh->nentries= 0;
- eh->nbuckets= hashsizes[eh->cursize];
-
- eh->buckets= malloc(eh->nbuckets*sizeof(*eh->buckets));
- memset(eh->buckets, 0, eh->nbuckets*sizeof(*eh->buckets));
+ eh->nbuckets= _ehash_hashsizes[eh->cursize];
- return eh;
-}
-
-void BLI_edgehash_insert(EdgeHash *eh, int v0, int v1, void *val) {
- unsigned int hash;
- Entry *e= malloc(sizeof(*e));
+ eh->buckets= MEM_callocN(eh->nbuckets*sizeof(*eh->buckets), "eh buckets 2");
+ eh->epool = BLI_mempool_create(sizeof(EdgeEntry), 512, 512, 1, 0);
- if (v1<v0) {
- v0 ^= v1;
- v1 ^= v0;
- v0 ^= v1;
- }
- hash = EDGEHASH(v0,v1)%eh->nbuckets;
-
- e->v0 = v0;
- e->v1 = v1;
- e->val = val;
- e->next= eh->buckets[hash];
- eh->buckets[hash]= e;
-
- if (++eh->nentries>eh->nbuckets*3) {
- Entry *e, **old= eh->buckets;
- int i, nold= eh->nbuckets;
-
- eh->nbuckets= hashsizes[++eh->cursize];
- eh->buckets= malloc(eh->nbuckets*sizeof(*eh->buckets));
- memset(eh->buckets, 0, eh->nbuckets*sizeof(*eh->buckets));
-
- for (i=0; i<nold; i++) {
- for (e= old[i]; e;) {
- Entry *n= e->next;
-
- hash= EDGEHASH(e->v0,e->v1)%eh->nbuckets;
- e->next= eh->buckets[hash];
- eh->buckets[hash]= e;
-
- e= n;
- }
- }
-
- free(old);
- }
-}
-
-void** BLI_edgehash_lookup_p(EdgeHash *eh, int v0, int v1) {
- unsigned int hash;
- Entry *e;
-
- if (v1<v0) {
- v0 ^= v1;
- v1 ^= v0;
- v0 ^= v1;
- }
- hash = EDGEHASH(v0,v1)%eh->nbuckets;
- for (e= eh->buckets[hash]; e; e= e->next)
- if (v0==e->v0 && v1==e->v1)
- return &e->val;
-
- return NULL;
-}
-
-void* BLI_edgehash_lookup(EdgeHash *eh, int v0, int v1) {
- void **value_p = BLI_edgehash_lookup_p(eh,v0,v1);
-
- return value_p?*value_p:NULL;
-}
-
-int BLI_edgehash_haskey(EdgeHash *eh, int v0, int v1) {
- return BLI_edgehash_lookup_p(eh, v0, v1)!=NULL;
+ return eh;
}
int BLI_edgehash_size(EdgeHash *eh) {
@@ -149,13 +57,13 @@ void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP valfreefp) {
int i;
for (i=0; i<eh->nbuckets; i++) {
- Entry *e;
+ EdgeEntry *e;
for (e= eh->buckets[i]; e; ) {
- Entry *n= e->next;
+ EdgeEntry *n= e->next;
if (valfreefp) valfreefp(e->val);
- free(e);
+ BLI_mempool_free(eh->epool, e);
e= n;
}
@@ -167,8 +75,10 @@ void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP valfreefp) {
void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP valfreefp) {
BLI_edgehash_clear(eh, valfreefp);
-
- free(eh->buckets);
+
+ BLI_mempool_destroy(eh->epool);
+
+ MEM_freeN(eh->buckets);
MEM_freeN(eh);
}
@@ -178,11 +88,11 @@ void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP valfreefp) {
struct EdgeHashIterator {
EdgeHash *eh;
int curBucket;
- Entry *curEntry;
+ EdgeEntry *curEntry;
};
EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) {
- EdgeHashIterator *ehi= malloc(sizeof(*ehi));
+ EdgeHashIterator *ehi= MEM_mallocN(sizeof(*ehi), "eh iter");
ehi->eh= eh;
ehi->curEntry= NULL;
ehi->curBucket= -1;
@@ -195,7 +105,7 @@ EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) {
return ehi;
}
void BLI_edgehashIterator_free(EdgeHashIterator *ehi) {
- free(ehi);
+ MEM_freeN(ehi);
}
void BLI_edgehashIterator_getKey(EdgeHashIterator *ehi, int *v0_r, int *v1_r) {
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 8e0fea54e68..2d4935ed4a6 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -1702,7 +1702,7 @@ void interp_weights_poly_v3(float *w,float v[][3], int n, float *co)
t2= mean_value_half_tan(co, vmid, vnext);
len= len_v3v3(co, vmid);
- w[i]= (t1+t2)/len;
+ w[i]= (t1+t2)/(len+FLT_EPSILON*2);
totweight += w[i];
}
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 77c2c9b74d2..52d55ab948b 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -414,6 +414,29 @@ MINLINE float normalize_v3_v3(float r[3], const float a[3])
return d;
}
+MINLINE double normalize_dv3(double n[3])
+{
+ double d= n[0]*n[0] + n[1]*n[1] + n[2]*n[2];
+
+ /* a larger value causes normalize errors in a
+ scaled down models with camera xtreme close */
+ if(d > 1.0e-35f) {
+ double mul;
+
+ d= sqrt(d);
+ mul = 1.0 / d;
+
+ n[0] *= mul;
+ n[1] *= mul;
+ n[2] *= mul;
+ } else {
+ n[0] = n[1] = n[2] = 0;
+ d= 0.0;
+ }
+
+ return d;
+}
+
MINLINE float normalize_v3(float n[3])
{
return normalize_v3_v3(n, n);
diff --git a/source/blender/blenlib/intern/pbvh.c b/source/blender/blenlib/intern/pbvh.c
index cc62742969e..3393a2674e9 100644
--- a/source/blender/blenlib/intern/pbvh.c
+++ b/source/blender/blenlib/intern/pbvh.c
@@ -1400,7 +1400,8 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
return hit;
}
-//#include <GL/glew.h>
+//#include "BIF_gl.h"
+//#include "BIF_glutil.h"
void BLI_pbvh_node_draw(PBVHNode *node, void *UNUSED(data))
{
diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c
index 923abf22794..5fb9842b7a2 100644
--- a/source/blender/blenlib/intern/rct.c
+++ b/source/blender/blenlib/intern/rct.c
@@ -38,6 +38,8 @@
#include <math.h>
#include "DNA_vec_types.h"
+#include <stdio.h>
+#include <math.h>
#include "BLI_rect.h"
int BLI_rcti_is_empty(rcti * rect)
diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c
index af7795030a0..2054179a7e2 100644
--- a/source/blender/blenlib/intern/scanfill.c
+++ b/source/blender/blenlib/intern/scanfill.c
@@ -28,6 +28,11 @@
* (uit traces) maart 95
*/
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
#include "MEM_guardedalloc.h"
#include "BLI_callbacks.h"
@@ -35,6 +40,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_scanfill.h"
+#include "BLI_utildefines.h"
/* callbacks for errors and interrupts and some goo */
static void (*BLI_localErrorCallBack)(const char*) = NULL;
@@ -140,7 +146,7 @@ static void *new_mem_element(int size)
{
int blocksize= 16384;
static int offs= 0; /* the current free address */
- static struct mem_elements *cur= 0;
+ static struct mem_elements *cur= 0, *first;
static ListBase lb= {0, 0};
void *adr;
@@ -148,6 +154,10 @@ static void *new_mem_element(int size)
printf("incorrect use of new_mem_element\n");
}
else if(size== -1) {
+ /*keep the first block*/
+ first = lb.first;
+ BLI_remlink(&lb, first);
+
cur= lb.first;
while(cur) {
MEM_freeN(cur->data);
@@ -155,6 +165,12 @@ static void *new_mem_element(int size)
}
BLI_freelistN(&lb);
+ /*reset the block we're keeping*/
+ BLI_addtail(&lb, first);
+ memset(first->data, 0, blocksize);
+ cur = first;
+ offs = 0;
+
return NULL;
}
@@ -755,6 +771,7 @@ int BLI_edgefill(int mat_nr)
- struct elements xs en ys are not used here: don't hide stuff in it
- edge flag ->f becomes 2 when it's a new edge
- mode: & 1 is check for crossings, then create edges (TO DO )
+ - mode: & 2 is enable shortest diagonal test for quads
*/
ListBase tempve, temped;
EditVert *eve;
@@ -765,11 +782,42 @@ int BLI_edgefill(int mat_nr)
/* reset variables */
eve= fillvertbase.first;
+ a = 0;
while(eve) {
eve->f= 0;
eve->xs= 0;
eve->h= 0;
eve= eve->next;
+ a += 1;
+ }
+
+ if (a == 3) {
+ eve = fillvertbase.first;
+
+ addfillface(eve, eve->next, eve->next->next, 0);
+ return 1;
+ } else if (a == 4) {
+ float vec1[3], vec2[3];
+
+ eve = fillvertbase.first;
+
+ if (1) { //BMESH_TODO this is correct, right? -joeedh //mode & 2) {
+ /*use shortest diagonal for quad*/
+ sub_v3_v3v3(vec1, eve->co, eve->next->next->co);
+ sub_v3_v3v3(vec2, eve->next->co, eve->next->next->next->co);
+
+ if (INPR(vec1, vec1) < INPR(vec2, vec2)) {
+ addfillface(eve, eve->next, eve->next->next, 0);
+ addfillface(eve->next->next, eve->next->next->next, eve, 0);
+ } else{
+ addfillface(eve->next, eve->next->next, eve->next->next->next, 0);
+ addfillface(eve->next->next->next, eve, eve->next, 0);
+ }
+ } else {
+ addfillface(eve, eve->next, eve->next->next, 0);
+ addfillface(eve->next->next, eve->next->next->next, eve, 0);
+ }
+ return 1;
}
/* first test vertices if they are in edges */
diff --git a/source/blender/blenloader/SConscript b/source/blender/blenloader/SConscript
index 695d17f0638..b3cb98abb9b 100644
--- a/source/blender/blenloader/SConscript
+++ b/source/blender/blenloader/SConscript
@@ -5,7 +5,7 @@ sources = env.Glob('intern/*.c')
incs = '. #/intern/guardedalloc ../blenlib ../blenkernel'
incs += ' ../makesdna ../readblenfile ../editors/include'
-incs += ' ../render/extern/include ../makesrna'
+incs += ' ../render/extern/include ../makesrna ../bmesh'
incs += ' ' + env['BF_ZLIB_INC']
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 9c2ceb12c5a..4fbc19e1c2c 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -88,6 +88,8 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_cellalloc.h"
+#include "BLI_edgehash.h"
#include "BLI_utildefines.h"
#include "BKE_anim.h"
@@ -2487,6 +2489,16 @@ static void lib_link_key(FileData *fd, Main *main)
key= main->key.first;
while(key) {
+ /*check if we need to generate unique ids for the shapekeys*/
+ if (!key->uidgen) {
+ KeyBlock *block;
+
+ key->uidgen = 1;
+ for (block=key->block.first; block; block=block->next) {
+ block->uid = key->uidgen++;
+ }
+ }
+
if(key->id.flag & LIB_NEEDLINK) {
if(key->adt) lib_link_animdata(fd, &key->id, key->adt);
@@ -3345,6 +3357,26 @@ static void lib_link_customdata_mtface(FileData *fd, Mesh *me, CustomData *fdata
}
+static void lib_link_customdata_mtpoly(FileData *fd, Mesh *me, CustomData *pdata, int totface)
+{
+ int i;
+
+ for(i=0; i<pdata->totlayer; i++) {
+ CustomDataLayer *layer = &pdata->layers[i];
+
+ if(layer->type == CD_MTEXPOLY) {
+ MTexPoly *tf= layer->data;
+ int i;
+
+ for (i=0; i<totface; i++, tf++) {
+ tf->tpage= newlibadr(fd, me->id.lib, tf->tpage);
+ if(tf->tpage && tf->tpage->id.us==0)
+ tf->tpage->id.us= 1;
+ }
+ }
+ }
+}
+
static void lib_link_mesh(FileData *fd, Main *main)
{
Mesh *me;
@@ -3372,6 +3404,7 @@ static void lib_link_mesh(FileData *fd, Main *main)
me->texcomesh= newlibadr_us(fd, me->id.lib, me->texcomesh);
lib_link_customdata_mtface(fd, me, &me->fdata, me->totface);
+ lib_link_customdata_mtpoly(fd, me, &me->pdata, me->totpoly);
if(me->mr && me->mr->levels.first)
lib_link_customdata_mtface(fd, me, &me->mr->fdata,
((MultiresLevel*)me->mr->levels.first)->totface);
@@ -3390,7 +3423,19 @@ static void direct_link_dverts(FileData *fd, int count, MDeformVert *mdverts)
return;
for (i=0; i<count; i++) {
+ void *tmp;
+
mdverts[i].dw=newdataadr(fd, mdverts[i].dw);
+
+ /*convert to vgroup allocation system*/
+ if (mdverts[i].dw) {
+ tmp = BLI_cellalloc_malloc(MEM_allocN_len(mdverts[i].dw), "vgroups from readfile.c");
+ memcpy(tmp, mdverts[i].dw, MEM_allocN_len(mdverts[i].dw));
+
+ MEM_freeN(mdverts[i].dw);
+ mdverts[i].dw = tmp;
+ }
+
if (!mdverts[i].dw)
mdverts[i].totweight=0;
}
@@ -3420,6 +3465,8 @@ static void direct_link_mdisps(FileData *fd, int count, MDisps *mdisps, int exte
}
}
+/*this isn't really a public api function, so prototyped here*/
+void customData_update_typemap(CustomData *data);
static void direct_link_customdata(FileData *fd, CustomData *data, int count)
{
int i = 0;
@@ -3440,6 +3487,126 @@ static void direct_link_customdata(FileData *fd, CustomData *data, int count)
i++;
}
}
+
+ customData_update_typemap(data);
+}
+
+
+void bmesh_corners_to_loops(Mesh *me, int findex, int loopstart, int numTex, int numCol)
+{
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ MFace *mf;
+ int i;
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_get_n(&me->fdata, CD_MTFACE, findex, i);
+ texpoly = CustomData_get_n(&me->pdata, CD_MTEXPOLY, findex, i);
+ mf = me->mface + findex;
+
+ texpoly->tpage = texface->tpage;
+ texpoly->flag = texface->flag;
+ texpoly->transp = texface->transp;
+ texpoly->mode = texface->mode;
+ texpoly->tile = texface->tile;
+ texpoly->unwrap = texface->unwrap;
+
+ mloopuv = CustomData_get_n(&me->ldata, CD_MLOOPUV, loopstart, i);
+ mloopuv->uv[0] = texface->uv[0][0]; mloopuv->uv[1] = texface->uv[0][1]; mloopuv++;
+ mloopuv->uv[0] = texface->uv[1][0]; mloopuv->uv[1] = texface->uv[1][1]; mloopuv++;
+ mloopuv->uv[0] = texface->uv[2][0]; mloopuv->uv[1] = texface->uv[2][1]; mloopuv++;
+
+ if (mf->v4) {
+ mloopuv->uv[0] = texface->uv[3][0]; mloopuv->uv[1] = texface->uv[3][1]; mloopuv++;
+ }
+ }
+
+ for(i=0; i < numCol; i++){
+ mf = me->mface + findex;
+ mloopcol = CustomData_get_n(&me->ldata, CD_MLOOPCOL, loopstart, i);
+ mcol = CustomData_get_n(&me->fdata, CD_MCOL, findex, i);
+
+ mloopcol->r = mcol[0].r; mloopcol->g = mcol[0].g; mloopcol->b = mcol[0].b; mloopcol->a = mcol[0].a; mloopcol++;
+ mloopcol->r = mcol[1].r; mloopcol->g = mcol[1].g; mloopcol->b = mcol[1].b; mloopcol->a = mcol[1].a; mloopcol++;
+ mloopcol->r = mcol[2].r; mloopcol->g = mcol[2].g; mloopcol->b = mcol[2].b; mloopcol->a = mcol[2].a; mloopcol++;
+ if (mf->v4) {
+ mloopcol->r = mcol[3].r; mloopcol->g = mcol[3].g; mloopcol->b = mcol[3].b; mloopcol->a = mcol[3].a; mloopcol++;
+ }
+ }
+}
+
+static void convert_mfaces_to_mpolys(Mesh *mesh)
+{
+ MFace *mf;
+ MLoop *ml;
+ MPoly *mp;
+ MEdge *me;
+ EdgeHash *eh;
+ int numTex, numCol;
+ int i, j, totloop;
+
+ mesh->totpoly = mesh->totface;
+ mesh->mpoly = MEM_callocN(sizeof(MPoly)*mesh->totpoly, "mpoly converted");
+ CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_ASSIGN, mesh->mpoly, mesh->totpoly);
+
+ numTex = CustomData_number_of_layers(&mesh->fdata, CD_MTFACE);
+ numCol = CustomData_number_of_layers(&mesh->fdata, CD_MCOL);
+
+ totloop = 0;
+ mf = mesh->mface;
+ for (i=0; i<mesh->totface; i++, mf++) {
+ totloop += mf->v4 ? 4 : 3;
+ }
+
+ mesh->totloop = totloop;
+ mesh->mloop = MEM_callocN(sizeof(MLoop)*mesh->totloop, "mloop converted");
+
+ CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_ASSIGN, mesh->mloop, totloop);
+ CustomData_to_bmeshpoly(&mesh->fdata, &mesh->pdata, &mesh->ldata,
+ mesh->totloop, mesh->totpoly);
+
+ eh = BLI_edgehash_new();
+
+ /*build edge hash*/
+ me = mesh->medge;
+ for (i=0; i<mesh->totedge; i++, me++) {
+ BLI_edgehash_insert(eh, me->v1, me->v2, SET_INT_IN_POINTER(i));
+ }
+
+ j = 0; /*current loop index*/
+ ml = mesh->mloop;
+ mf = mesh->mface;
+ mp = mesh->mpoly;
+ for (i=0; i<mesh->totface; i++, mf++, mp++) {
+ mp->loopstart = j;
+
+ mp->totloop = mf->v4 ? 4 : 3;
+
+ mp->mat_nr = mf->mat_nr;
+ mp->flag = mf->flag;
+
+ #define ML(v1, v2) {ml->v = mf->v1; ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); ml++; j++;}
+
+ ML(v1, v2);
+ ML(v2, v3);
+ if (mf->v4) {
+ ML(v3, v4);
+ ML(v4, v1);
+ } else {
+ ML(v3, v1);
+ }
+
+ #undef ML
+
+ bmesh_corners_to_loops(mesh, i, mp->loopstart, numTex, numCol);
+ }
+
+ /*BMESH_TODO now to deal with fgons*/
+
+ BLI_edgehash_free(eh, NULL);
}
static void direct_link_mesh(FileData *fd, Mesh *mesh)
@@ -3450,12 +3617,17 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
mesh->mvert= newdataadr(fd, mesh->mvert);
mesh->medge= newdataadr(fd, mesh->medge);
mesh->mface= newdataadr(fd, mesh->mface);
+ mesh->mloop= newdataadr(fd, mesh->mloop);
+ mesh->mpoly= newdataadr(fd, mesh->mpoly);
mesh->tface= newdataadr(fd, mesh->tface);
mesh->mtface= newdataadr(fd, mesh->mtface);
mesh->mcol= newdataadr(fd, mesh->mcol);
mesh->msticky= newdataadr(fd, mesh->msticky);
mesh->dvert= newdataadr(fd, mesh->dvert);
-
+ mesh->mloopcol= newdataadr(fd, mesh->mloopcol);
+ mesh->mloopuv= newdataadr(fd, mesh->mloopuv);
+ mesh->mtpoly= newdataadr(fd, mesh->mtpoly);
+
/* animdata */
mesh->adt= newdataadr(fd, mesh->adt);
direct_link_animdata(fd, mesh->adt);
@@ -3476,10 +3648,12 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
direct_link_customdata(fd, &mesh->vdata, mesh->pv ? mesh->pv->totvert : mesh->totvert);
direct_link_customdata(fd, &mesh->edata, mesh->pv ? mesh->pv->totedge : mesh->totedge);
direct_link_customdata(fd, &mesh->fdata, mesh->pv ? mesh->pv->totface : mesh->totface);
-
+ direct_link_customdata(fd, &mesh->ldata, mesh->totloop);
+ direct_link_customdata(fd, &mesh->pdata, mesh->totpoly);
+
mesh->bb= NULL;
mesh->mselect = NULL;
- mesh->edit_mesh= NULL;
+ mesh->edit_btmesh= NULL;
/* Multires data */
mesh->mr= newdataadr(fd, mesh->mr);
@@ -3529,6 +3703,11 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
SWITCH_INT(tf->col[3]);
}
}
+
+ /*check if we need to convert mfaces to mpolys*/
+ if (mesh->totface && !mesh->totpoly) {
+ convert_mfaces_to_mpolys(mesh);
+ }
}
/* ************ READ LATTICE ***************** */
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index d2d6c2412cd..2f8feb9b9da 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -1117,16 +1117,16 @@ static void write_constraints(WriteData *wd, ListBase *conlist)
of library blocks that implement this.*/
IDP_WriteProperty(data->prop, wd);
}
- break;
+ break;
case CONSTRAINT_TYPE_SPLINEIK:
{
bSplineIKConstraint *data= (bSplineIKConstraint*)con->data;
/* write points array */
writedata(wd, DATA, sizeof(float)*(data->numpoints), data->points);
- }
- break;
}
+ break;
+ }
}
/* Write the constraint */
@@ -1582,6 +1582,8 @@ static void write_meshs(WriteData *wd, ListBase *idbase)
write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, -1, 0);
write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, -1, 0);
write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, -1, 0);
}
/* PMV data */
diff --git a/source/blender/blenpluginapi/SConscript b/source/blender/blenpluginapi/SConscript
index 32e69069bb0..178f470e080 100644
--- a/source/blender/blenpluginapi/SConscript
+++ b/source/blender/blenpluginapi/SConscript
@@ -7,6 +7,8 @@ incs = '. .. #/intern/guardedalloc ../blenlib ../imbuf ../makesdna ../blenloader
defs = []
+incs += ' ' + env["BF_PTHREADS_INC"]
+
if env['WITH_BF_QUICKTIME']:
defs.append('WITH_QUICKTIME')
incs += ' ' + env['BF_QUICKTIME_INC']
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
new file mode 100644
index 00000000000..870cfa66a61
--- /dev/null
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -0,0 +1,124 @@
+# $Id: CMakeLists.txt 31746 2010-09-04 05:31:25Z joeedh $
+# ***** 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) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ../avi
+ ../blenlib
+ ../blenloader
+ ../blenkernel
+ operators
+ intern
+ ../editors/mesh
+ ../gpu
+ ../ikplugin
+ ../imbuf
+ ../makesdna
+ ../makesrna
+ ../modifiers
+ ../nodes
+ ../editors/include
+ ../render/extern/include
+ ../../../extern/glew/include
+ ../../../intern/audaspace/intern
+ ../../../intern/bsp/extern ../blenfont
+ ../../../intern/decimation/extern
+ ../../../intern/elbeem/extern
+ ../../../intern/guardedalloc
+ ../../../intern/iksolver/extern
+ ../../../intern/memutil
+ ../../../intern/opennl/extern
+ ../../../intern/smoke/extern
+ ../../../intern/mikktspace
+ ../../../source/blender/windowmanager # XXX - BAD LEVEL CALL WM_api.h
+ ${ZLIB_INCLUDE_DIRS}
+)
+
+set(SRC
+ operators/bmesh_dupeops.c
+ operators/utils.c
+ operators/subdivideop.c
+ operators/connectops.c
+ operators/removedoubles.c
+ operators/mirror.c
+ operators/primitiveops.c
+ operators/join_triangles.c
+ operators/edgesplitop.c
+ operators/createops.c
+ operators/dissolveops.c
+ operators/subdivideop.h
+ operators/triangulateop.c
+ operators/mesh_conv.c
+ operators/extrudeops.c
+ bmesh_operators.h
+ bmesh_iterators.h
+ intern/bmesh_newcore.c
+ intern/bmesh_interp.c
+ intern/bmesh_iterators.c
+ intern/bmesh_marking.c
+ intern/bmesh_mesh.c
+ intern/bmesh_mods.c
+ intern/bmesh_structure.h
+ intern/bmesh_construct.c
+ intern/bmesh_walkers.c
+ intern/bmesh_to_editmesh.c
+ intern/bmesh_operators_private.h
+ intern/editmesh_to_bmesh.c
+ intern/bmesh_structure.c
+ intern/bmesh_polygon.c
+ intern/bmesh_queries.c
+ intern/bmesh_opdefines.c
+ intern/bmesh_filters.c
+ intern/bmesh_eulers.c
+ intern/bmesh_operators.c
+ intern/bmesh_private.h
+ bmesh_error.h
+ bmesh_queries.h
+ bmesh.h
+ bmesh_marking.h
+ bmesh_operator_api.h
+ bmesh_filters.h
+ bmesh_class.h
+ bmesh_walkers.h
+)
+
+add_definitions(-DGLEW_STATIC)
+
+if(WITH_LZO)
+ list(APPEND INC ../../../extern/lzo/minilzo)
+ add_definitions(-DWITH_LZO)
+endif()
+
+if(WITH_LZMA)
+ list(APPEND INC ../../../extern/lzma)
+ add_definitions(-DWITH_LZMA)
+endif()
+
+if(MSVC)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
+endif()
+
+blender_add_lib(bf_bmesh "${SRC}" "${INC}")
diff --git a/source/blender/bmesh/SConscript b/source/blender/bmesh/SConscript
new file mode 100644
index 00000000000..8de603e4dc9
--- /dev/null
+++ b/source/blender/bmesh/SConscript
@@ -0,0 +1,39 @@
+#!/usr/bin/python
+Import ('env')
+
+cflags=''
+"""
+sources = ['intern/bmesh_eulers.c']
+sources.append('intern/bmesh_mesh.c')
+sources.append('intern/bmesh_polygon.c')
+sources.append('intern/bmesh_structure.c')
+sources.append('intern/bmesh_marking.c')
+
+sources.append('intern/bmesh_construct.c')
+sources.append('intern/bmesh_interp.c')
+sources.append('intern/bmesh_filters.c')
+sources.append('intern/bmesh_iterators.c')
+sources.append('intern/bmesh_mods.c')
+sources.append('intern/bmesh_queries.c')
+sources.append('intern/bmesh_operators.c')
+"""
+#sources.append('api/BME_walkers.c')
+
+
+sources = env.Glob('intern/*.c')
+sources += env.Glob('operators/*.c')
+
+#sources += env.Glob('tools/*.c')
+
+incs = ['#/intern/guardedalloc']
+incs.append('../blenlib')
+incs.append('../makesdna')
+incs.append('../makesrna')
+incs.append('../blenkernel')
+incs.append('./')
+incs.append('./intern')
+incs.append('../editors/mesh')
+incs.append('../editors/include')
+
+defs = []
+env.BlenderLib ( libname = 'bf_bmesh', sources = sources, includes = Split(incs), libtype = 'core', defines=defs, priority=100, compileflags=cflags )
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
new file mode 100644
index 00000000000..01f714000f0
--- /dev/null
+++ b/source/blender/bmesh/bmesh.h
@@ -0,0 +1,400 @@
+/**
+ * bmesh.h jan 2007
+ *
+ * BMesh API.
+ *
+ * $Id: BKE_bmesh.h,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle, Levi Schooley.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BMESH_H
+#define BMESH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "DNA_listBase.h"
+#include "DNA_scene_types.h"
+#include "DNA_customdata_types.h"
+
+#include "BKE_customdata.h"
+
+/*
+short introduction:
+
+the bmesh structure is a boundary representation, supporting non-manifold
+locally modifiable topology. the API is designed to allow clean, maintainable
+code, that never (or almost never) directly inspects the underlying structure.
+
+The API includes iterators, including many useful topological iterators;
+walkers, which walk over a mesh, without the risk of hitting the recursion
+limit; operators, which are logical, reusable mesh modules; topological
+modification functions (like split face, join faces, etc), which are used for
+topological manipulations; and some (not yet finished) geometric utility
+functions.
+
+some definitions:
+
+tool flags: private flags for tools. each operator has it's own private
+ tool flag "layer", which it can use to flag elements.
+ tool flags are also used by various other parts of the api.
+header flags: stores persistent flags, such as selection state, hide state,
+ etc. be careful of touching these.
+*/
+
+/*forward declarations*/
+struct BMesh;
+struct BMVert;
+struct BMEdge;
+struct BMFace;
+struct BMLoop;
+struct BMOperator;
+struct Mesh;
+struct EditMesh;
+
+/*
+ * BMHeader
+ *
+ * All mesh elements begin with a BMHeader. This structure
+ * hold several types of data
+ *
+ * 1: The type of the element (vert, edge, loop or face)
+ * 2: Persistant "header" flags/markings (sharp, seam, select, hidden, ect)
+ note that this is different from the "tool" flags.
+ * 3: Unique ID in the bmesh.
+ * 4: some elements for internal record keeping.
+ *
+*/
+
+/*BMHeader->type*/
+#define BM_VERT 1
+#define BM_EDGE 2
+#define BM_LOOP 4
+#define BM_FACE 8
+#define BM_ALL (BM_VERT | BM_EDGE | BM_LOOP | BM_FACE)
+
+/*BMHeader->flag*/
+#define BM_SELECT (1<<0)
+
+#define BM_SEAM (1<<1)
+#define BM_FGON (1<<2)
+#define BM_HIDDEN (1<<3)
+#define BM_SHARP (1<<4)
+#define BM_SMOOTH (1<<5)
+#define BM_ACTIVE (1<<6)
+#define BM_NONORMCALC (1<<7)
+#define BM_PINNED (1<<8)
+
+#include "bmesh_class.h"
+
+/*stub */
+void bmesh_error ( void );
+
+/*Mesh Level Ops */
+struct BMesh *BM_Make_Mesh ( int allocsize[4] );
+BMesh *BM_Copy_Mesh ( BMesh *bmold );
+void BM_Free_Mesh ( struct BMesh *bm );
+
+/*frees mesh, but not actual BMesh struct*/
+void BM_Free_Mesh_Data ( BMesh *bm );
+void BM_Compute_Normals ( struct BMesh *bm );
+
+/*Construction*/
+struct BMVert *BM_Make_Vert ( struct BMesh *bm, float co[3], struct BMVert *example );
+struct BMEdge *BM_Make_Edge ( struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMEdge *example, int nodouble );
+struct BMFace *BM_Make_Quadtriangle ( struct BMesh *bm, struct BMVert **verts, BMEdge **edges, int len, struct BMFace *example, int nodouble );
+
+BMFace *BM_Make_Face(BMesh *bm, BMVert **verts, BMEdge **edges, int len);
+
+/*more easier to use version of BM_Make_Quadtriangle.
+ creates edges if necassary.*/
+BMFace *BM_Make_QuadTri ( BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3,
+ BMVert *v4, BMFace *example, int nodouble );
+
+/*makes an ngon from an unordered list of edges. v1 and v2 must be the verts
+defining edges[0], and define the winding of the new face.*/
+struct BMFace *BM_Make_Ngon ( struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMEdge **edges, int len, int nodouble );
+
+/*stuff for dealing with header flags*/
+#define BM_TestHFlag(ele, f) (ele && (((BMHeader*)ele)->flag & (f)))
+#define BM_SetHFlag(ele, f) (((BMHeader*)ele)->flag = ((BMHeader*)ele)->flag | (f))
+#define BM_ClearHFlag(ele, f) (((BMHeader*)ele)->flag = ((BMHeader*)ele)->flag & ~(f))
+
+/*stuff for setting indices in elements.*/
+#define BMINDEX_SET(ele, i) (((BMHeader*)ele)->index = i)
+#define BMINDEX_GET(ele) (((BMHeader*)ele)->index)
+
+/*copies loop data from adjacent faces*/
+void BM_Face_CopyShared ( BMesh *bm, BMFace *f );
+
+/*copies attributes, e.g. customdata, header flags, etc, from one element
+ to another of the same type.*/
+void BM_Copy_Attributes ( struct BMesh *source_mesh, struct BMesh *target_mesh, void *source, void *target );
+
+/*Modification*/
+/*join two adjacent faces together along an edge. note that
+ the faces must only be joined by on edge. e is the edge you
+ wish to dissolve.*/
+BMFace *BM_Join_TwoFaces(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e);
+
+/*generic, flexible join faces function; note that most everything uses
+ this, including BM_Join_TwoFaces*/
+BMFace *BM_Join_Faces(BMesh *bm, BMFace **faces, int totface);
+
+/*split a face along two vertices. returns the newly made face, and sets
+ the nl member to a loop in the newly created edge.*/
+struct BMFace *BM_Split_Face ( struct BMesh *bm, struct BMFace *f,
+ struct BMVert *v1, struct BMVert *v2,
+ struct BMLoop **nl, struct BMEdge *example );
+
+/*dissolves a vert shared only by two edges*/
+void BM_Collapse_Vert ( struct BMesh *bm, struct BMEdge *ke, struct BMVert *kv,
+ float fac );
+
+/*splits an edge. ne is set to the new edge created.*/
+struct BMVert *BM_Split_Edge ( struct BMesh *bm, struct BMVert *v,
+ struct BMEdge *e, struct BMEdge **ne,
+ float percent );
+
+/*split an edge multiple times evenly*/
+struct BMVert *BM_Split_Edge_Multi ( struct BMesh *bm, struct BMEdge *e,
+ int numcuts );
+
+/*connect two verts together, through a face they share. this function may
+ be removed in the future.*/
+BMEdge *BM_Connect_Verts ( BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf );
+
+/*rotates an edge topologically, either clockwise (if ccw=0) or counterclockwise
+ (if ccw is 1).*/
+BMEdge *BM_Rotate_Edge ( BMesh *bm, BMEdge *e, int ccw );
+
+/*updates a face normal*/
+void BM_Face_UpdateNormal ( BMesh *bm, BMFace *f );
+
+/*updates face and vertex normals incident on an edge*/
+void BM_Edge_UpdateNormals ( BMesh *bm, BMEdge *e );
+
+/*update a vert normal (but not the faces incident on it)*/
+void BM_Vert_UpdateNormal ( BMesh *bm, BMVert *v );
+
+void BM_flip_normal ( BMesh *bm, BMFace *f );
+
+/*dissolves all faces around a vert, and removes it.*/
+int BM_Dissolve_Disk ( BMesh *bm, BMVert *v );
+
+/*dissolves vert, in more situations then BM_Dissolve_Disk
+ (e.g. if the vert is part of a wire edge, etc).*/
+int BM_Dissolve_Vert ( BMesh *bm, BMVert *v );
+
+
+/*Interpolation*/
+void BM_Data_Interp_From_Verts ( struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMVert *v, float fac );
+void BM_Data_Facevert_Edgeinterp ( struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMVert *v, struct BMEdge *e1, float fac );
+//void bmesh_data_interp_from_face(struct BMesh *bm, struct BMFace *source, struct BMFace *target);
+void BM_add_data_layer ( BMesh *em, CustomData *data, int type );
+void BM_add_data_layer_named ( BMesh *bm, CustomData *data, int type, char *name );
+void BM_free_data_layer ( BMesh *em, CustomData *data, int type );
+float BM_GetCDf(struct CustomData *cd, void *element, int type);
+void BM_SetCDf(struct CustomData *cd, void *element, int type, float val);
+
+
+/*computes the centroid of a face, using the center of the bounding box*/
+int BM_Compute_Face_Center ( BMesh *bm, BMFace *f, float center[3] );
+
+void BM_SelectMode_Flush ( BMesh *bm );
+
+/*convert an editmesh to a bmesh*/
+BMesh *editmesh_to_bmesh ( struct EditMesh *em );
+
+/*initializes editmesh to bmesh operator, but doesn't execute.
+ this is used in situations where you need to get access to the
+ conversion operator's editmesh->bmesh mapping slot (e.g. if you
+ need to find the bmesh edge that corrusponds to a specific editmesh
+ edge).*/
+BMesh *init_editmesh_to_bmesh ( struct EditMesh *em, struct BMOperator *op );
+
+/*converts a bmesh to an editmesh*/
+struct EditMesh *bmesh_to_editmesh ( BMesh *bm );
+
+/*convert between bmesh and Mesh flags*/
+int BMFlags_To_MEFlags ( void *element );
+
+/*convert between Mesh and bmesh flags
+ type must be BM_VERT/BM_EDGE/BM_FACE,
+ and represents the type of the element
+ parameter (the three defines map to
+ MVert, MEdge, and MPoly, respectively).*/
+int MEFlags_To_BMFlags ( int flag, int type );
+
+/*convert MLoop*** in a bmface to mtface and mcol in
+ an MFace*/
+void BM_loops_to_corners ( BMesh *bm, struct Mesh *me, int findex,
+ BMFace *f, int numTex, int numCol );
+
+void BM_Kill_Loop(BMesh *bm, BMLoop *l);
+void BM_Kill_Face(BMesh *bm, BMFace *f);
+void BM_Kill_Edge(BMesh *bm, BMEdge *e);
+void BM_Kill_Vert(BMesh *bm, BMVert *v);
+
+#define bm_firstfaceloop(p) ((BMLoopList*)(p->loops.first))->first
+
+/*include the rest of the API*/
+#include "bmesh_filters.h"
+#include "bmesh_iterators.h"
+#include "bmesh_marking.h"
+#include "bmesh_operator_api.h"
+#include "bmesh_operators.h"
+#include "bmesh_error.h"
+#include "bmesh_queries.h"
+#include "bmesh_walkers.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BMESH_H */
+
+/*old structures*/
+#if 0
+
+typedef struct BMHeader
+{
+ struct BMHeader *next, *prev;
+ int EID; /*Consider removing this/making it ifdeffed for debugging*/
+
+ /*don't confuse this with tool flags. this flag
+ member is what "header flag" means.*/
+ int flag;
+ int type; /*the element type, can be BM_VERT, BM_EDGE, BM_LOOP, or BM_FACE*/
+ int eflag1, eflag2; /*Flags used by eulers. Try and get rid of/minimize some of these*/
+
+ /*this is only used to store temporary integers.
+ don't use it for anything else.
+ use the BMINDEX_GET and BMINDEX_SET macros to access it*/
+ int index;
+ struct BMFlagLayer *flags; /*Dynamically allocated block of flag layers for operators to use*/
+ void *data; /*customdata block*/
+} BMHeader;
+
+typedef struct BMFlagLayer
+{
+ int f1;
+ short mask, pflag;
+} BMFlagLayer;
+
+#define BM_OVERLAP (1<<14) /*used by bmesh_verts_in_face*/
+#define BM_EDGEVERT (1<<15) /*used by bmesh_make_ngon*/
+
+/*
+ * BMNode
+ *
+ * Used for circular/linked list functions that form basis of
+ * adjacency system in BMesh. This should probably be hidden
+ * somewhere since tool authors never need to know about it.
+ *
+*/
+
+typedef struct BMNode
+{
+ struct BMNode *next, *prev;
+ void *data;
+} BMNode;
+
+typedef struct BMesh
+{
+ ListBase verts, edges, polys;
+ struct BLI_mempool *vpool;
+ struct BLI_mempool *epool;
+ struct BLI_mempool *lpool;
+ struct BLI_mempool *ppool;
+ struct BMVert **vtar;
+ struct BMEdge **edar;
+ struct BMLoop **lpar;
+ struct BMFace **plar;
+ int vtarlen, edarlen, lparlen, plarlen;
+ int totvert, totedge, totface, totloop;
+ int totvertsel, totedgesel, totfacesel;
+ int nextv, nexte, nextp, nextl;
+ struct CustomData vdata, edata, pdata, ldata;
+ int selectmode; /*now uses defines in DNA_scene_types.h*/
+ struct BLI_mempool *flagpool; /*memory pool for dynamically allocated flag layers*/
+ int stackdepth; /*current depth of operator stack*/
+ int totflags, walkers; /*total number of tool flag layers*/
+ ListBase errorstack;
+
+ /*selection order list*/
+ ListBase selected;
+
+ /*active face pointer*/
+ struct BMFace *act_face;
+
+ /*active shape key number, should really be in BMEditMesh, not here*/
+ int shapenr;
+} BMesh;
+
+typedef struct BMVert
+{
+ struct BMHeader head;
+ float co[3];
+ float no[3];
+ struct BMEdge *edge;
+ float bweight; /*please, someone just get rid of me...*/
+} BMVert;
+
+typedef struct BMEdge
+{
+ struct BMHeader head;
+ struct BMVert *v1, *v2;
+ struct BMNode d1, d2;
+ struct BMLoop *loop;
+ float crease, bweight; /*make these custom data.... no really, please....*/
+} BMEdge;
+
+typedef struct BMLoop
+{
+ struct BMHeader head;
+ struct BMNode radial;
+ struct BMVert *v;
+ struct BMEdge *e;
+ struct BMFace *f;
+} BMLoop;
+
+typedef struct BMFace
+{
+ struct BMHeader head;
+ struct BMLoop *loopbase;
+ int len;
+ float no[3];
+
+ /*custom data again*/
+ short mat_nr;
+} BMFace;
+#endif
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
new file mode 100644
index 00000000000..f955c1965c5
--- /dev/null
+++ b/source/blender/bmesh/bmesh_class.h
@@ -0,0 +1,273 @@
+#ifndef _BMESH_CLASS_H
+#define _BMESH_CLASS_H
+
+#include "DNA_listBase.h"
+
+#include "BKE_utildefines.h"
+#include "BLI_utildefines.h"
+
+struct BMesh;
+struct BMVert;
+struct BMEdge;
+struct BMLoop;
+struct BMFace;
+struct BMBaseVert;
+struct BMBaseEdge;
+struct BMBaseLoop;
+struct BMBaseFace;
+struct BMLayerType;
+struct BMSubClassLayer;
+struct BMFlagLayer;
+struct BLI_mempool;
+
+/*
+ UPDATE: ok, this hasn't been all that useful. Need to rip this out and just go with original
+ structs.
+
+ well, much of the actual code was great, but this inheritance thing isn't so
+ useful, need to just make CDDM better.
+*/
+/*
+ok: we have a simple subclassing system, to layer in bmesh api features (and
+let people subclass the api). There's also a separate, compile-time system
+that will end up being the back-end to a "lite" bmesh API for modifiers.
+
+there are two seperate and distinct subtyping strategies here. one is with
+macros and struct inheritence, and the other is more dynamic. this is because
+of two competing motivations for subclassing: the ability to code faster,
+less memory intensive BMTools that don't use adjacency info, and the ability
+to hook into higher-level API functions for things like multires interpolation,
+which needs much more then what is provided in the CustomData API.
+
+The first strategy is part of a plan to replace CDDM with a bmesh-like API
+(which is much easier for me then rewriting array, mirror, in CDDM, which
+would be a huge pain).
+*/
+
+/*note: it is very important for BMHeader to start with two
+ pointers. this is a requirement of mempool's method of
+ iteration.
+*/
+typedef struct BMHeader {
+ void *data; /*customdata layers*/
+ void *layerdata; /*dynamic subclass data, doesn't include BMTool and adjacency which use a static compile-time method */
+ int eid; /*element id*/
+ short type; /*element geometric type (verts/edges/loops/faces)*/
+ short flag; /*this would be a CD layer, see below*/
+ short eflag1, eflag2;
+ int sysflag, index; /*note: do *not* touch sysflag! and use BMINDEX_GET/SET macros for index*/
+ struct BMFlagLayer *flags;
+} BMHeader;
+
+/*note: need some way to specify custom locations for custom data layers. so we can
+make them point directly into structs. and some way to make it only happen to the
+active layer, and properly update when switching active layers.*/
+
+/*alloc type a: smallest mesh possible*/
+#define BM_BASE_VHEAD\
+ BMHeader head;\
+ float co[3];\
+ float no[3];
+
+typedef struct BMBaseVert {
+ BM_BASE_VHEAD
+} BMBaseVert;
+
+#define BM_BASE_EHEAD(vtype)\
+ BMHeader head;\
+ struct vtype *v1, *v2;
+
+typedef struct BMBaseEdge {
+ BM_BASE_EHEAD(BMBaseVert)
+} BMBaseEdge;
+
+#define BM_BASE_LHEAD(vtype, etype, ltype)\
+ BMHeader head;\
+ struct vtype *v;\
+ struct etype *e;\
+ struct ltype *next, *prev; /*won't be able to use listbase API, ger, due to head*/\
+ int _index; /*used for sorting during tesselation*/
+
+typedef struct BMBaseLoop {
+ BM_BASE_LHEAD(BMBaseVert, BMBaseEdge, BMBaseLoop)
+} BMBaseLoop;
+
+#define BM_BASE_LSTHEAD(listtype, looptype)\
+ struct listtype *next, *prev;\
+ struct looptype *first, *last;
+
+typedef struct BMBaseLoopList {
+ BM_BASE_LSTHEAD(BMBaseLoopList, BMBaseLoop)
+} BMBaseLoopList;
+
+#define BM_BASE_FHEAD\
+ BMHeader head;\
+ int len; /*includes all boundary loops*/\
+ int totbounds; /*total boundaries, is one plus the number of holes in the face*/\
+ ListBase loops;\
+ float no[3]; /*yes, we do store this here*/\
+ short mat_nr;
+
+typedef struct BMBaseFace {
+ BM_BASE_FHEAD
+} BMBaseFace;
+
+typedef struct BMFlagLayer {
+ short f, pflag; /*flags*/
+ int index; /*generic index*/
+} BMFlagLayer;
+
+#define BM_ADJ_VHEAD(etype)\
+ BM_BASE_VHEAD\
+ struct etype *e;
+
+typedef struct BMVert {
+ BM_ADJ_VHEAD(BMEdge)
+} BMVert;
+
+#define BM_ADJ_EHEAD(vtype, etype, ltype)\
+ BM_BASE_EHEAD(vtype)\
+ struct ltype *l;\
+ /*disk cycle pointers*/\
+ struct {\
+ struct etype *next, *prev;\
+ } dlink1;\
+ struct {\
+ struct etype *next, *prev;\
+ } dlink2;
+
+typedef struct BMEdge {
+ BM_ADJ_EHEAD(BMVert, BMEdge, BMLoop)
+} BMEdge;
+
+#define BM_ADJ_LHEAD(vtype, etype, ltype, ftype)\
+ BM_BASE_LHEAD(vtype, etype, ltype)\
+ struct ltype *radial_next, *radial_prev;\
+ struct ftype *f;
+
+typedef struct BMLoop {
+ BM_ADJ_LHEAD(BMVert, BMEdge, BMLoop, BMFace)
+} BMLoop;
+
+typedef struct BMLoopList {
+ BM_BASE_LSTHEAD(BMLoopList, BMLoop)
+} BMLoopList;
+
+#define BM_ADJ_FHEAD\
+ BM_BASE_FHEAD
+typedef struct BMFace {
+ BM_ADJ_FHEAD
+} BMFace;
+
+/*this is part of the lower-level face splitting API, higer-level
+stuff will be preferred*/
+typedef struct BMFaceCut {
+ BMLoop *l1, *l2;
+ ListBase origface_loops;
+ ListBase newface_loops;
+ BMFace *new_f; /*empty new face to be filled by api*/
+} BMFaceCut;
+
+/*ok, in nearly (if not all) cases the subclasses will use CustomData to store stuff, but they store things
+here as well (except it's not saved in files obviously, or interpolating, or all the other things the CD
+system does)*/
+#define BMSC_GETSELF(bm, e, type) (void*)(((char*)((BMHeader*)(e))->layerdata) + bm->layer_offsets[(type)->__index])
+#define BMSC_DEFAULT_LAYERSIZE sizeof(LayerType)
+
+#define BM_SUBCLASS_HEAD struct BMLayerType *type; int __index;
+
+typedef struct BMSubClassLayer {
+ BM_SUBCLASS_HEAD
+} BMSubClassLayer;
+
+typedef struct BMLayerType {
+ int vsize, esize, lsize, fsize;
+ int meshsize; /*size of custom mesh structure, if exists*/
+
+ /*note that allocation is done entirely outside of the subclass functions, thus the need for
+ the above struct size parameters*/
+ void (*new_mesh)(struct BMesh *bm, void *self);
+ void (*free_mesh)(struct BMesh *bm, void *self);
+
+ /*these functions may return NULL if this child class doesn't need to store anything
+ outside of the CustomData API*/
+ void (*new_vert)(struct BMesh *bm, BMBaseVert *v, void *self);
+ void (*new_edge)(struct BMesh *bm, BMBaseEdge *e, void *self);
+ void (*new_loop)(struct BMesh *bm, BMBaseLoop *l, void *self, BMBaseFace *f);
+ void (*new_face)(struct BMesh *bm, BMBaseFace *f, void *self);
+
+ void (*free_vert)(struct BMesh *bm, BMBaseVert *v);
+ void (*free_edge)(struct BMesh *bm, BMBaseEdge *e);
+ void (*free_loop)(struct BMesh *bm, BMBaseLoop *l);
+ void (*free_face)(struct BMesh *bm, BMBaseFace *f);
+
+ void (*copy_vert)(struct BMesh *bm, BMBaseVert *v);
+ void (*copy_edge)(struct BMesh *bm, BMBaseEdge *e);
+ void (*copy_loop)(struct BMesh *bm, BMBaseLoop *l);
+ void (*copy_face)(struct BMesh *bm, BMBaseFace *f);
+
+ /*hrm, I wonder if I should have this at all, faces_from_faces might be
+ better all by itself*/
+ void (*split_face)(struct BMesh *bm, void *f, BMFaceCut *cuts, int totcut);
+
+ /*interpolates non-CustomData-stored data. faces in dest overlap some or all faces in source*/
+ void (*faces_from_faces)(struct BMesh *bm, BMFace **sources, int totsource, BMFace **dests, int totdest);
+
+ int required_base_layers; /*sets if BMTool flags or adjacency data layers are needed*/
+ int customdata_required_layers; /*mask of required CD layers*/
+} BMLayerType;
+
+typedef struct BMesh {
+ int totvert, totedge, totloop, totface;
+ int totvertsel, totedgesel, totfacesel;
+
+ /*element pools*/
+ struct BLI_mempool *vpool, *epool, *lpool, *fpool;
+
+ /*subclass data layer pools*/
+ struct BLI_mempool *svpool, *sepool, *slpool, *sfpool;
+
+ /*operator api stuff*/
+ struct BLI_mempool *toolflagpool;
+ int stackdepth;
+ struct BMOperator *currentop;
+
+ CustomData vdata, edata, ldata, pdata;
+
+ struct BLI_mempool *looplistpool;
+
+ /*stuff for compile-time subclassing*/
+ int baselevel, totlayer;
+ BMSubClassLayer *layers; /*does not include base types*/
+ int *layer_offsets;
+
+ /*should be copy of scene select mode*/
+ int selectmode;
+
+ /*ID of the shape key this bmesh came from*/
+ int shapenr;
+
+ int walkers, totflags;
+ ListBase selected, error_stack;
+
+ BMFace *act_face;
+
+ ListBase errorstack;
+} BMesh;
+
+void BM_Copy_Vert(BMesh *bm, BMVert *destv, BMVert *source);
+void BM_Copy_Edge(BMesh *bm, BMEdge *deste, BMEdge *source);
+void BM_Copy_Loop(BMesh *bm, BMLoop *destl, BMLoop *source);
+void BM_Copy_Face(BMesh *bm, BMFace *destf, BMFace *source);
+
+#define LAYER_BASE 1
+#define LAYER_TOOL 2
+#define LAYER_ADJ 4
+#define MAX_LAYERS 2 /*does not include base*/
+
+#define BM_VERT 1
+#define BM_EDGE 2
+#define BM_LOOP 4
+#define BM_FACE 8
+
+#endif /* _BMESH_CLASS_H */
diff --git a/source/blender/bmesh/bmesh_error.h b/source/blender/bmesh/bmesh_error.h
new file mode 100644
index 00000000000..482de844cd4
--- /dev/null
+++ b/source/blender/bmesh/bmesh_error.h
@@ -0,0 +1,42 @@
+#ifndef _BMESH_ERROR_H
+#define _BMESH_ERROR_H
+
+/*----------- bmop error system ----------*/
+
+/*pushes an error onto the bmesh error stack.
+ if msg is null, then the default message for the errorcode is used.*/
+void BMO_RaiseError(BMesh *bm, BMOperator *owner, int errcode, const char *msg);
+
+/*gets the topmost error from the stack.
+ returns error code or 0 if no error.*/
+int BMO_GetError(BMesh *bm, const char **msg, BMOperator **op);
+int BMO_HasError(BMesh *bm);
+
+/*same as geterror, only pops the error off the stack as well*/
+int BMO_PopError(BMesh *bm, const char **msg, BMOperator **op);
+void BMO_ClearStack(BMesh *bm);
+
+#if 0
+//this is meant for handling errors, like self-intersection test failures.
+//it's dangerous to handle errors in general though, so disabled for now.
+
+/*catches an error raised by the op pointed to by catchop.
+ errorcode is either the errorcode, or BMERR_ALL for any
+ error.*/
+int BMO_CatchOpError(BMesh *bm, BMOperator *catchop, int errorcode, char **msg);
+#endif
+
+/*------ error code defines -------*/
+
+/*error messages*/
+#define BMERR_SELF_INTERSECTING 1
+#define BMERR_DISSOLVEDISK_FAILED 2
+#define BMERR_CONNECTVERT_FAILED 3
+#define BMERR_WALKER_FAILED 4
+#define BMERR_DISSOLVEFACES_FAILED 5
+#define BMERR_DISSOLVEVERTS_FAILED 6
+#define BMERR_TESSELATION 7
+#define BMERR_NONMANIFOLD 8
+#define BMERR_INVALID_SELECTION 9
+
+#endif /* _BMESH_ERROR_H */
diff --git a/source/blender/bmesh/bmesh_filters.h b/source/blender/bmesh/bmesh_filters.h
new file mode 100644
index 00000000000..9eed4e509fa
--- /dev/null
+++ b/source/blender/bmesh/bmesh_filters.h
@@ -0,0 +1,4 @@
+#ifndef BM_FILTER_H
+#define BM_FILTER_H
+
+#endif
diff --git a/source/blender/bmesh/bmesh_iterators.h b/source/blender/bmesh/bmesh_iterators.h
new file mode 100644
index 00000000000..1d35db8058e
--- /dev/null
+++ b/source/blender/bmesh/bmesh_iterators.h
@@ -0,0 +1,91 @@
+/*
+ * BMESH ITERATORS
+ *
+ * The functions and structures in this file
+ * provide a unified method for iterating over
+ * the elements of a mesh and answering simple
+ * adjacency queries. Tool authors should use
+ * the iterators provided in this file instead
+ * of inspecting the structure directly.
+ *
+*/
+
+#ifndef BM_ITERATORS_H
+#define BM_ITERATORS_H
+
+#include "BLI_mempool.h"
+
+/*Defines for passing to BMIter_New.
+
+ "OF" can be substituted for "around"
+ so BM_VERTS_OF_FACE means "vertices
+ around a face."
+ */
+
+/*these iterator over all elements of a specific
+ type in the mesh.*/
+#define BM_VERTS_OF_MESH 1
+#define BM_EDGES_OF_MESH 2
+#define BM_FACES_OF_MESH 3
+
+/*these are topological iterators.*/
+#define BM_EDGES_OF_VERT 4
+#define BM_FACES_OF_VERT 5
+#define BM_LOOPS_OF_VERT 6
+#define BM_FACES_OF_EDGE 7
+#define BM_VERTS_OF_FACE 8
+#define BM_EDGES_OF_FACE 9
+#define BM_LOOPS_OF_FACE 10
+/*returns elements from all boundaries, and returns
+the first element at the end to flag that we're entering
+a different face hole boundary*/
+#define BM_ALL_LOOPS_OF_FACE 11
+
+/*iterate through loops around this loop, which are fetched
+ from the other faces in the radial cycle surrounding the
+ input loop's edge.*/
+#define BM_LOOPS_OF_LOOP 12
+#define BM_LOOPS_OF_EDGE 13
+
+#define BM_ITER(ele, iter, bm, type, data) \
+ ele = BMIter_New(iter, bm, type, data); \
+ for ( ; ele; ele=BMIter_Step(iter))
+
+#define BM_ITER_SELECT(ele, iter, bm, type, data)\
+for (ele = BMIter_New(iter, bm, type, data); ele; ele=BMIter_Step(iter)) {\
+ if (BM_TestHFlag(ele, BM_HIDDEN) || !BM_TestHFlag(ele, BM_SELECT)) continue;
+
+#define BM_ITER_VISIBLE(ele, iter, bm, type, data)\
+for (ele = BMIter_New(iter, bm, type, data); ele; ele=BMIter_Step(iter)) {\
+ if (BM_TestHFlag(ele, BM_HIDDEN)) continue;
+
+#define BM_ITER_NOTSELECT(ele, iter, bm, type, data)\
+for (ele = BMIter_New(iter, bm, type, data); ele; ele=BMIter_Step(iter)) {\
+ if (BM_TestHFlag(ele, BM_HIDDEN) || BM_TestHFlag(ele, BM_SELECT)) continue;
+
+
+/*Iterator Structure*/
+typedef struct BMIter {
+ BLI_mempool_iter pooliter;
+
+ struct BMVert *firstvert, *nextvert, *vdata;
+ struct BMEdge *firstedge, *nextedge, *edata;
+ struct BMLoop *firstloop, *nextloop, *ldata, *l;
+ struct BMFace *firstpoly, *nextpoly, *pdata;
+ struct BMesh *bm;
+ void (*begin)(struct BMIter *iter);
+ void *(*step)(struct BMIter *iter);
+ union{
+ void *p;
+ int i;
+ long l;
+ float f;
+ }filter;
+ int type, count;
+}BMIter;
+
+void *BMIter_New(struct BMIter *iter, struct BMesh *bm, int type, void *data);
+void *BMIter_Step(struct BMIter *iter);
+void *BMIter_AtIndex(struct BMesh *bm, int type, void *data, int index);
+
+#endif
diff --git a/source/blender/bmesh/bmesh_marking.h b/source/blender/bmesh/bmesh_marking.h
new file mode 100644
index 00000000000..1d80b297222
--- /dev/null
+++ b/source/blender/bmesh/bmesh_marking.h
@@ -0,0 +1,52 @@
+#ifndef BM_MARKING_H
+#define BM_MARKING_H
+
+typedef struct BMEditSelection
+{
+ struct BMEditSelection *next, *prev;
+ short type;
+ void *data;
+} BMEditSelection;
+
+/* pinning code */
+void BM_Pin(BMesh *bm, void *element, int pin);
+void BM_Pin_Vert(BMesh *bm, BMVert *v, int pin);
+void BM_Pin_Edge(BMesh *bm, BMEdge *e, int pin);
+void BM_Pin_Face(BMesh *bm, BMFace *f, int pin);
+
+/*geometry hiding code*/
+void BM_Hide(BMesh *bm, void *element, int hide);
+void BM_Hide_Vert(BMesh *bm, BMVert *v, int hide);
+void BM_Hide_Edge(BMesh *bm, BMEdge *e, int hide);
+void BM_Hide_Face(BMesh *bm, BMFace *f, int hide);
+
+/*Selection code*/
+void BM_Select(struct BMesh *bm, void *element, int select);
+/*I don't use this function anywhere, been using BM_TestHFlag instead.
+ Need to decide either to keep it and convert everything over, or
+ chuck it.*/
+int BM_Selected(BMesh *bm, void *element);
+
+void BM_clear_flag_all(BMesh *bm, int flag);
+
+/*individual element select functions, BM_Select is a shortcut for these
+ that automatically detects which one to use*/
+void BM_Select_Vert(struct BMesh *bm, struct BMVert *v, int select);
+void BM_Select_Edge(struct BMesh *bm, struct BMEdge *e, int select);
+void BM_Select_Face(struct BMesh *bm, struct BMFace *f, int select);
+
+void BM_Selectmode_Set(struct BMesh *bm, int selectmode);
+
+/*counts number of elements with flag set*/
+int BM_CountFlag(struct BMesh *bm, int type, int flag, int respectflag);
+
+/*edit selection stuff*/
+void BM_editselection_center(BMesh *bm, float *center, BMEditSelection *ese);
+void BM_editselection_normal(float *normal, BMEditSelection *ese);
+void BM_editselection_plane(BMesh *bm, float *plane, BMEditSelection *ese);
+void BM_remove_selection(BMesh *bm, void *data);
+void BM_store_selection(BMesh *bm, void *data);
+void BM_validate_selections(BMesh *bm);
+void BM_clear_selection_history(BMesh *em);
+
+#endif
diff --git a/source/blender/bmesh/bmesh_operator_api.h b/source/blender/bmesh/bmesh_operator_api.h
new file mode 100644
index 00000000000..9c76bedb5c4
--- /dev/null
+++ b/source/blender/bmesh/bmesh_operator_api.h
@@ -0,0 +1,481 @@
+#ifndef _BMESH_OPERATOR_H
+#define _BMESH_OPERATOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_memarena.h"
+#include "BLI_ghash.h"
+
+#include "BKE_utildefines.h"
+
+#include <stdarg.h>
+
+/*
+operators represent logical, executable mesh modules. all topological
+operations involving a bmesh has to go through them.
+
+operators are nested, as are tool flags, which are private to an operator
+when it's executed. tool flags are allocated in layers, one per operator
+execution, and are used for all internal flagging a tool needs to do.
+
+each operator has a series of "slots," which can be of the following types:
+* simple numerical types
+* arrays of elements (e.g. arrays of faces).
+* hash mappings.
+
+each slot is identified by a slot code, as are each operator.
+operators, and their slots, are defined in bmesh_opdefines.c (with their
+execution functions prototyped in bmesh_operators_private.h), with all their
+operator code and slot codes defined in bmesh_operators.h. see
+bmesh_opdefines.c and the BMOpDefine struct for how to define new operators.
+
+in general, operators are fed arrays of elements, created using either
+BM_HeaderFlag_To_Slot or BM_Flag_To_Slot (or through one of the format
+specifyers in BMO_CallOpf or BMO_InitOpf). Note that multiple element
+types (e.g. faces and edges) can be fed to the same slot array. Operators
+act on this data, and possibly spit out data into output slots.
+
+some notes:
+* operators should never read from header flags (e.g. element->head.flag). for
+ example, if you want an operator to only operate on selected faces, you
+ should use BM_HeaderFlag_To_Slot to put the selected elements into a slot.
+* when you read from an element slot array or mapping, you can either tool-flag
+ all the elements in it, or read them using an iterator APi (which is
+ semantically similar to the iterator api in bmesh_iterators.h).
+*/
+
+struct GHashIterator;
+
+/*slot type arrays are terminated by the last member
+ having a slot type of 0.*/
+#define BMOP_OPSLOT_SENTINEL 0
+#define BMOP_OPSLOT_INT 1
+#define BMOP_OPSLOT_FLT 2
+#define BMOP_OPSLOT_PNT 3
+#define BMOP_OPSLOT_MAT 4
+#define BMOP_OPSLOT_VEC 7
+
+/*after BMOP_OPSLOT_VEC, everything is
+
+ dynamically allocated arrays. we
+ leave a space in the identifiers
+ for future growth.
+
+ */
+//it's very important this remain a power of two
+#define BMOP_OPSLOT_ELEMENT_BUF 8
+#define BMOP_OPSLOT_MAPPING 9
+#define BMOP_OPSLOT_TYPES 10
+
+/*please ignore all these structures, don't touch them in tool code, except
+ for when your defining an operator with BMOpDefine.*/
+
+typedef struct BMOpSlot{
+ int slottype;
+ int len;
+ int flag;
+ int index; /*index within slot array*/
+ union {
+ int i;
+ float f;
+ void *p;
+ float vec[3];
+ void *buf;
+ GHash *ghash;
+ } data;
+} BMOpSlot;
+
+#define BMOP_MAX_SLOTS 16 /*way more than probably needed*/
+
+#ifdef slots
+#undef slots
+#endif
+
+typedef struct BMOperator {
+ int type;
+ int slottype;
+ int needflag;
+ struct BMOpSlot slots[BMOP_MAX_SLOTS];
+ void (*exec)(struct BMesh *bm, struct BMOperator *op);
+ MemArena *arena;
+} BMOperator;
+
+#define MAX_SLOTNAME 32
+
+typedef struct slottype {
+ int type;
+ char name[MAX_SLOTNAME];
+} slottype;
+
+typedef struct BMOpDefine {
+ const char *name;
+ slottype slottypes[BMOP_MAX_SLOTS];
+ void (*exec)(BMesh *bm, BMOperator *op);
+ int flag; /*doesn't do anything right now*/
+} BMOpDefine;
+
+/*------------- Operator API --------------*/
+
+/*data types that use pointers (arrays, etc) should never
+ have it set directly. and never use BMO_Set_Pnt to
+ pass in a list of edges or any arrays, really.*/
+
+void BMO_Init_Op(struct BMOperator *op, const char *opname);
+
+/*executes an operator, pushing and popping a new tool flag
+ layer as appropriate.*/
+void BMO_Exec_Op(struct BMesh *bm, struct BMOperator *op);
+
+/*finishes an operator (though note the operator's tool flag is removed
+ after it finishes executing in BMO_Exec_Op).*/
+void BMO_Finish_Op(struct BMesh *bm, struct BMOperator *op);
+
+
+/*tool flag API. never, ever ever should tool code put junk in
+ header flags (element->head.flag), nor should they use
+ element->head.eflag1/eflag2. instead, use this api to set
+ flags.
+
+ if you need to store a value per element, use a
+ ghash or a mapping slot to do it.*/
+/*flags 15 and 16 (1<<14 and 1<<15) are reserved for bmesh api use*/
+#define BMO_TestFlag(bm, element, flag) (((BMHeader*)(element))->flags[bm->stackdepth-1].f & (flag))
+#define BMO_SetFlag(bm, element, flag) (((BMHeader*)(element))->flags[bm->stackdepth-1].f |= (flag))
+#define BMO_ClearFlag(bm, element, flag) (((BMHeader*)(element))->flags[bm->stackdepth-1].f &= ~(flag))
+
+/*profiling showed a significant amount of time spent in BMO_TestFlag
+void BMO_SetFlag(struct BMesh *bm, void *element, int flag);
+void BMO_ClearFlag(struct BMesh *bm, void *element, int flag);
+int BMO_TestFlag(struct BMesh *bm, void *element, int flag);*/
+
+/*count the number of elements with a specific flag. type
+ can be a bitmask of BM_FACE, BM_EDGE, or BM_FACE.*/
+int BMO_CountFlag(struct BMesh *bm, int flag, int type);
+
+/*---------formatted operator initialization/execution-----------*/
+/*
+ this system is used to execute or initialize an operator,
+ using a formatted-string system.
+
+ for example, BMO_CallOpf(bm, "del geom=%hf context=%d", BM_SELECT, DEL_FACES);
+ . . .will execute the delete operator, feeding in selected faces, deleting them.
+
+ the basic format for the format string is:
+ [operatorname] [slotname]=%[code] [slotname]=%[code]
+
+ as in printf, you pass in one additional argument to the function
+ for every code.
+
+ the formatting codes are:
+ %d - put int in slot
+ %f - put float in slot
+ %p - put pointer in slot
+ %h[f/e/v] - put elements with a header flag in slot.
+ the letters after %h define which element types to use,
+ so e.g. %hf will do faces, %hfe will do faces and edges,
+ %hv will do verts, etc. must pass in at least one
+ element type letter.
+ %f[f/e/v] - same as %h, except it deals with tool flags instead of
+ header flags.
+ %a[f/e/v] - pass all elements (of types specified by f/e/v) to the
+ slot.
+ %e - pass in a single element.
+ %v - pointer to a float vector of length 3.
+ %m[3/4] - matrix, 3/4 refers to the matrix size, 3 or 4. the
+ corrusponding argument must be a pointer to
+ a float matrix.
+ %s - copy a slot from another op, instead of mapping to one
+ argument, it maps to two, a pointer to an operator and
+ a slot name.
+*/
+void BMO_push(BMesh *bm, BMOperator *op);
+void BMO_pop(BMesh *bm);
+
+/*executes an operator*/
+int BMO_CallOpf(BMesh *bm, const char *fmt, ...);
+
+/*initializes, but doesn't execute an operator. this is so you can
+ gain access to the outputs of the operator. note that you have
+ to execute/finitsh (BMO_Exec_Op and BMO_Finish_Op) yourself.*/
+int BMO_InitOpf(BMesh *bm, BMOperator *op, const char *fmt, ...);
+
+/*va_list version, used to implement the above two functions,
+ plus EDBM_CallOpf in bmeshutils.c.*/
+int BMO_VInitOpf(BMesh *bm, BMOperator *op, const char *fmt, va_list vlist);
+
+/*get a point to a slot. this may be removed layer on from the public API.*/
+BMOpSlot *BMO_GetSlot(struct BMOperator *op, const char *slotname);
+
+/*copies the data of a slot from one operator to another. src and dst are the
+ source/destination slot codes, respectively.*/
+void BMO_CopySlot(struct BMOperator *source_op, struct BMOperator *dest_op,
+ const char *src, const char *dst);
+
+/*remove tool flagged elements*/
+void BM_remove_tagged_faces(struct BMesh *bm, int flag);
+void BM_remove_tagged_edges(struct BMesh *bm, int flag);
+void BM_remove_tagged_verts(struct BMesh *bm, int flag);
+
+void BMO_Set_Float(struct BMOperator *op, const char *slotname, float f);
+float BMO_Get_Float(BMOperator *op, const char *slotname);
+void BMO_Set_Int(struct BMOperator *op, const char *slotname, int i);
+int BMO_Get_Int(BMOperator *op, const char *slotname);
+
+/*don't pass in arrays that are supposed to map to elements this way.
+
+ so, e.g. passing in list of floats per element in another slot is bad.
+ passing in, e.g. pointer to an editmesh for the conversion operator is fine
+ though.*/
+void BMO_Set_Pnt(struct BMOperator *op, const char *slotname, void *p);
+void *BMO_Get_Pnt(BMOperator *op, const char *slotname);
+void BMO_Set_Vec(struct BMOperator *op, const char *slotname, float *vec);
+void BMO_Get_Vec(BMOperator *op, const char *slotname, float *vec_out);
+
+/*only supports square mats*/
+/*size must be 3 or 4; this api is meant only for transformation matrices.
+ note that internally the matrix is stored in 4x4 form, and it's safe to
+ call whichever BMO_Get_Mat* function you want.*/
+void BMO_Set_Mat(struct BMOperator *op, const char *slotname, float *mat, int size);
+void BMO_Get_Mat4(struct BMOperator *op, const char *slotname, float mat[4][4]);
+void BMO_Get_Mat3(struct BMOperator *op, const char *slotname, float mat[3][3]);
+
+void BMO_Clear_Flag_All(BMesh *bm, BMOperator *op, int type, int flag);
+
+/*puts every element of type type (which is a bitmask) with tool flag flag,
+ into a slot.*/
+void BMO_Flag_To_Slot(struct BMesh *bm, struct BMOperator *op, const char *slotname, int flag, int type);
+
+/*tool-flags all elements inside an element slot array with flag flag.*/
+void BMO_Flag_Buffer(struct BMesh *bm, struct BMOperator *op, const char *slotname, int flag, int type);
+/*clears tool-flag flag from all elements inside a slot array.*/
+void BMO_Unflag_Buffer(struct BMesh *bm, struct BMOperator *op, const char *slotname, int flag, int type);
+
+/*tool-flags all elements inside an element slot array with flag flag.*/
+void BMO_HeaderFlag_Buffer(struct BMesh *bm, struct BMOperator *op, const char *slotname, int flag, int type);
+/*clears tool-flag flag from all elements inside a slot array.*/
+void BMO_UnHeaderFlag_Buffer(struct BMesh *bm, struct BMOperator *op, const char *slotname, int flag, int type);
+
+/*puts every element of type type (which is a bitmask) with header flag
+ flag, into a slot. note: ignores hidden elements (e.g. elements with
+ header flag BM_HIDDEN set).*/
+void BMO_HeaderFlag_To_Slot(struct BMesh *bm, struct BMOperator *op, const char *slotname, int flag, int type);
+
+/*counts number of elements inside a slot array.*/
+int BMO_CountSlotBuf(struct BMesh *bm, struct BMOperator *op, const char *slotname);
+int BMO_CountSlotMap(struct BMesh *bm, struct BMOperator *op, const char *slotname);
+
+/*Counts the number of edges with tool flag toolflag around
+ v*/
+int BMO_Vert_CountEdgeFlags(BMesh *bm, BMVert *v, int toolflag);
+
+/*inserts a key/value mapping into a mapping slot. note that it copies the
+ value, it doesn't store a reference to it.*/
+//BM_INLINE void BMO_Insert_Mapping(BMesh *bm, BMOperator *op, const char *slotname,
+ //void *element, void *data, int len);
+
+/*inserts a key/float mapping pair into a mapping slot.*/
+//BM_INLINE void BMO_Insert_MapFloat(BMesh *bm, BMOperator *op, const char *slotname,
+ //void *element, float val);
+
+//returns 1 if the specified pointer is in the map.
+//BM_INLINE int BMO_InMap(BMesh *bm, BMOperator *op, const char *slotname, void *element);
+
+/*returns a point to the value of a specific key.*/
+//BM_INLINE void *BMO_Get_MapData(BMesh *bm, BMOperator *op, const char *slotname, void *element);
+
+/*returns the float part of a key/float pair.*/
+//BM_INLINE float BMO_Get_MapFloat(BMesh *bm, BMOperator *op, const char *slotname, void *element);
+
+/*flags all elements in a mapping. note that the mapping must only have
+ bmesh elements in it.*/
+void BMO_Mapping_To_Flag(struct BMesh *bm, struct BMOperator *op,
+ const char *slotname, int flag);
+
+/*pointer versoins of BMO_Get_MapFloat and BMO_Insert_MapFloat.
+
+ do NOT use these for non-operator-api-allocated memory! instead
+ use BMO_Get_MapData and BMO_Insert_Mapping, which copies the data.*/
+//BM_INLINE void BMO_Insert_MapPointer(BMesh *bm, BMOperator *op, const char *slotname,
+ //void *key, void *val);
+//BM_INLINE void *BMO_Get_MapPointer(BMesh *bm, BMOperator *op, const char *slotname,
+ //void *key);
+
+/*this part of the API is used to iterate over element buffer or
+ mapping slots.
+
+ for example, iterating over the faces in a slot is:
+
+ BMOIter oiter;
+ BMFace *f;
+
+ f = BMO_IterNew(&oiter, bm, some_operator, "slotname", BM_FACE);
+ for (; f; f=BMO_IterStep(&oiter)) {
+ /do something with the face
+ }
+
+ another example, iterating over a mapping:
+ BMOIter oiter;
+ void *key;
+ void *val;
+
+ key = BMO_IterNew(&oiter, bm, some_operator, "slotname", 0);
+ for (; key; key=BMO_IterStep(&oiter)) {
+ val = BMO_IterMapVal(&oiter);
+ //do something with the key/val pair
+ //note that val is a pointer to the val data,
+ //whether it's a float, pointer, whatever.
+ //
+ // so to get a pointer, for example, use:
+ // *((void**)BMO_IterMapVal(&oiter));
+ //or something like that.
+ }
+
+ */
+
+/*contents of this structure are private,
+ don't directly access.*/
+typedef struct BMOIter {
+ BMOpSlot *slot;
+ int cur; //for arrays
+ struct GHashIterator giter;
+ void *val;
+ int restrict;
+} BMOIter;
+
+void *BMO_FirstElem(BMOperator *op, const char *slotname);
+
+/*restrictmask restricts the iteration to certain element types
+ (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
+ over an element buffer (not a mapping).*/
+void *BMO_IterNew(BMOIter *iter, BMesh *bm, BMOperator *op,
+ const char *slotname, int restrictmask);
+void *BMO_IterStep(BMOIter *iter);
+
+/*returns a pointer to the key value when iterating over mappings.
+ remember for pointer maps this will be a pointer to a pointer.*/
+void *BMO_IterMapVal(BMOIter *iter);
+
+/*use this for pointer mappings*/
+void *BMO_IterMapValp(BMOIter *iter);
+
+/*use this for float mappings*/
+float BMO_IterMapValf(BMOIter *iter);
+
+#define BMO_ITER(ele, iter, bm, op, slotname, restrict) \
+ ele = BMO_IterNew(iter, bm, op, slotname, restrict); \
+ for ( ; ele; ele=BMO_IterStep(iter))
+
+/******************* Inlined Functions********************/
+typedef void (*opexec)(struct BMesh *bm, struct BMOperator *op);
+
+/*mappings map elements to data, which
+ follows the mapping struct in memory.*/
+typedef struct element_mapping {
+ BMHeader *element;
+ int len;
+} element_mapping;
+
+extern const int BMOP_OPSLOT_TYPEINFO[];
+
+BM_INLINE void BMO_Insert_Mapping(BMesh *UNUSED(bm), BMOperator *op, const char *slotname,
+ void *element, void *data, int len) {
+ element_mapping *mapping;
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+
+ /*sanity check*/
+ if (slot->slottype != BMOP_OPSLOT_MAPPING) return;
+
+ mapping = (element_mapping*) BLI_memarena_alloc(op->arena, sizeof(*mapping) + len);
+
+ mapping->element = (BMHeader*) element;
+ mapping->len = len;
+ memcpy(mapping+1, data, len);
+
+ if (!slot->data.ghash) {
+ slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash,
+ BLI_ghashutil_ptrcmp, "bmesh op");
+ }
+
+ BLI_ghash_insert(slot->data.ghash, element, mapping);
+}
+
+BM_INLINE void BMO_Insert_MapInt(BMesh *bm, BMOperator *op, const char *slotname,
+ void *element, int val)
+{
+ BMO_Insert_Mapping(bm, op, slotname, element, &val, sizeof(int));
+}
+
+BM_INLINE void BMO_Insert_MapFloat(BMesh *bm, BMOperator *op, const char *slotname,
+ void *element, float val)
+{
+ BMO_Insert_Mapping(bm, op, slotname, element, &val, sizeof(float));
+}
+
+BM_INLINE void BMO_Insert_MapPointer(BMesh *bm, BMOperator *op, const char *slotname,
+ void *element, void *val)
+{
+ BMO_Insert_Mapping(bm, op, slotname, element, &val, sizeof(void*));
+}
+
+BM_INLINE int BMO_InMap(BMesh *UNUSED(bm), BMOperator *op, const char *slotname, void *element)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+
+ /*sanity check*/
+ if (slot->slottype != BMOP_OPSLOT_MAPPING) return 0;
+ if (!slot->data.ghash) return 0;
+
+ return BLI_ghash_haskey(slot->data.ghash, element);
+}
+
+BM_INLINE void *BMO_Get_MapData(BMesh *UNUSED(bm), BMOperator *op, const char *slotname,
+ void *element)
+{
+ element_mapping *mapping;
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+
+ /*sanity check*/
+ if (slot->slottype != BMOP_OPSLOT_MAPPING) return NULL;
+ if (!slot->data.ghash) return NULL;
+
+ mapping = (element_mapping*) BLI_ghash_lookup(slot->data.ghash, element);
+
+ if (!mapping) return NULL;
+
+ return mapping + 1;
+}
+
+BM_INLINE float BMO_Get_MapFloat(BMesh *bm, BMOperator *op, const char *slotname,
+ void *element)
+{
+ float *val = (float*) BMO_Get_MapData(bm, op, slotname, element);
+ if (val) return *val;
+
+ return 0.0f;
+}
+
+BM_INLINE int BMO_Get_MapInt(BMesh *bm, BMOperator *op, const char *slotname,
+ void *element)
+{
+ int *val = (int*) BMO_Get_MapData(bm, op, slotname, element);
+ if (val) return *val;
+
+ return 0;
+}
+
+BM_INLINE void *BMO_Get_MapPointer(BMesh *bm, BMOperator *op, const char *slotname,
+ void *element)
+{
+ void **val = (void**) BMO_Get_MapData(bm, op, slotname, element);
+ if (val) return *val;
+
+ return NULL;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BMESH_OPERATOR_H */
diff --git a/source/blender/bmesh/bmesh_operators.h b/source/blender/bmesh/bmesh_operators.h
new file mode 100644
index 00000000000..620d7576141
--- /dev/null
+++ b/source/blender/bmesh/bmesh_operators.h
@@ -0,0 +1,93 @@
+#ifndef BM_OPERATORS_H
+#define BM_OPERATORS_H
+
+/*--------defines/enumerations for specific operators-------*/
+
+/*del operator "context" slot values*/
+enum {
+ DEL_VERTS = 1,
+ DEL_EDGES,
+ DEL_ONLYFACES,
+ DEL_EDGESFACES,
+ DEL_FACES,
+ DEL_ALL ,
+ DEL_ONLYTAGGED,
+};
+
+/*quad innervert values*/
+enum {
+ SUBD_INNERVERT,
+ SUBD_PATH,
+ SUBD_FAN,
+ SUBD_STRAIGHT_CUT,
+};
+
+/* similar face selection slot values */
+enum {
+ SIMFACE_MATERIAL = 201,
+ SIMFACE_IMAGE,
+ SIMFACE_AREA,
+ SIMFACE_PERIMETER,
+ SIMFACE_NORMAL,
+ SIMFACE_COPLANAR,
+};
+
+/* similar edge selection slot values */
+enum {
+ SIMEDGE_LENGTH = 101,
+ SIMEDGE_DIR,
+ SIMEDGE_FACE,
+ SIMEDGE_FACE_ANGLE,
+ SIMEDGE_CREASE,
+ SIMEDGE_SEAM,
+ SIMEDGE_SHARP,
+};
+
+/* similar vertex selection slot values */
+enum {
+ SIMVERT_NORMAL = 0,
+ SIMVERT_FACE,
+ SIMVERT_VGROUP,
+};
+
+enum {
+ OPUVC_AXIS_X = 1,
+ OPUVC_AXIS_Y
+};
+
+enum {
+ DIRECTION_CW = 1,
+ DIRECTION_CCW
+};
+
+/* vertex path selection values */
+enum {
+ VPATH_SELECT_EDGE_LENGTH = 0,
+ VPATH_SELECT_TOPOLOGICAL
+};
+
+extern BMOpDefine *opdefines[];
+extern int bmesh_total_ops;
+
+/*------specific operator helper functions-------*/
+
+/*executes the duplicate operation, feeding elements of
+ type flag etypeflag and header flag flag to it. note,
+ to get more useful information (such as the mapping from
+ original to new elements) you should run the dupe op manually.*/
+struct Object;
+struct EditMesh;
+
+void BMOP_DupeFromFlag(struct BMesh *bm, int etypeflag, int flag);
+void BM_esubdivideflag(struct Object *obedit, BMesh *bm, int flag, float smooth,
+ float fractal, int beauty, int numcuts, int seltype,
+ int cornertype, int singleedge, int gridfill);
+void BM_extrudefaceflag(BMesh *bm, int flag);
+
+/*this next one return 1 if they did anything, or zero otherwise.
+ they're kindof a hackish way to integrate with fkey, until
+ such time as fkey is completely bmeshafied.*/
+/*this doesn't display errors to the user, btw*/
+int BM_ConnectVerts(struct EditMesh *em, int flag);
+
+#endif
diff --git a/source/blender/bmesh/bmesh_queries.h b/source/blender/bmesh/bmesh_queries.h
new file mode 100644
index 00000000000..4f185d8725c
--- /dev/null
+++ b/source/blender/bmesh/bmesh_queries.h
@@ -0,0 +1,89 @@
+#ifndef BMESH_QUERIES_H
+#define BMESH_QUERIES_H
+#include <stdio.h>
+
+/*Queries*/
+
+/*get the area of face f*/
+float BM_face_area(BMFace *f);
+
+/*counts number of elements of type type are in the mesh.*/
+int BM_Count_Element(struct BMesh *bm, int type);
+
+/*returns true if v is in f*/
+int BM_Vert_In_Face(struct BMFace *f, struct BMVert *v);
+
+// int BM_Verts_In_Face(struct BMFace *f, struct BMVert **varr, int len);
+int BM_Verts_In_Face(struct BMesh *bm, struct BMFace *f, struct BMVert **varr, int len);
+
+int BM_Edge_In_Face(struct BMFace *f, struct BMEdge *e);
+
+int BM_Vert_In_Edge(struct BMEdge *e, struct BMVert *v);
+
+/*get opposing vert from v in edge e.*/
+struct BMVert *BM_OtherEdgeVert(struct BMEdge *e, struct BMVert *v);
+
+/*finds other loop that shares v with e's loop in f.*/
+struct BMLoop *BM_OtherFaceLoop(BMEdge *e, BMFace *f, BMVert *v);
+
+//#define BM_OtherEdgeVert(e, v) (v==e->v1?e->v2:e->v1)
+
+/*returns the edge existing between v1 and v2, or NULL if there isn't one.*/
+struct BMEdge *BM_Edge_Exist(struct BMVert *v1, struct BMVert *v2);
+
+
+/*returns number of edges aroudn a vert*/
+int BM_Vert_EdgeCount(struct BMVert *v);
+
+/*returns number of faces around an edge*/
+int BM_Edge_FaceCount(struct BMEdge *e);
+
+/*returns number of faces around a vert.*/
+int BM_Vert_FaceCount(struct BMVert *v);
+
+
+/*returns true if v is a wire vert*/
+int BM_Wire_Vert(struct BMesh *bm, struct BMVert *v);
+
+/*returns true if e is a wire edge*/
+int BM_Wire_Edge(struct BMesh *bm, struct BMEdge *e);
+
+/*returns true if v is part of a non-manifold edge in the mesh,
+ I believe this includes if it's part of both a wire edge and
+ a face.*/
+int BM_Nonmanifold_Vert(struct BMesh *bm, struct BMVert *v);
+
+/*returns true if e is shared by more then two faces.*/
+int BM_Nonmanifold_Edge(struct BMesh *bm, struct BMEdge *e);
+
+/*returns true if e is a boundary edge, e.g. has only 1 face bordering it.*/
+int BM_Boundary_Edge(struct BMEdge *e);
+
+
+/*returns angle of two faces surrounding an edge. note there must be
+ exactly two faces sharing the edge.*/
+float BM_Face_Angle(struct BMesh *bm, struct BMEdge *e);
+
+/*checks overlapping of existing faces with the verts in varr.*/
+int BM_Exist_Face_Overlaps(struct BMesh *bm, struct BMVert **varr, int len, struct BMFace **existface);
+
+/*checks if a face defined by varr already exists.*/
+int BM_Face_Exists(BMesh *bm, BMVert **varr, int len, BMFace **existface);
+
+
+/*returns number of edges f1 and f2 share.*/
+int BM_Face_Sharededges(struct BMFace *f1, struct BMFace *f2);
+
+/*returns number of faces e1 and e2 share.*/
+int BM_Edge_Share_Faces(struct BMEdge *e1, struct BMEdge *e2);
+
+/*checks if a face is valid in the data structure*/
+int BM_Validate_Face(BMesh *bm, BMFace *face, FILE *err);
+
+/*each pair of loops defines a new edge, a split. this function goes
+ through and sets pairs that are geometrically invalid to null. a
+ split is invalid, if it forms a concave angle or it intersects other
+ edges in the face.*/
+void BM_LegalSplits(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len);
+
+#endif
diff --git a/source/blender/bmesh/bmesh_walkers.h b/source/blender/bmesh/bmesh_walkers.h
new file mode 100644
index 00000000000..3d6891c1c39
--- /dev/null
+++ b/source/blender/bmesh/bmesh_walkers.h
@@ -0,0 +1,73 @@
+#ifndef BM_WALKERS_H
+#define BM_WALKERS_H
+
+#include "BLI_ghash.h"
+
+/*
+ NOTE: do NOT modify topology while walking a mesh!
+*/
+
+/*Walkers*/
+typedef struct BMWalker {
+ BLI_mempool *stack;
+ BMesh *bm;
+ void *currentstate;
+ void (*begin) (struct BMWalker *walker, void *start);
+ void *(*yield)(struct BMWalker *walker);
+ void *(*step) (struct BMWalker *walker);
+ int restrictflag;
+ GHash *visithash;
+ int flag;
+} BMWalker;
+
+/*initialize a walker. searchmask restricts some (not all) walkers to
+ elements with a specific tool flag set. flags is specific to each walker.*/
+void BMW_Init(struct BMWalker *walker, BMesh *bm, int type, int searchmask, int flags);
+void *BMW_Begin(BMWalker *walker, void *start);
+void *BMW_Step(struct BMWalker *walker);
+void BMW_End(struct BMWalker *walker);
+
+/*
+example of usage, walking over an island of tool flagged faces:
+
+BMWalker walker;
+BMFace *f;
+
+BMW_Init(&walker, bm, BMW_ISLAND, SOME_OP_FLAG);
+f = BMW_Begin(&walker, some_start_face);
+for (; f; f=BMW_Step(&walker)) {
+ //do something with f
+}
+BMW_End(&walker);
+*/
+
+enum {
+ /*walk over connected geometry. can restrict to a search flag,
+ or not, it's optional.
+
+ takes a vert as an arugment, and spits out edges, restrict flag acts
+ on the edges as well.*/
+ BMW_SHELL,
+ /*walk over an edge loop. search flag doesn't do anything.*/
+ BMW_LOOP,
+ BMW_FACELOOP,
+ BMW_EDGERING,
+ /*#define BMW_RING 2*/
+ //walk over uv islands; takes a loop as input. restrict flag
+ //restricts the walking to loops whose vert has restrict flag set as a
+ //tool flag.
+ //
+ //the flag parameter to BMW_Init maps to a loop customdata layer index.
+ BMW_LOOPDATA_ISLAND,
+ /*walk over an island of flagged faces. note, that this doesn't work on
+ non-manifold geometry. it might be better to rewrite this to extract
+ boundary info from the island walker, rather then directly walking
+ over the boundary. raises an error if it encouters nonmanifold
+ geometry.*/
+ BMW_ISLANDBOUND,
+ /*walk over all faces in an island of tool flagged faces.*/
+ BMW_ISLAND,
+ BMW_MAXWALKERS,
+};
+
+#endif \ No newline at end of file
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/bmesh/editmesh_tools.c
index 4a0b1cb9e5e..4250a682866 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/bmesh/editmesh_tools.c
@@ -1,4 +1,5 @@
- /* $Id$
+/**
+ * $Id:
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
@@ -14,9 +15,9 @@
*
* 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.
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * The Original Code is Copyright (C) 2004 by Blender Foundation.
+ * The Original Code is Copyright (C) 2004 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
@@ -35,70 +36,85 @@ editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise
#include <stdlib.h>
#include <string.h>
#include <math.h>
-#include <float.h>
-#include "BLO_sys_types.h" // for intptr_t support
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
#include "DNA_key_types.h"
-#include "MEM_guardedalloc.h"
-
-#include "RNA_define.h"
-#include "RNA_access.h"
-
#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BLI_utildefines.h"
#include "BLI_editVert.h"
#include "BLI_rand.h"
#include "BLI_ghash.h"
#include "BLI_linklist.h"
#include "BLI_heap.h"
-#include "BLI_scanfill.h"
-#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_customdata.h"
#include "BKE_global.h"
-#include "BKE_key.h"
+#include "BKE_library.h"
#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
#include "BKE_bmesh.h"
-#include "BKE_report.h"
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
-#include "WM_api.h"
-#include "WM_types.h"
+#include "BIF_cursors.h"
+#include "BIF_editmesh.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_resources.h"
+#include "BIF_toolbox.h"
+#include "BIF_transform.h"
+#include "transform.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
-#include "ED_mesh.h"
-#include "ED_screen.h"
-#include "ED_transform.h"
-#include "ED_view3d.h"
-#include "ED_object.h"
+#include "BDR_drawobject.h"
+#include "BDR_editobject.h"
+#include "BSE_view.h"
+#include "BSE_edit.h"
-#include "mesh_intern.h"
+#include "blendef.h"
+#include "multires.h"
+#include "mydevice.h"
-/* XXX */
-static void waitcursor(int UNUSED(val)) {}
-#define add_numbut(a, b, c, d, e, f, g) {}
+#include "editmesh.h"
-/* XXX */
+#include "MTC_vectorops.h"
-/* RNA corner cut enum property - used in multiple files for tools
- * that need this property for esubdivideflag() */
-EnumPropertyItem corner_type_items[] = {
- {SUBDIV_CORNER_PATH, "PATH", 0, "Path", ""},
- {SUBDIV_CORNER_INNERVERT, "INNER_VERTEX", 0, "Inner Vertex", ""},
- {SUBDIV_CORNER_FAN, "FAN", 0, "Fan", ""},
- {0, NULL, 0, NULL, NULL}};
+#include "PIL_time.h"
+#include "BLO_sys_types.h" // for intptr_t support
/* local prototypes ---------------*/
-static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa);
-int EdgeLoopDelete(EditMesh *em, wmOperator *op);
+void bevel_menu(void);
+static void free_tagged_edges_faces(EditEdge *eed, EditFace *efa);
/********* qsort routines *********/
@@ -126,7 +142,7 @@ struct facesort {
static int vergface(const void *v1, const void *v2)
{
const struct facesort *x1=v1, *x2=v2;
-
+
if( x1->x > x2->x ) return 1;
else if( x1->x < x2->x) return -1;
return 0;
@@ -135,11 +151,14 @@ static int vergface(const void *v1, const void *v2)
/* *********************************** */
-static void convert_to_triface(EditMesh *em, int direction)
+void convert_to_triface(int direction)
{
+ EditMesh *em = G.editMesh;
EditFace *efa, *efan, *next;
float fac;
-
+
+ if(multires_test()) return;
+
efa= em->faces.last;
while(efa) {
next= efa->prev;
@@ -149,31 +168,36 @@ static void convert_to_triface(EditMesh *em, int direction)
fac= len_v3v3(efa->v1->co, efa->v3->co) - len_v3v3(efa->v2->co, efa->v4->co);
/* this makes sure exact squares get split different in both cases */
if( (direction==0 && fac<FLT_EPSILON) || (direction && fac>0.0f) ) {
- efan= EM_face_from_faces(em, efa, NULL, 0, 1, 2, -1);
+ efan= EM_face_from_faces(efa, NULL, 0, 1, 2, -1);
if(efa->f & SELECT) EM_select_face(efan, 1);
- efan= EM_face_from_faces(em, efa, NULL, 0, 2, 3, -1);
+ efan= EM_face_from_faces(efa, NULL, 0, 2, 3, -1);
if(efa->f & SELECT) EM_select_face(efan, 1);
}
else {
- efan= EM_face_from_faces(em, efa, NULL, 0, 1, 3, -1);
+ efan= EM_face_from_faces(efa, NULL, 0, 1, 3, -1);
if(efa->f & SELECT) EM_select_face(efan, 1);
- efan= EM_face_from_faces(em, efa, NULL, 1, 2, 3, -1);
+ efan= EM_face_from_faces(efa, NULL, 1, 2, 3, -1);
if(efa->f & SELECT) EM_select_face(efan, 1);
}
-
+
BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
+ free_editface(efa);
}
}
efa= next;
}
+
+ EM_fgon_flags(); // redo flags and indices for fgons
- EM_fgon_flags(em); // redo flags and indices for fgons
-
-
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+ BIF_undo_push("Convert Quads to Triangles");
+
}
-int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /* return amount */
+int removedoublesflag(short flag, short automerge, float limit) /* return amount */
{
/*
flag - Test with vert->flags
@@ -181,7 +205,8 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
Used for "Auto Weld" mode. warning.
limit - Quick manhattan distance between verts.
*/
-
+
+ EditMesh *em = G.editMesh;
/* all verts with (flag & 'flag') are being evaluated */
EditVert *eve, *v1, *nextve;
EditEdge *eed, *e1, *nexted;
@@ -189,8 +214,10 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
xvertsort *sortblock, *sb, *sb1;
struct facesort *vlsortblock, *vsb, *vsb1;
int a, b, test, amount;
+
+ if(multires_test()) return 0;
-
+
/* flag 128 is cleared, count */
/* Normal non weld operation */
@@ -216,9 +243,9 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
}
qsort(sortblock, amount, sizeof(xvertsort), vergxco);
-
+
/* test for doubles */
- sb= sortblock;
+ sb= sortblock;
if (automerge) {
for(a=0; a<amount; a++, sb++) {
eve= sb->v1;
@@ -226,12 +253,12 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
sb1= sb+1;
for(b=a+1; b<amount && (eve->f & 128)==0; b++, sb1++) {
if(sb1->x - sb->x > limit) break;
-
+
/* when automarge, only allow unselected->selected */
v1= sb1->v1;
if( (v1->f & 128)==0 ) {
if ((eve->f & flag)==0 && (v1->f & flag)==1) {
- if( (float)fabs(v1->co[0]-eve->co[0])<=limit &&
+ if( (float)fabs(v1->co[0]-eve->co[0])<=limit &&
(float)fabs(v1->co[1]-eve->co[1])<=limit &&
(float)fabs(v1->co[2]-eve->co[2])<=limit)
{ /* unique bit */
@@ -239,7 +266,7 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
eve->tmp.v = v1;
}
} else if( (eve->f & flag)==1 && (v1->f & flag)==0 ) {
- if( (float)fabs(v1->co[0]-eve->co[0])<=limit &&
+ if( (float)fabs(v1->co[0]-eve->co[0])<=limit &&
(float)fabs(v1->co[1]-eve->co[1])<=limit &&
(float)fabs(v1->co[2]-eve->co[2])<=limit)
{ /* unique bit */
@@ -260,10 +287,10 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
/* first test: simpel dist */
if(sb1->x - sb->x > limit) break;
v1= sb1->v1;
-
+
/* second test: is vertex allowed */
if( (v1->f & 128)==0 ) {
- if( (float)fabs(v1->co[0]-eve->co[0])<=limit &&
+ if( (float)fabs(v1->co[0]-eve->co[0])<=limit &&
(float)fabs(v1->co[1]-eve->co[1])<=limit &&
(float)fabs(v1->co[2]-eve->co[2])<=limit)
{
@@ -276,12 +303,12 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
}
}
MEM_freeN(sortblock);
-
+
if (!automerge)
for(eve = em->verts.first; eve; eve=eve->next)
if((eve->f & flag) && (eve->f & 128))
- EM_data_interp_from_verts(em, eve, eve->tmp.v, eve->tmp.v, 0.5f);
-
+ EM_data_interp_from_verts(eve, eve->tmp.v, eve->tmp.v, 0.5f);
+
/* test edges and insert again */
eed= em->edges.first;
while(eed) {
@@ -294,18 +321,18 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
if(eed->f2==0) {
if( (eed->v1->f & 128) || (eed->v2->f & 128) ) {
- remedge(em, eed);
+ remedge(eed);
if(eed->v1->f & 128) eed->v1 = eed->v1->tmp.v;
if(eed->v2->f & 128) eed->v2 = eed->v2->tmp.v;
- e1= addedgelist(em, eed->v1, eed->v2, eed);
+ e1= addedgelist(eed->v1, eed->v2, eed);
if(e1) {
e1->f2= 1;
if(eed->f & SELECT)
e1->f |= SELECT;
}
- if(e1!=eed) free_editedge(em, eed);
+ if(e1!=eed) free_editedge(eed);
}
}
eed= nexted;
@@ -320,7 +347,7 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
else if(efa->v2->f & 128) efa->f1= 1;
else if(efa->v3->f & 128) efa->f1= 1;
else if(efa->v4 && (efa->v4->f & 128)) efa->f1= 1;
-
+
if(efa->f1==1) amount++;
efa= efa->next;
}
@@ -330,12 +357,12 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
while(efa) {
nextvl= efa->next;
if(efa->f1==1) {
-
+
if(efa->v1->f & 128) efa->v1= efa->v1->tmp.v;
if(efa->v2->f & 128) efa->v2= efa->v2->tmp.v;
if(efa->v3->f & 128) efa->v3= efa->v3->tmp.v;
if(efa->v4 && (efa->v4->f & 128)) efa->v4= efa->v4->tmp.v;
-
+
test= 0;
if(efa->v1==efa->v2) test+=1;
if(efa->v2==efa->v3) test+=2;
@@ -343,7 +370,7 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
if(efa->v4==efa->v1) test+=8;
if(efa->v3==efa->v4) test+=16;
if(efa->v2==efa->v4) test+=32;
-
+
if(test) {
if(efa->v4) {
if(test==1 || test==2) {
@@ -351,7 +378,7 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
efa->v3= efa->v4;
efa->v4= 0;
- EM_data_interp_from_faces(em, efa, NULL, efa, 0, 2, 3, 3);
+ EM_data_interp_from_faces(efa, NULL, efa, 0, 2, 3, 3);
test= 0;
}
@@ -361,28 +388,28 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
}
else {
BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
+ free_editface(efa);
amount--;
}
}
else {
BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
+ free_editface(efa);
amount--;
}
}
-
+
if(test==0) {
/* set edge pointers */
- efa->e1= findedgelist(em, efa->v1, efa->v2);
- efa->e2= findedgelist(em, efa->v2, efa->v3);
+ efa->e1= findedgelist(efa->v1, efa->v2);
+ efa->e2= findedgelist(efa->v2, efa->v3);
if(efa->v4==0) {
- efa->e3= findedgelist(em, efa->v3, efa->v1);
+ efa->e3= findedgelist(efa->v3, efa->v1);
efa->e4= 0;
}
else {
- efa->e3= findedgelist(em, efa->v3, efa->v4);
- efa->e4= findedgelist(em, efa->v4, efa->v1);
+ efa->e3= findedgelist(efa->v3, efa->v4);
+ efa->e4= findedgelist(efa->v4, efa->v1);
}
}
}
@@ -416,9 +443,9 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
}
efa= efa->next;
}
-
+
qsort(vlsortblock, amount, sizeof(struct facesort), vergface);
-
+
vsb= vlsortblock;
for(a=0; a<amount; a++) {
efa= vsb->efa;
@@ -426,36 +453,36 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
vsb1= vsb+1;
for(b=a+1; b<amount; b++) {
-
+
/* first test: same pointer? */
if(vsb->x != vsb1->x) break;
-
+
/* second test: is test permitted? */
efa= vsb1->efa;
if( (efa->f1 & 128)==0 ) {
if( compareface(efa, vsb->efa)) efa->f1 |= 128;
-
+
}
vsb1++;
}
}
vsb++;
}
-
+
MEM_freeN(vlsortblock);
-
+
/* remove double faces */
efa= (struct EditFace *)em->faces.first;
while(efa) {
nextvl= efa->next;
if(efa->f1 & 128) {
BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
+ free_editface(efa);
}
efa= nextvl;
}
}
-
+
/* remove double vertices */
a= 0;
eve= (struct EditVert *)em->verts.first;
@@ -465,136 +492,83 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
if(eve->f & 128) {
a++;
BLI_remlink(&em->verts, eve);
- free_editvert(em, eve);
+ free_editvert(eve);
}
}
eve= nextve;
}
- return a; /* amount */
-}
-
-static int removedoublesflag_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- int count = removedoublesflag(em,1,0,RNA_float_get(op->ptr, "limit"));
-
- if(count) {
- recalc_editnormals(em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+#ifdef WITH_VERSE
+ if((a>0) && (G.editMesh->vnode)) {
+ sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode);
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
}
+#endif
- BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s.", count, (count==1)?"ex":"ices");
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_remove_doubles(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name= "Remove Doubles";
- ot->description= "Remove duplicate vertices";
- ot->idname= "MESH_OT_remove_doubles";
-
- /* api callbacks */
- ot->exec= removedoublesflag_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- prop= RNA_def_float(ot->srna, "limit", 0.0001f, 0.000001f, 50.0f, "Merge Threshold", "Minimum distance between merged verts", 0.00001f, 2.0f);
- RNA_def_property_ui_range(prop, 0.000001f, 50.0f, 0.001, 5);
+ return a; /* amount */
}
-// XXX is this needed?
/* called from buttons */
-static void xsortvert_flag__doSetX(void *userData, EditVert *UNUSED(eve), int x, int UNUSED(y), int index)
+static void xsortvert_flag__doSetX(void *userData, EditVert *eve, int x, int y, int index)
{
xvertsort *sortblock = userData;
sortblock[index].x = x;
}
-
-/* all verts with (flag & 'flag') are sorted */
-static void xsortvert_flag(bContext *C, int flag)
+void xsortvert_flag(int flag)
{
- ViewContext vc;
+ EditMesh *em = G.editMesh;
+ /* all verts with (flag & 'flag') are sorted */
EditVert *eve;
xvertsort *sortblock;
ListBase tbase;
- int i, amount;
-
- em_setup_viewcontext(C, &vc);
-
- amount = BLI_countlist(&vc.em->verts);
+ int i, amount = BLI_countlist(&em->verts);
+
+ if(multires_test()) return;
+
sortblock = MEM_callocN(sizeof(xvertsort)*amount,"xsort");
- for (i=0,eve= vc.em->verts.first; eve; i++,eve=eve->next)
+ for (i=0,eve=em->verts.first; eve; i++,eve=eve->next)
if(eve->f & flag)
sortblock[i].v1 = eve;
-
- ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
- mesh_foreachScreenVert(&vc, xsortvert_flag__doSetX, sortblock, 0);
-
+ mesh_foreachScreenVert(xsortvert_flag__doSetX, sortblock, 0);
qsort(sortblock, amount, sizeof(xvertsort), vergxco);
-
+
/* make temporal listbase */
tbase.first= tbase.last= 0;
for (i=0; i<amount; i++) {
eve = sortblock[i].v1;
if (eve) {
- BLI_remlink(&vc.em->verts, eve);
+ BLI_remlink(&em->verts, eve);
BLI_addtail(&tbase, eve);
}
}
-
- BLI_movelisttolist(&vc.em->verts, &tbase);
-
+
+ addlisttolist(&em->verts, &tbase);
+
MEM_freeN(sortblock);
-}
-
-static int mesh_vertices_sort_exec(bContext *C, wmOperator *UNUSED(op))
-{
- xsortvert_flag(C, SELECT);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_vertices_sort(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Vertex Sort";
- ot->description= "Sort vertex order";
- ot->idname= "MESH_OT_vertices_sort";
-
- /* api callbacks */
- ot->exec= mesh_vertices_sort_exec;
-
- ot->poll= EM_view3d_poll; /* uses view relative X axis to sort verts */
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ BIF_undo_push("Xsort");
+
}
-
/* called from buttons */
-static void hashvert_flag(EditMesh *em, int flag)
+void hashvert_flag(int flag)
{
/* switch vertex order using hash table */
+ EditMesh *em = G.editMesh;
EditVert *eve;
struct xvertsort *sortblock, *sb, onth, *newsort;
ListBase tbase;
int amount, a, b;
-
+
+ if(multires_test()) return;
+
/* count */
eve= em->verts.first;
amount= 0;
@@ -603,7 +577,7 @@ static void hashvert_flag(EditMesh *em, int flag)
eve= eve->next;
}
if(amount==0) return;
-
+
/* allocate memory */
sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*amount,"sortremovedoub");
eve= em->verts.first;
@@ -616,7 +590,7 @@ static void hashvert_flag(EditMesh *em, int flag)
}
BLI_srand(1);
-
+
sb= sortblock;
for(a=0; a<amount; a++, sb++) {
b= (int)(amount*BLI_drand());
@@ -637,349 +611,202 @@ static void hashvert_flag(EditMesh *em, int flag)
BLI_addtail(&tbase, eve);
sb++;
}
-
- BLI_movelisttolist(&em->verts, &tbase);
-
+
+ addlisttolist(&em->verts, &tbase);
+
MEM_freeN(sortblock);
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+ BIF_undo_push("Hash");
}
-static int mesh_vertices_randomize_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
- hashvert_flag(em, SELECT);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_vertices_randomize(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Vertex Randomize";
- ot->description= "Randomize vertex order";
- ot->idname= "MESH_OT_vertices_randomize";
-
- /* api callbacks */
- ot->exec= mesh_vertices_randomize_exec;
-
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-
/* generic extern called extruder */
-static void extrude_mesh(Object *obedit, EditMesh *em, wmOperator *op, short type)
+void extrude_mesh(void)
{
float nor[3]= {0.0, 0.0, 0.0};
- short transmode= 0;
-
- if(type<1) return;
+ short nr, transmode= 0;
- if(type==1) transmode= extrudeflag(obedit, em, SELECT, nor, 0);
- else if(type==4) transmode= extrudeflag_verts_indiv(em, SELECT, nor);
- else if(type==3) transmode= extrudeflag_edges_indiv(em, SELECT, nor);
- else transmode= extrudeflag_face_indiv(em, SELECT, nor);
-
- EM_stats_update(em);
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ if(G.totvertsel==0) nr= 0;
+ else if(G.totvertsel==1) nr= 4;
+ else if(G.totedgesel==0) nr= 4;
+ else if(G.totfacesel==0)
+ nr= pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4");
+ else if(G.totfacesel==1)
+ nr= pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4");
+ else
+ nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
+ }
+ else if(G.scene->selectmode & SCE_SELECT_EDGE) {
+ if (G.totedgesel==0) nr = 0;
+ else if (G.totedgesel==1) nr = 3;
+ else if(G.totfacesel==0) nr = 3;
+ else if(G.totfacesel==1)
+ nr= pupmenu("Extrude %t|Region %x1|Only Edges%x3");
+ else
+ nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
+ }
+ else {
+ if (G.totfacesel == 0) nr = 0;
+ else if (G.totfacesel == 1) nr = 1;
+ else
+ nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
+ }
+
+ if(nr<1) return;
+ if(nr==1) transmode= extrudeflag(SELECT, nor);
+ else if(nr==4) transmode= extrudeflag_verts_indiv(SELECT, nor);
+ else if(nr==3) transmode= extrudeflag_edges_indiv(SELECT, nor);
+ else transmode= extrudeflag_face_indiv(SELECT, nor);
+
if(transmode==0) {
- BKE_report(op->reports, RPT_WARNING, "Not a valid selection for extrude");
+ error("No valid selection");
}
else {
- EM_fgon_flags(em);
-
- /* We need to force immediate calculation here because
+ EM_fgon_flags();
+ countall();
+
+ /* We need to force immediate calculation here because
* transform may use derived objects (which are now stale).
*
* This shouldn't be necessary, derived queries should be
* automatically building this data if invalid. Or something.
*/
- DAG_id_tag_update(obedit->data, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ object_handle_update(G.obedit);
/* individual faces? */
-// BIF_TransformSetUndo("Extrude");
- if(type==2) {
-// initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR);
-// Transform();
+ BIF_TransformSetUndo("Extrude");
+ if(nr==2) {
+ initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR);
+ Transform();
}
else {
-// initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR);
+ initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR);
if(transmode=='n') {
- mul_m4_v3(obedit->obmat, nor);
- sub_v3_v3(nor, obedit->obmat[3]);
-// BIF_setSingleAxisConstraint(nor, "along normal");
+ mul_m4_v3(G.obedit->obmat, nor);
+ sub_v3_v3v3(nor, nor, G.obedit->obmat[3]);
+ BIF_setSingleAxisConstraint(nor, "along normal");
}
-// Transform();
+ Transform();
}
}
}
-// XXX should be a menu item
-static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+void split_mesh(void)
{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- extrude_mesh(obedit, em, op, RNA_int_get(op->ptr, "type"));
-
- BKE_mesh_end_editmesh(obedit->data, em);
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-/* extrude without transform */
-static int mesh_extrude_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
-
- extrude_mesh(obedit, em, op, RNA_int_get(op->ptr, "type"));
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
+ TEST_EDITMESH
+ if(multires_test()) return;
-static EnumPropertyItem extrude_items[] = {
- {1, "REGION", 0, "Region", ""},
- {2, "FACES", 0, "Individual Faces", ""},
- {3, "EDGES", 0, "Only Edges", ""},
- {4, "VERTS", 0, "Only Vertices", ""},
- {0, NULL, 0, NULL, NULL}};
+ if(okee(" Split ")==0) return;
-
-static EnumPropertyItem *extrude_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
-{
- EnumPropertyItem *item= NULL;
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em;
-
- int totitem= 0;
-
- if(!obedit)
- return extrude_items;
-
- em = BKE_mesh_get_editmesh(obedit->data);
-
- EM_stats_update(em);
-
- if(em->selectmode & SCE_SELECT_VERTEX) {
- if(em->totvertsel==0) {}
- else if(em->totvertsel==1) { RNA_enum_item_add(&item, &totitem, &extrude_items[3]); }
- else if(em->totedgesel==0) { RNA_enum_item_add(&item, &totitem, &extrude_items[3]); }
- else if(em->totfacesel==0) {
- RNA_enum_item_add(&item, &totitem, &extrude_items[2]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[3]);
- }
- else if(em->totfacesel==1) {
- RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[2]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[3]);
- }
- else {
- RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[1]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[2]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[3]);
- }
- }
- else if(em->selectmode & SCE_SELECT_EDGE) {
- if (em->totedgesel==0) {}
- else if (em->totedgesel==1) { RNA_enum_item_add(&item, &totitem, &extrude_items[2]); }
- else if(em->totfacesel==0) { RNA_enum_item_add(&item, &totitem, &extrude_items[2]); }
- else if(em->totfacesel==1) {
- RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[2]);
- }
- else {
- RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[1]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[2]);
- }
- }
- else {
- if (em->totfacesel == 0) {}
- else if (em->totfacesel == 1) { RNA_enum_item_add(&item, &totitem, &extrude_items[0]); }
- else {
- RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[1]);
- }
- }
-
- if(item) {
- RNA_enum_item_end(&item, &totitem);
- *free= 1;
- return item;
- }
- else {
- return NULL;
- }
-}
-
-void MESH_OT_extrude(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name= "Extrude";
- ot->description= "Extrude selected vertices, edges or faces";
- ot->idname= "MESH_OT_extrude";
-
- /* api callbacks */
- ot->invoke= mesh_extrude_invoke;
- ot->exec= mesh_extrude_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- prop= RNA_def_enum(ot->srna, "type", extrude_items, 0, "Type", "");
- RNA_def_property_flag(prop, PROP_HIDDEN);
- RNA_def_enum_funcs(prop, extrude_itemf);
- ot->prop= prop;
-}
-
-static int split_mesh(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- WM_cursor_wait(1);
+ waitcursor(1);
/* make duplicate first */
- adduplicateflag(em, SELECT);
+ adduplicateflag(SELECT);
/* old faces have flag 128 set, delete them */
- delfaceflag(em, 128);
- recalc_editnormals(em);
+ delfaceflag(128);
+ recalc_editnormals();
- WM_cursor_wait(0);
+ waitcursor(0);
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_split(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Split";
- ot->description= "Split selected geometry into separate disconnected mesh";
- ot->idname= "MESH_OT_split";
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
- /* api callbacks */
- ot->exec= split_mesh;
- ot->poll= ED_operator_editmesh;
+ BIF_undo_push("Split");
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
-
-static int extrude_repeat_mesh(bContext *C, wmOperator *op)
+void extrude_repeat_mesh(int steps, float offs)
{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- RegionView3D *rv3d = ED_view3d_context_rv3d(C);
-
- int steps = RNA_int_get(op->ptr,"steps");
-
- float offs = RNA_float_get(op->ptr,"offset");
-
float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
short a;
+ TEST_EDITMESH
+ if(multires_test()) return;
+
/* dvec */
- dvec[0]= rv3d->persinv[2][0];
- dvec[1]= rv3d->persinv[2][1];
- dvec[2]= rv3d->persinv[2][2];
+ dvec[0]= G.vd->persinv[2][0];
+ dvec[1]= G.vd->persinv[2][1];
+ dvec[2]= G.vd->persinv[2][2];
normalize_v3(dvec);
dvec[0]*= offs;
dvec[1]*= offs;
dvec[2]*= offs;
/* base correction */
- copy_m3_m4(bmat, obedit->obmat);
+ copy_m3_m4(bmat, G.obedit->obmat);
invert_m3_m3(tmat, bmat);
mul_m3_v3(tmat, dvec);
for(a=0; a<steps; a++) {
- extrudeflag(obedit, em, SELECT, nor, 0);
- translateflag(em, SELECT, dvec);
+ extrudeflag(SELECT, nor);
+ translateflag(SELECT, dvec);
}
+
+ recalc_editnormals();
+
+ EM_fgon_flags();
+ countall();
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
- recalc_editnormals(em);
-
- EM_fgon_flags(em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
+ BIF_undo_push("Extrude Repeat");
}
-void MESH_OT_extrude_repeat(wmOperatorType *ot)
+void spin_mesh(int steps, float degr, float *dvec, int mode)
{
- /* identifiers */
- ot->name= "Extrude Repeat Mesh";
- ot->description= "Extrude selected vertices, edges or faces repeatedly";
- ot->idname= "MESH_OT_extrude_repeat";
-
- /* api callbacks */
- ot->exec= extrude_repeat_mesh;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, FLT_MAX);
- RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, INT_MAX);
-}
-
-/* ************************** spin operator ******************** */
-
-
-static int spin_mesh(bContext *C, wmOperator *op, float *dvec, int steps, float degr, int dupli )
-{
- Object *obedit= CTX_data_edit_object(C);
- ToolSettings *ts= CTX_data_tool_settings(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ EditMesh *em = G.editMesh;
EditVert *eve,*nextve;
- float nor[3]= {0.0f, 0.0f, 0.0f};
- float si, n[3], q[4], cmat[3][3], imat[3][3], tmat[3][3];
- float cent[3], bmat[3][3];
+ float nor[3]= {0.0, 0.0, 0.0};
+ float *curs, si,n[3],q[4],cmat[3][3],imat[3][3], tmat[3][3];
+ float cent[3],bmat[3][3];
float phi;
- short a, ok= 1;
-
- RNA_float_get_array(op->ptr, "center", cent);
+ short a,ok;
+ TEST_EDITMESH
+ if(multires_test()) return;
+
/* imat and center and size */
- copy_m3_m4(bmat, obedit->obmat);
+ copy_m3_m4(bmat, G.obedit->obmat);
invert_m3_m3(imat,bmat);
- cent[0]-= obedit->obmat[3][0];
- cent[1]-= obedit->obmat[3][1];
- cent[2]-= obedit->obmat[3][2];
+ curs= give_cursor();
+ VECCOPY(cent, curs);
+ cent[0]-= G.obedit->obmat[3][0];
+ cent[1]-= G.obedit->obmat[3][1];
+ cent[2]-= G.obedit->obmat[3][2];
mul_m3_v3(imat, cent);
phi= degr*M_PI/360.0;
phi/= steps;
- if(ts->editbutflag & B_CLOCKWISE) phi= -phi;
+ if(G.scene->toolsettings->editbutflag & B_CLOCKWISE) phi= -phi;
- RNA_float_get_array(op->ptr, "axis", n);
+ if(dvec) {
+ n[0]= G.vd->viewinv[1][0];
+ n[1]= G.vd->viewinv[1][1];
+ n[2]= G.vd->viewinv[1][2];
+ } else {
+ n[0]= G.vd->viewinv[2][0];
+ n[1]= G.vd->viewinv[2][1];
+ n[2]= G.vd->viewinv[2][2];
+ }
normalize_v3(n);
q[0]= (float)cos(phi);
@@ -992,21 +819,20 @@ static int spin_mesh(bContext *C, wmOperator *op, float *dvec, int steps, float
mul_m3_m3m3(tmat,cmat,bmat);
mul_m3_m3m3(bmat,imat,tmat);
- if(dupli==0)
- if(ts->editbutflag & B_KEEPORIG)
- adduplicateflag(em, 1);
-
- for(a=0; a<steps; a++) {
- if(dupli==0) ok= extrudeflag(obedit, em, SELECT, nor, 0);
- else adduplicateflag(em, SELECT);
+ if(mode==0) if(G.scene->toolsettings->editbutflag & B_KEEPORIG) adduplicateflag(1);
+ ok= 1;
- if(ok==0)
+ for(a=0;a<steps;a++) {
+ if(mode==0) ok= extrudeflag(SELECT, nor);
+ else adduplicateflag(SELECT);
+ if(ok==0) {
+ error("No valid vertices are selected");
break;
-
- rotateflag(em, SELECT, cent, bmat);
+ }
+ rotateflag(SELECT, cent, bmat);
if(dvec) {
mul_m3_v3(bmat,dvec);
- translateflag(em, SELECT, dvec);
+ translateflag(SELECT, dvec);
}
}
@@ -1017,96 +843,41 @@ static int spin_mesh(bContext *C, wmOperator *op, float *dvec, int steps, float
nextve= eve->next;
if(eve->f & SELECT) {
BLI_remlink(&em->verts,eve);
- free_editvert(em, eve);
+ free_editvert(eve);
}
eve= nextve;
}
}
- else {
- recalc_editnormals(em);
-
- EM_fgon_flags(em);
-
- DAG_id_tag_update(obedit->data, 0);
- }
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return ok;
-}
-
-static int spin_mesh_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- int ok;
-
- ok= spin_mesh(C, op, NULL, RNA_int_get(op->ptr,"steps"), RNA_float_get(op->ptr,"degrees"), RNA_boolean_get(op->ptr,"dupli"));
- if(ok==0) {
- BKE_report(op->reports, RPT_WARNING, "No valid vertices are selected");
- return OPERATOR_CANCELLED;
- }
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-/* get center and axis, in global coords */
-static int spin_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
-{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d= ED_view3d_context_rv3d(C);
-
- RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d));
- RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[2]);
-
- return spin_mesh_exec(C, op);
-}
-
-void MESH_OT_spin(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Spin";
- ot->description= "Extrude selected vertices in a circle around the cursor in indicated viewport";
- ot->idname= "MESH_OT_spin";
-
- /* api callbacks */
- ot->invoke= spin_mesh_invoke;
- ot->exec= spin_mesh_exec;
- ot->poll= EM_view3d_poll;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, 128);
- RNA_def_boolean(ot->srna, "dupli", 0, "Dupli", "Make Duplicates");
- RNA_def_float(ot->srna, "degrees", 90.0f, -FLT_MAX, FLT_MAX, "Degrees", "Degrees", -360.0f, 360.0f);
+ recalc_editnormals();
- RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
- RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX);
+ EM_fgon_flags();
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ if(dvec==NULL) BIF_undo_push("Spin");
}
-static int screw_mesh_exec(bContext *C, wmOperator *op)
+void screw_mesh(int steps, int turns)
{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ EditMesh *em = G.editMesh;
EditVert *eve,*v1=0,*v2=0;
EditEdge *eed;
float dvec[3], nor[3];
- int steps, turns;
-
- turns= RNA_int_get(op->ptr, "turns");
- steps= RNA_int_get(op->ptr, "steps");
+ TEST_EDITMESH
+ if(multires_test()) return;
+
/* clear flags */
- for(eve= em->verts.first; eve; eve= eve->next)
+ eve= em->verts.first;
+ while(eve) {
eve->f1= 0;
-
+ eve= eve->next;
+ }
/* edges set flags in verts */
- for(eed= em->edges.first; eed; eed= eed->next) {
+ eed= em->edges.first;
+ while(eed) {
if(eed->v1->f & SELECT) {
if(eed->v2->f & SELECT) {
/* watch: f1 is a byte */
@@ -1114,30 +885,32 @@ static int screw_mesh_exec(bContext *C, wmOperator *op)
if(eed->v2->f1<2) eed->v2->f1++;
}
}
+ eed= eed->next;
}
/* find two vertices with eve->f1==1, more or less is wrong */
- for(eve= em->verts.first; eve; eve= eve->next) {
+ eve= em->verts.first;
+ while(eve) {
if(eve->f1==1) {
- if(v1==NULL) v1= eve;
- else if(v2==NULL) v2= eve;
+ if(v1==0) v1= eve;
+ else if(v2==0) v2= eve;
else {
- v1= NULL;
+ v1=0;
break;
}
}
+ eve= eve->next;
}
- if(v1==NULL || v2==NULL) {
- BKE_report(op->reports, RPT_WARNING, "You have to select a string of connected vertices too");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
+ if(v1==0 || v2==0) {
+ error("You have to select a string of connected vertices too");
+ return;
}
/* calculate dvec */
- dvec[0]= ( v1->co[0]- v2->co[0] )/steps;
- dvec[1]= ( v1->co[1]- v2->co[1] )/steps;
- dvec[2]= ( v1->co[2]- v2->co[2] )/steps;
+ dvec[0]= ( (v1->co[0]- v2->co[0]) )/(steps);
+ dvec[1]= ( (v1->co[1]- v2->co[1]) )/(steps);
+ dvec[2]= ( (v1->co[2]- v2->co[2]) )/(steps);
- VECCOPY(nor, obedit->obmat[2]);
+ VECCOPY(nor, G.obedit->obmat[2]);
if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.000) {
dvec[0]= -dvec[0];
@@ -1145,72 +918,28 @@ static int screw_mesh_exec(bContext *C, wmOperator *op)
dvec[2]= -dvec[2];
}
- if(spin_mesh(C, op, dvec, turns*steps, 360.0f*turns, 0)) {
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+ spin_mesh(turns*steps, turns*360, dvec, 0);
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
- }
- else {
- BKE_report(op->reports, RPT_WARNING, "No valid vertices are selected");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
+ BIF_undo_push("Spin");
}
-/* get center and axis, in global coords */
-static int screw_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
-{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d= ED_view3d_context_rv3d(C);
-
- RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d));
- RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[1]);
-
- return screw_mesh_exec(C, op);
-}
-
-void MESH_OT_screw(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Screw";
- ot->description= "Extrude selected vertices in screw-shaped rotation around the cursor in indicated viewport";
- ot->idname= "MESH_OT_screw";
-
- /* api callbacks */
- ot->invoke= screw_mesh_invoke;
- ot->exec= screw_mesh_exec;
- ot->poll= EM_view3d_poll;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /*props */
- RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, 256);
- RNA_def_int(ot->srna, "turns", 1, 0, INT_MAX, "Turns", "Turns", 0, 256);
- RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
- RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX);
-}
-
-static void erase_edges(EditMesh *em, ListBase *l)
+static void erase_edges(ListBase *l)
{
EditEdge *ed, *nexted;
-
+
ed = (EditEdge *) l->first;
while(ed) {
nexted= ed->next;
if( (ed->v1->f & SELECT) || (ed->v2->f & SELECT) ) {
- remedge(em, ed);
- free_editedge(em, ed);
+ remedge(ed);
+ free_editedge(ed);
}
ed= nexted;
}
}
-static void erase_faces(EditMesh *em, ListBase *l)
+static void erase_faces(ListBase *l)
{
EditFace *f, *nextf;
@@ -1220,13 +949,13 @@ static void erase_faces(EditMesh *em, ListBase *l)
nextf= f->next;
if( faceselectedOR(f, SELECT) ) {
BLI_remlink(l, f);
- free_editface(em, f);
+ free_editface(f);
}
f = nextf;
}
-}
+}
-static void erase_vertices(EditMesh *em, ListBase *l)
+static void erase_vertices(ListBase *l)
{
EditVert *v, *nextv;
@@ -1235,37 +964,42 @@ static void erase_vertices(EditMesh *em, ListBase *l)
nextv= v->next;
if(v->f & 1) {
BLI_remlink(l, v);
- free_editvert(em, v);
+ free_editvert(v);
}
v = nextv;
}
}
-static void delete_mesh(EditMesh *em, wmOperator *op, int event)
+void delete_mesh(void)
{
+ EditMesh *em = G.editMesh;
EditFace *efa, *nextvl;
EditVert *eve,*nextve;
EditEdge *eed,*nexted;
+ short event;
int count;
- /* const char *str="Erase"; */
-
+ char *str="Erase";
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ event= pupmenu("Erase %t|Vertices%x10|Edges%x1|Faces%x2|All%x3|Edges & Faces%x4|Only Faces%x5|Edge Loop%x6");
if(event<1) return;
if(event==10 ) {
- /* str= "Erase Vertices"; */
- erase_edges(em, &em->edges);
- erase_faces(em, &em->faces);
- erase_vertices(em, &em->verts);
- }
+ str= "Erase Vertices";
+ erase_edges(&em->edges);
+ erase_faces(&em->faces);
+ erase_vertices(&em->verts);
+ }
else if(event==6) {
- if(!EdgeLoopDelete(em, op))
+ if(!EdgeLoopDelete())
return;
- /* str= "Erase Edge Loop"; */
+ str= "Erase Edge Loop";
}
else if(event==4) {
- /* str= "Erase Edges & Faces"; */
+ str= "Erase Edges & Faces";
efa= em->faces.first;
while(efa) {
nextvl= efa->next;
@@ -1277,7 +1011,7 @@ static void delete_mesh(EditMesh *em, wmOperator *op, int event)
if(efa->e4 && (efa->e4->f & SELECT)) count++;
if(count) {
BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
+ free_editface(efa);
}
efa= nextvl;
}
@@ -1285,8 +1019,8 @@ static void delete_mesh(EditMesh *em, wmOperator *op, int event)
while(eed) {
nexted= eed->next;
if(eed->f & SELECT) {
- remedge(em, eed);
- free_editedge(em, eed);
+ remedge(eed);
+ free_editedge(eed);
}
eed= nexted;
}
@@ -1298,16 +1032,16 @@ static void delete_mesh(EditMesh *em, wmOperator *op, int event)
if( efa->v2->f & SELECT) event++;
if( efa->v3->f & SELECT) event++;
if(efa->v4 && (efa->v4->f & SELECT)) event++;
-
+
if(event>1) {
BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
+ free_editface(efa);
}
efa= nextvl;
}
- }
+ }
else if(event==1) {
- /* str= "Erase Edges"; */
+ str= "Erase Edges";
// faces first
efa= em->faces.first;
while(efa) {
@@ -1317,10 +1051,10 @@ static void delete_mesh(EditMesh *em, wmOperator *op, int event)
if( efa->e2->f & SELECT) event++;
if( efa->e3->f & SELECT) event++;
if(efa->e4 && (efa->e4->f & SELECT)) event++;
-
+
if(event) {
BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
+ free_editface(efa);
}
efa= nextvl;
}
@@ -1328,8 +1062,8 @@ static void delete_mesh(EditMesh *em, wmOperator *op, int event)
while(eed) {
nexted= eed->next;
if(eed->f & SELECT) {
- remedge(em, eed);
- free_editedge(em, eed);
+ remedge(eed);
+ free_editedge(eed);
}
eed= nexted;
}
@@ -1345,90 +1079,135 @@ static void delete_mesh(EditMesh *em, wmOperator *op, int event)
nextve= eve->next;
if(eve->f & SELECT) {
BLI_remlink(&em->verts,eve);
- free_editvert(em, eve);
+ free_editvert(eve);
}
eve= nextve;
}
}
else if(event==2) {
- /* str="Erase Faces"; */
- delfaceflag(em, SELECT);
+ str="Erase Faces";
+ delfaceflag(SELECT);
}
else if(event==3) {
- /* str= "Erase All"; */
- if(em->verts.first) free_vertlist(em, &em->verts);
- if(em->edges.first) free_edgelist(em, &em->edges);
- if(em->faces.first) free_facelist(em, &em->faces);
+ str= "Erase All";
+ if(em->verts.first) free_vertlist(&em->verts);
+ if(em->edges.first) free_edgelist(&em->edges);
+ if(em->faces.first) free_facelist(&em->faces);
if(em->selected.first) BLI_freelistN(&(em->selected));
}
else if(event==5) {
- /* str= "Erase Only Faces"; */
+ str= "Erase Only Faces";
efa= em->faces.first;
while(efa) {
nextvl= efa->next;
if(efa->f & SELECT) {
BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
+ free_editface(efa);
}
efa= nextvl;
}
}
- EM_fgon_flags(em); // redo flags and indices for fgons
+ EM_fgon_flags(); // redo flags and indices for fgons
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ BIF_undo_push(str);
}
-/* Note, these values must match delete_mesh() event values */
-static EnumPropertyItem prop_mesh_delete_types[] = {
- {10,"VERT", 0, "Vertices", ""},
- {1, "EDGE", 0, "Edges", ""},
- {2, "FACE", 0, "Faces", ""},
- {3, "ALL", 0, "All", ""},
- {4, "EDGE_FACE",0, "Edges & Faces", ""},
- {5, "ONLY_FACE",0, "Only Faces", ""},
- {6, "EDGE_LOOP",0, "Edge Loop", ""},
- {0, NULL, 0, NULL, NULL}
-};
-static int delete_mesh_exec(bContext *C, wmOperator *op)
+/* Got this from scanfill.c. You will need to juggle around the
+ * callbacks for the scanfill.c code a bit for this to work. */
+void fill_mesh(void)
{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
- int type= RNA_enum_get(op->ptr, "type");
-
- if(type==6)
- return WM_operator_name_call(C, "MESH_OT_delete_edgeloop", WM_OP_EXEC_DEFAULT, NULL);
+ EditMesh *em = G.editMesh;
+ EditVert *eve,*v1;
+ EditEdge *eed,*e1,*nexted;
+ EditFace *efa,*nextvl, *efan;
+ short ok;
- delete_mesh(em, op, type);
+ if(G.obedit==0 || (G.obedit->type!=OB_MESH)) return;
+ if(multires_test()) return;
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+ waitcursor(1);
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
+ /* copy all selected vertices */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & SELECT) {
+ v1= BLI_addfillvert(eve->co);
+ eve->tmp.v= v1;
+ v1->tmp.v= eve;
+ v1->xs= 0; // used for counting edges
+ }
+ eve= eve->next;
+ }
+ /* copy all selected edges */
+ eed= em->edges.first;
+ while(eed) {
+ if( (eed->v1->f & SELECT) && (eed->v2->f & SELECT) ) {
+ e1= BLI_addfilledge(eed->v1->tmp.v, eed->v2->tmp.v);
+ e1->v1->xs++;
+ e1->v2->xs++;
+ }
+ eed= eed->next;
+ }
+ /* from all selected faces: remove vertices and edges to prevent doubles */
+ /* all edges add values, faces subtract,
+ then remove edges with vertices ->xs<2 */
+ efa= em->faces.first;
+ ok= 0;
+ while(efa) {
+ nextvl= efa->next;
+ if( faceselectedAND(efa, 1) ) {
+ efa->v1->tmp.v->xs--;
+ efa->v2->tmp.v->xs--;
+ efa->v3->tmp.v->xs--;
+ if(efa->v4) efa->v4->tmp.v->xs--;
+ ok= 1;
+
+ }
+ efa= nextvl;
+ }
+ if(ok) { /* there are faces selected */
+ eed= filledgebase.first;
+ while(eed) {
+ nexted= eed->next;
+ if(eed->v1->xs<2 || eed->v2->xs<2) {
+ BLI_remlink(&filledgebase,eed);
+ }
+ eed= nexted;
+ }
+ }
-void MESH_OT_delete(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Delete";
- ot->description= "Delete selected vertices, edges or faces";
- ot->idname= "MESH_OT_delete";
+ if(BLI_edgefill(0, (G.obedit && G.obedit->actcol)?(G.obedit->actcol-1):0)) {
+ efa= fillfacebase.first;
+ while(efa) {
+ /* normals default pointing up */
+ efan= addfacelist(efa->v3->tmp.v, efa->v2->tmp.v,
+ efa->v1->tmp.v, 0, NULL, NULL);
+ if(efan) EM_select_face(efan, 1);
+ efa= efa->next;
+ }
+ }
- /* api callbacks */
- ot->invoke= WM_menu_invoke;
- ot->exec= delete_mesh_exec;
+ BLI_end_edgefill();
- ot->poll= ED_operator_editmesh;
+ waitcursor(0);
+ EM_select_flush();
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
- /*props */
- ot->prop= RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data");
+ BIF_undo_push("Fill");
}
-
-
/*GB*/
/*-------------------------------------------------------------------------------*/
/*--------------------------- Edge Based Subdivide ------------------------------*/
@@ -1442,76 +1221,75 @@ void MESH_OT_delete(wmOperatorType *ot)
#define DOUBLEOPFILL 16
/* calculates offset for co, based on fractal, sphere or smooth settings */
-static void alter_co(float *co, EditEdge *edge, float smooth, float fractal, int beauty, float perc)
+static void alter_co(float *co, EditEdge *edge, float rad, int beauty, float perc)
{
float vec1[3], fac;
-
+
if(beauty & B_SMOOTH) {
/* we calculate an offset vector vec1[], to be added to *co */
float len, fac, nor[3], nor1[3], nor2[3];
-
+
sub_v3_v3v3(nor, edge->v1->co, edge->v2->co);
len= 0.5f*normalize_v3(nor);
-
+
VECCOPY(nor1, edge->v1->no);
VECCOPY(nor2, edge->v2->no);
-
+
/* cosine angle */
fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ;
-
+
vec1[0]= fac*nor1[0];
vec1[1]= fac*nor1[1];
vec1[2]= fac*nor1[2];
-
+
/* cosine angle */
fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ;
-
+
vec1[0]+= fac*nor2[0];
vec1[1]+= fac*nor2[1];
vec1[2]+= fac*nor2[2];
-
- /* falloff for multi subdivide */
- smooth *= sqrt(fabs(1.0f - 2.0f*fabs(0.5f-perc)));
-
- vec1[0]*= smooth*len;
- vec1[1]*= smooth*len;
- vec1[2]*= smooth*len;
-
+
+ vec1[0]*= rad*len;
+ vec1[1]*= rad*len;
+ vec1[2]*= rad*len;
+
co[0] += vec1[0];
co[1] += vec1[1];
co[2] += vec1[2];
}
- else if(beauty & B_SPHERE) { /* subdivide sphere */
- normalize_v3(co);
- co[0]*= smooth;
- co[1]*= smooth;
- co[2]*= smooth;
- }
+ else {
+ if(rad > 0.0) { /* subdivide sphere */
+ normalize_v3(co);
+ co[0]*= rad;
+ co[1]*= rad;
+ co[2]*= rad;
+ }
+ else if(rad< 0.0) { /* fractal subdivide */
+ fac= rad* len_v3v3(edge->v1->co, edge->v2->co);
+ vec1[0]= fac*(float)(0.5-BLI_drand());
+ vec1[1]= fac*(float)(0.5-BLI_drand());
+ vec1[2]= fac*(float)(0.5-BLI_drand());
+ add_v3_v3v3(co, co, vec1);
+ }
- if(beauty & B_FRACTAL) {
- fac= fractal*len_v3v3(edge->v1->co, edge->v2->co);
- vec1[0]= fac*(float)(0.5-BLI_drand());
- vec1[1]= fac*(float)(0.5-BLI_drand());
- vec1[2]= fac*(float)(0.5-BLI_drand());
- add_v3_v3(co, vec1);
}
}
/* assumes in the edge is the correct interpolated vertices already */
-/* percent defines the interpolation, smooth, fractal and beauty are for special options */
+/* percent defines the interpolation, rad and beauty are for special options */
/* results in new vertex with correct coordinate, vertex normal and weight group info */
-static EditVert *subdivide_edge_addvert(EditMesh *em, EditEdge *edge, float smooth, float fractal, int beauty, float percent)
+static EditVert *subdivide_edge_addvert(EditEdge *edge, float rad, int beauty, float percent)
{
EditVert *ev;
float co[3];
-
+
co[0] = (edge->v2->co[0]-edge->v1->co[0])*percent + edge->v1->co[0];
co[1] = (edge->v2->co[1]-edge->v1->co[1])*percent + edge->v1->co[1];
- co[2] = (edge->v2->co[2]-edge->v1->co[2])*percent + edge->v1->co[2];
-
+ co[2] = (edge->v2->co[2]-edge->v1->co[2])*percent + edge->v1->co[2];
+
/* offset for smooth or sphere or fractal */
- alter_co(co, edge, smooth, fractal, beauty, percent);
-
+ alter_co(co, edge, rad, beauty, percent);
+
/* clip if needed by mirror modifier */
if (edge->v1->f2) {
if ( edge->v1->f2 & edge->v2->f2 & 1) {
@@ -1524,18 +1302,18 @@ static EditVert *subdivide_edge_addvert(EditMesh *em, EditEdge *edge, float smoo
co[2]= 0.0f;
}
}
-
- ev = addvertlist(em, co, NULL);
-
+
+ ev = addvertlist(co, NULL);
+
/* vert data (vgroups, ..) */
- EM_data_interp_from_verts(em, edge->v1, edge->v2, ev, percent);
-
+ EM_data_interp_from_verts(edge->v1, edge->v2, ev, percent);
+
/* normal */
ev->no[0] = (edge->v2->no[0]-edge->v1->no[0])*percent + edge->v1->no[0];
ev->no[1] = (edge->v2->no[1]-edge->v1->no[1])*percent + edge->v1->no[1];
ev->no[2] = (edge->v2->no[2]-edge->v1->no[2])*percent + edge->v1->no[2];
normalize_v3(ev->no);
-
+
return ev;
}
@@ -1543,16 +1321,17 @@ static void flipvertarray(EditVert** arr, short size)
{
EditVert *hold;
int i;
-
+
for(i=0; i<size/2; i++) {
hold = arr[i];
arr[i] = arr[size-i-1];
- arr[size-i-1] = hold;
+ arr[size-i-1] = hold;
}
}
-static void facecopy(EditMesh *em, EditFace *source, EditFace *target)
+static void facecopy(EditFace *source, EditFace *target)
{
+ EditMesh *em= G.editMesh;
float *v1 = source->v1->co, *v2 = source->v2->co, *v3 = source->v3->co;
float *v4 = source->v4? source->v4->co: NULL;
float w[4][4];
@@ -1560,35 +1339,34 @@ static void facecopy(EditMesh *em, EditFace *source, EditFace *target)
CustomData_em_copy_data(&em->fdata, &em->fdata, source->data, &target->data);
target->mat_nr = source->mat_nr;
- target->flag = source->flag;
+ target->flag = source->flag;
target->h = source->h;
-
+
interp_weights_face_v3( w[0],v1, v2, v3, v4, target->v1->co);
interp_weights_face_v3( w[1],v1, v2, v3, v4, target->v2->co);
interp_weights_face_v3( w[2],v1, v2, v3, v4, target->v3->co);
if (target->v4)
interp_weights_face_v3( w[3],v1, v2, v3, v4, target->v4->co);
-
- CustomData_em_validate_data(&em->fdata, target->data, target->v4 ? 4 : 3);
+
CustomData_em_interp(&em->fdata, &source->data, NULL, (float*)w, 1, target->data);
}
-static void fill_quad_single(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, int seltype)
+static void fill_quad_single(EditFace *efa, struct GHash *gh, int numcuts, int seltype)
{
EditEdge *cedge=NULL;
EditVert *v[4], **verts;
EditFace *hold;
- short start=0, end, left, right, vertsize,i;
-
+ short start=0, end, left, right, vertsize,i;
+
v[0] = efa->v1;
v[1] = efa->v2;
v[2] = efa->v3;
- v[3] = efa->v4;
+ v[3] = efa->v4;
if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;}
- else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;}
- else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;}
- else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;}
+ else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;}
+ else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;}
+ else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;}
// Point verts to the array of new verts for cedge
verts = BLI_ghash_lookup(gh, cedge);
@@ -1602,77 +1380,77 @@ static void fill_quad_single(EditMesh *em, EditFace *efa, struct GHash *gh, int
if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);}
end = (start+1)%4;
left = (start+2)%4;
- right = (start+3)%4;
-
+ right = (start+3)%4;
+
/*
We should have something like this now
- end start
- 3 2 1 0
+ end start
+ 3 2 1 0
|---*---*---|
| |
+ | |
| |
- | |
- -------------
+ -------------
left right
where start,end,left, right are indexes of EditFace->v1, etc (stored in v)
and 0,1,2... are the indexes of the new verts stored in verts
We will fill this case like this or this depending on even or odd cuts
-
+
|---*---*---| |---*---|
| / \ | | / \ |
- | / \ | | / \ |
+ | / \ | | / \ |
|/ \| |/ \|
- ------------- ---------
+ ------------- ---------
*/
// Make center face
if(vertsize % 2 == 0) {
- hold = addfacelist(em, verts[(vertsize-1)/2],verts[((vertsize-1)/2)+1],v[left],v[right], NULL,NULL);
+ hold = addfacelist(verts[(vertsize-1)/2],verts[((vertsize-1)/2)+1],v[left],v[right], NULL,NULL);
hold->e2->f2 |= EDGEINNER;
hold->e4->f2 |= EDGEINNER;
}else{
- hold = addfacelist(em, verts[(vertsize-1)/2],v[left],v[right],NULL, NULL,NULL);
+ hold = addfacelist(verts[(vertsize-1)/2],v[left],v[right],NULL, NULL,NULL);
hold->e1->f2 |= EDGEINNER;
hold->e3->f2 |= EDGEINNER;
}
- facecopy(em, efa,hold);
+ facecopy(efa,hold);
// Make side faces
for(i=0;i<(vertsize-1)/2;i++) {
- hold = addfacelist(em, verts[i],verts[i+1],v[right],NULL,NULL,NULL);
- facecopy(em, efa,hold);
+ hold = addfacelist(verts[i],verts[i+1],v[right],NULL,NULL,NULL);
+ facecopy(efa,hold);
if(i+1 != (vertsize-1)/2) {
- if(seltype == SUBDIV_SELECT_INNER) {
- hold->e2->f2 |= EDGEINNER;
- }
+ if(seltype == SUBDIV_SELECT_INNER) {
+ hold->e2->f2 |= EDGEINNER;
+ }
}
- hold = addfacelist(em, verts[vertsize-2-i],verts[vertsize-1-i],v[left],NULL,NULL,NULL);
- facecopy(em, efa,hold);
+ hold = addfacelist(verts[vertsize-2-i],verts[vertsize-1-i],v[left],NULL,NULL,NULL);
+ facecopy(efa,hold);
if(i+1 != (vertsize-1)/2) {
- if(seltype == SUBDIV_SELECT_INNER) {
- hold->e3->f2 |= EDGEINNER;
- }
+ if(seltype == SUBDIV_SELECT_INNER) {
+ hold->e3->f2 |= EDGEINNER;
+ }
}
- }
+ }
}
-static void fill_tri_single(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, int seltype)
+static void fill_tri_single(EditFace *efa, struct GHash *gh, int numcuts, int seltype)
{
EditEdge *cedge=NULL;
EditVert *v[3], **verts;
EditFace *hold;
- short start=0, end, op, vertsize,i;
-
+ short start=0, end, op, vertsize,i;
+
v[0] = efa->v1;
v[1] = efa->v2;
- v[2] = efa->v3;
+ v[2] = efa->v3;
if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;}
- else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;}
- else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;}
+ else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;}
+ else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;}
// Point verts to the array of new verts for cedge
verts = BLI_ghash_lookup(gh, cedge);
@@ -1686,30 +1464,30 @@ static void fill_tri_single(EditMesh *em, EditFace *efa, struct GHash *gh, int n
if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);}
end = (start+1)%3;
op = (start+2)%3;
-
+
/*
We should have something like this now
- end start
- 3 2 1 0
+ end start
+ 3 2 1 0
|---*---*---|
\ |
- \ |
+ \ |
\ |
\ |
\ |
\ |
|op
-
+
where start,end,op are indexes of EditFace->v1, etc (stored in v)
and 0,1,2... are the indexes of the new verts stored in verts
We will fill this case like this or this depending on even or odd cuts
-
- 3 2 1 0
+
+ 3 2 1 0
|---*---*---|
\ \ \ |
- \ \ \ |
+ \ \ \ |
\ \ \ |
\ \ \|
\ \\|
@@ -1719,27 +1497,27 @@ static void fill_tri_single(EditMesh *em, EditFace *efa, struct GHash *gh, int n
// Make side faces
for(i=0;i<(vertsize-1);i++) {
- hold = addfacelist(em, verts[i],verts[i+1],v[op],NULL,NULL,NULL);
+ hold = addfacelist(verts[i],verts[i+1],v[op],NULL,NULL,NULL);
if(i+1 != vertsize-1) {
- if(seltype == SUBDIV_SELECT_INNER) {
- hold->e2->f2 |= EDGEINNER;
- }
+ if(seltype == SUBDIV_SELECT_INNER) {
+ hold->e2->f2 |= EDGEINNER;
+ }
}
- facecopy(em, efa,hold);
- }
+ facecopy(efa,hold);
+ }
}
-static void fill_quad_double_op(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
+static void fill_quad_double_op(EditFace *efa, struct GHash *gh, int numcuts)
{
EditEdge *cedge[2]={NULL, NULL};
EditVert *v[4], **verts[2];
EditFace *hold;
- short start=0, /*end,*/ left, /* right,*/ vertsize,i;
-
+ short start=0, end, left, right, vertsize,i;
+
v[0] = efa->v1;
v[1] = efa->v2;
v[2] = efa->v3;
- v[3] = efa->v4;
+ v[3] = efa->v4;
if(efa->e1->f & SELECT) { cedge[0] = efa->e1; cedge[1] = efa->e3; start = 0;}
else if(efa->e2->f & SELECT) { cedge[0] = efa->e2; cedge[1] = efa->e4; start = 1;}
@@ -1755,55 +1533,54 @@ static void fill_quad_double_op(EditMesh *em, EditFace *efa, struct GHash *gh, i
// the array to the correct direction
if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
- /* end = (start+1)%4; */ /* UNUSED */
+ end = (start+1)%4;
left = (start+2)%4;
- /* right = (start+3)%4; */ /* UNUSED */
- if(verts[1][0] != v[left]) {flipvertarray(verts[1],numcuts+2);}
+ right = (start+3)%4;
+ if(verts[1][0] != v[left]) {flipvertarray(verts[1],numcuts+2);}
/*
We should have something like this now
- end start
- 3 2 1 0
+ end start
+ 3 2 1 0
|---*---*---|
| |
+ | |
| |
- | |
- |---*---*---|
+ |---*---*---|
0 1 2 3
left right
We will fill this case like this or this depending on even or odd cuts
-
+
|---*---*---|
| | | |
+ | | | |
| | | |
- | | | |
- |---*---*---|
+ |---*---*---|
*/
-
+
// Make side faces
for(i=0;i<vertsize-1;i++) {
- hold = addfacelist(em, verts[0][i],verts[0][i+1],verts[1][vertsize-2-i],verts[1][vertsize-1-i],NULL,NULL);
+ hold = addfacelist(verts[0][i],verts[0][i+1],verts[1][vertsize-2-i],verts[1][vertsize-1-i],NULL,NULL);
if(i < vertsize-2) {
hold->e2->f2 |= EDGEINNER;
hold->e2->f2 |= DOUBLEOPFILL;
}
- facecopy(em, efa,hold);
- }
+ facecopy(efa,hold);
+ }
}
-static void fill_quad_double_adj_path(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
+static void fill_quad_double_adj_path(EditFace *efa, struct GHash *gh, int numcuts)
{
EditEdge *cedge[2]={NULL, NULL};
EditVert *v[4], **verts[2];
EditFace *hold;
short start=0, start2=0, vertsize,i;
- int ctrl= 0; // XXX
-
+
v[0] = efa->v1;
v[1] = efa->v2;
v[2] = efa->v3;
- v[3] = efa->v4;
+ v[3] = efa->v4;
if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1;}
if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2;}
@@ -1821,73 +1598,73 @@ static void fill_quad_double_adj_path(EditMesh *em, EditFace *efa, struct GHash
// the array to the correct direction
if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
- if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
+ if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
/*
We should have something like this now
- end start
- 3 2 1 0
+ end start
+ 3 2 1 0
start2 0|---*---*---|
| |
1* |
| |
- 2* |
+ 2* |
| |
- end2 3|-----------|
+ end2 3|-----------|
We will fill this case like this or this depending on even or odd cuts
|---*---*---|
| / / / |
* / / |
| / / |
- * / |
+ * / |
| / |
- |-----------|
+ |-----------|
*/
// Make outside tris
- hold = addfacelist(em, verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
+ hold = addfacelist(verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
/* when ctrl is depressed, only want verts on the cutline selected */
- if (ctrl)
+ if (G.qual != LR_CTRLKEY)
hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- hold = addfacelist(em, verts[0][0],verts[1][vertsize-1],v[(start2+2)%4],NULL,NULL,NULL);
+ facecopy(efa,hold);
+ hold = addfacelist(verts[0][0],verts[1][vertsize-1],v[(start2+2)%4],NULL,NULL,NULL);
/* when ctrl is depressed, only want verts on the cutline selected */
- if (ctrl)
- hold->e1->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
+ if (G.qual != LR_CTRLKEY)
+ hold->e1->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) {
// hold->e1->h |= EM_FGON;
- //}
+ //}
// Make side faces
for(i=0;i<numcuts;i++) {
- hold = addfacelist(em, verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL);
+ hold = addfacelist(verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL);
hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
+ facecopy(efa,hold);
}
- //EM_fgon_flags(em);
-
+ //EM_fgon_flags();
+
}
-static void fill_quad_double_adj_fan(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
+static void fill_quad_double_adj_fan(EditFace *efa, struct GHash *gh, int numcuts)
{
EditEdge *cedge[2]={NULL, NULL};
EditVert *v[4], *op=NULL, **verts[2];
EditFace *hold;
short start=0, start2=0, vertsize,i;
-
+
v[0] = efa->v1;
v[1] = efa->v2;
v[2] = efa->v3;
- v[3] = efa->v4;
+ v[3] = efa->v4;
if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;}
if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;}
if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;}
if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;}
-
+
// Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
verts[0] = BLI_ghash_lookup(gh, cedge[0]);
verts[1] = BLI_ghash_lookup(gh, cedge[1]);
@@ -1899,60 +1676,60 @@ static void fill_quad_double_adj_fan(EditMesh *em, EditFace *efa, struct GHash *
// the array to the correct direction
if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
- if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
+ if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
/*
We should have something like this now
- end start
- 3 2 1 0
+ end start
+ 3 2 1 0
start2 0|---*---*---|
| |
1* |
| |
- 2* |
+ 2* |
| |
- end2 3|-----------|op
+ end2 3|-----------|op
We will fill this case like this or this (warning horrible ascii art follows)
|---*---*---|
| \ \ \ |
*---\ \ \ |
| \ \ \ \|
- *---- \ \ \ |
+ *---- \ \ \ |
| --- \\\|
- |-----------|
+ |-----------|
*/
for(i=0;i<=numcuts;i++) {
- hold = addfacelist(em, op,verts[1][numcuts-i],verts[1][numcuts-i+1],NULL,NULL,NULL);
+ hold = addfacelist(op,verts[1][numcuts-i],verts[1][numcuts-i+1],NULL,NULL,NULL);
hold->e1->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
+ facecopy(efa,hold);
- hold = addfacelist(em, op,verts[0][i],verts[0][i+1],NULL,NULL,NULL);
+ hold = addfacelist(op,verts[0][i],verts[0][i+1],NULL,NULL,NULL);
hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- }
+ facecopy(efa,hold);
+ }
}
-static void fill_quad_double_adj_inner(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
+static void fill_quad_double_adj_inner(EditFace *efa, struct GHash *gh, int numcuts)
{
EditEdge *cedge[2]={NULL, NULL};
EditVert *v[4], *op=NULL, **verts[2],**inner;
EditFace *hold;
short start=0, start2=0, vertsize,i;
float co[3];
-
+
v[0] = efa->v1;
v[1] = efa->v2;
v[2] = efa->v3;
- v[3] = efa->v4;
+ v[3] = efa->v4;
if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;}
if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;}
if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;}
if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;}
-
+
// Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
verts[0] = BLI_ghash_lookup(gh, cedge[0]);
verts[1] = BLI_ghash_lookup(gh, cedge[1]);
@@ -1964,19 +1741,19 @@ static void fill_quad_double_adj_inner(EditMesh *em, EditFace *efa, struct GHash
// the array to the correct direction
if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
- if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
+ if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
/*
We should have something like this now
- end start
- 3 2 1 0
+ end start
+ 3 2 1 0
start2 0|---*---*---|
| |
1* |
| |
- 2* |
+ 2* |
| |
- end2 3|-----------|op
+ end2 3|-----------|op
We will fill this case like this or this (warning horrible ascii art follows)
|---*-----*---|
@@ -1984,71 +1761,71 @@ static void fill_quad_double_adj_inner(EditMesh *em, EditFace *efa, struct GHash
* \ / |
| * |
| / \ |
- * \ |
+ * \ |
| \ |
- |-------------|
+ |-------------|
*/
// Add Inner Vert(s)
inner = MEM_mallocN(sizeof(EditVert*)*numcuts,"New inner verts");
-
+
for(i=0;i<numcuts;i++) {
co[0] = (verts[0][numcuts-i]->co[0] + verts[1][i+1]->co[0] ) / 2 ;
co[1] = (verts[0][numcuts-i]->co[1] + verts[1][i+1]->co[1] ) / 2 ;
co[2] = (verts[0][numcuts-i]->co[2] + verts[1][i+1]->co[2] ) / 2 ;
- inner[i] = addvertlist(em, co, NULL);
+ inner[i] = addvertlist(co, NULL);
inner[i]->f2 |= EDGEINNER;
- EM_data_interp_from_verts(em, verts[0][numcuts-i], verts[1][i+1], inner[i], 0.5f);
+ EM_data_interp_from_verts(verts[0][numcuts-i], verts[1][i+1], inner[i], 0.5f);
}
-
+
// Add Corner Quad
- hold = addfacelist(em, verts[0][numcuts+1],verts[1][1],inner[0],verts[0][numcuts],NULL,NULL);
+ hold = addfacelist(verts[0][numcuts+1],verts[1][1],inner[0],verts[0][numcuts],NULL,NULL);
hold->e2->f2 |= EDGEINNER;
hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
+ facecopy(efa,hold);
// Add Bottom Quads
- hold = addfacelist(em, verts[0][0],verts[0][1],inner[numcuts-1],op,NULL,NULL);
+ hold = addfacelist(verts[0][0],verts[0][1],inner[numcuts-1],op,NULL,NULL);
hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
+ facecopy(efa,hold);
- hold = addfacelist(em, op,inner[numcuts-1],verts[1][numcuts],verts[1][numcuts+1],NULL,NULL);
+ hold = addfacelist(op,inner[numcuts-1],verts[1][numcuts],verts[1][numcuts+1],NULL,NULL);
hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
-
- //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
+ facecopy(efa,hold);
+
+ //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) {
// hold->e1->h |= EM_FGON;
- //}
+ //}
// Add Fill Quads (if # cuts > 1)
for(i=0;i<numcuts-1;i++) {
- hold = addfacelist(em, inner[i],verts[1][i+1],verts[1][i+2],inner[i+1],NULL,NULL);
+ hold = addfacelist(inner[i],verts[1][i+1],verts[1][i+2],inner[i+1],NULL,NULL);
hold->e1->f2 |= EDGEINNER;
hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
+ facecopy(efa,hold);
- hold = addfacelist(em, inner[i],inner[i+1],verts[0][numcuts-1-i],verts[0][numcuts-i],NULL,NULL);
+ hold = addfacelist(inner[i],inner[i+1],verts[0][numcuts-1-i],verts[0][numcuts-i],NULL,NULL);
hold->e2->f2 |= EDGEINNER;
hold->e4->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
-
- //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
+ facecopy(efa,hold);
+
+ //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) {
// hold->e1->h |= EM_FGON;
- //}
- }
-
- //EM_fgon_flags(em);
-
- MEM_freeN(inner);
+ //}
+ }
+
+ //EM_fgon_flags();
+
+ MEM_freeN(inner);
}
-static void fill_tri_double(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
+static void fill_tri_double(EditFace *efa, struct GHash *gh, int numcuts)
{
EditEdge *cedge[2]={NULL, NULL};
EditVert *v[3], **verts[2];
EditFace *hold;
short start=0, start2=0, vertsize,i;
-
+
v[0] = efa->v1;
v[1] = efa->v2;
v[2] = efa->v3;
@@ -2068,224 +1845,224 @@ static void fill_tri_double(EditMesh *em, EditFace *efa, struct GHash *gh, int n
// the array to the correct direction
if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
- if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
+ if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
/*
We should have something like this now
- end start
- 3 2 1 0
+ end start
+ 3 2 1 0
start2 0|---*---*---|
- | /
- 1* /
- | /
- 2* /
- | /
- end2 3|
+ | /
+ 1* /
+ | /
+ 2* /
+ | /
+ end2 3|
We will fill this case like this or this depending on even or odd cuts
|---*---*---|
- | / / /
- * / /
- | / /
- * /
- | /
+ | / / /
+ * / /
+ | / /
+ * /
+ | /
|
*/
// Make outside tri
- hold = addfacelist(em, verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
+ hold = addfacelist(verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
+ facecopy(efa,hold);
// Make side faces
for(i=0;i<numcuts;i++) {
- hold = addfacelist(em, verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL);
+ hold = addfacelist(verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL);
hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- }
+ facecopy(efa,hold);
+ }
}
-static void fill_quad_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
+static void fill_quad_triple(EditFace *efa, struct GHash *gh, int numcuts)
{
EditEdge *cedge[3]={0};
EditVert *v[4], **verts[3];
EditFace *hold;
short start=0, start2=0, start3=0, vertsize, i, repeats;
-
+
v[0] = efa->v1;
v[1] = efa->v2;
v[2] = efa->v3;
- v[3] = efa->v4;
-
+ v[3] = efa->v4;
+
if(!(efa->e1->f & SELECT)) {
- cedge[0] = efa->e2;
- cedge[1] = efa->e3;
+ cedge[0] = efa->e2;
+ cedge[1] = efa->e3;
cedge[2] = efa->e4;
- start = 1;start2 = 2;start3 = 3;
+ start = 1;start2 = 2;start3 = 3;
}
if(!(efa->e2->f & SELECT)) {
- cedge[0] = efa->e3;
- cedge[1] = efa->e4;
+ cedge[0] = efa->e3;
+ cedge[1] = efa->e4;
cedge[2] = efa->e1;
- start = 2;start2 = 3;start3 = 0;
+ start = 2;start2 = 3;start3 = 0;
}
if(!(efa->e3->f & SELECT)) {
- cedge[0] = efa->e4;
- cedge[1] = efa->e1;
+ cedge[0] = efa->e4;
+ cedge[1] = efa->e1;
cedge[2] = efa->e2;
- start = 3;start2 = 0;start3 = 1;
+ start = 3;start2 = 0;start3 = 1;
}
if(!(efa->e4->f & SELECT)) {
- cedge[0] = efa->e1;
- cedge[1] = efa->e2;
+ cedge[0] = efa->e1;
+ cedge[1] = efa->e2;
cedge[2] = efa->e3;
- start = 0;start2 = 1;start3 = 2;
- }
+ start = 0;start2 = 1;start3 = 2;
+ }
// Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
verts[0] = BLI_ghash_lookup(gh, cedge[0]);
verts[1] = BLI_ghash_lookup(gh, cedge[1]);
verts[2] = BLI_ghash_lookup(gh, cedge[2]);
//This is the index size of the verts array
vertsize = numcuts+2;
-
+
// Is the original v1 the same as the first vert on the selected edge?
// if not, the edge is running the opposite direction in this face so flip
// the array to the correct direction
-
+
if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
- if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
- if(verts[2][0] != v[start3]) {flipvertarray(verts[2],numcuts+2);}
+ if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
+ if(verts[2][0] != v[start3]) {flipvertarray(verts[2],numcuts+2);}
/*
We should have something like this now
-
- start2
- 3 2 1 0
- start3 0|---*---*---|3
+
+ start2
+ 3 2 1 0
+ start3 0|---*---*---|3
| |
1* *2
| |
- 2* *1
+ 2* *1
| |
- 3|-----------|0 start
-
- We will fill this case like this or this depending on even or odd cuts
+ 3|-----------|0 start
+
+ We will fill this case like this or this depending on even or odd cuts
there are a couple of differences. For odd cuts, there is a tri in the
middle as well as 1 quad at the bottom (not including the extra quads
- for odd cuts > 1
-
+ for odd cuts > 1
+
For even cuts, there is a quad in the middle and 2 quads on the bottom
-
+
they are numbered here for clarity
-
+
1 outer tris and bottom quads
2 inner tri or quad
3 repeating quads
-
+
|---*---*---*---|
|1/ / \ \ 1|
|/ 3 / \ 3 \|
* / 2 \ *
| / \ |
- |/ \ |
+ |/ \ |
*---------------*
| 3 |
- | |
+ | |
*---------------*
| |
- | 1 |
+ | 1 |
| |
|---------------|
-
+
|---*---*---*---*---|
- | 1/ / \ \ 1|
- | / / \ \ |
+ | 1/ / \ \ 1|
+ | / / \ \ |
|/ 3 / \ 3 \|
* / \ *
- | / \ |
- | / 2 \ |
+ | / \ |
+ | / 2 \ |
|/ \|
*-------------------*
| |
| 3 |
- | |
+ | |
*-------------------*
| |
| 1 |
- | |
+ | |
*-------------------*
| |
| 1 |
- | |
+ | |
|-------------------|
-
+
*/
// Make outside tris
- hold = addfacelist(em, verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
+ hold = addfacelist(verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- hold = addfacelist(em, verts[1][vertsize-2],verts[1][vertsize-1],verts[2][1],NULL,NULL,NULL);
+ facecopy(efa,hold);
+ hold = addfacelist(verts[1][vertsize-2],verts[1][vertsize-1],verts[2][1],NULL,NULL,NULL);
hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
+ facecopy(efa,hold);
// Make bottom quad
- hold = addfacelist(em, verts[0][0],verts[0][1],verts[2][vertsize-2],verts[2][vertsize-1],NULL,NULL);
+ hold = addfacelist(verts[0][0],verts[0][1],verts[2][vertsize-2],verts[2][vertsize-1],NULL,NULL);
hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
+ facecopy(efa,hold);
//If it is even cuts, add the 2nd lower quad
if(numcuts % 2 == 0) {
- hold = addfacelist(em, verts[0][1],verts[0][2],verts[2][vertsize-3],verts[2][vertsize-2],NULL,NULL);
+ hold = addfacelist(verts[0][1],verts[0][2],verts[2][vertsize-3],verts[2][vertsize-2],NULL,NULL);
hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
+ facecopy(efa,hold);
// Also Make inner quad
- hold = addfacelist(em, verts[1][numcuts/2],verts[1][(numcuts/2)+1],verts[2][numcuts/2],verts[0][(numcuts/2)+1],NULL,NULL);
+ hold = addfacelist(verts[1][numcuts/2],verts[1][(numcuts/2)+1],verts[2][numcuts/2],verts[0][(numcuts/2)+1],NULL,NULL);
hold->e3->f2 |= EDGEINNER;
- //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
+ //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) {
// hold->e3->h |= EM_FGON;
//}
- facecopy(em, efa,hold);
+ facecopy(efa,hold);
repeats = (numcuts / 2) -1;
} else {
- // Make inner tri
- hold = addfacelist(em, verts[1][(numcuts/2)+1],verts[2][(numcuts/2)+1],verts[0][(numcuts/2)+1],NULL,NULL,NULL);
+ // Make inner tri
+ hold = addfacelist(verts[1][(numcuts/2)+1],verts[2][(numcuts/2)+1],verts[0][(numcuts/2)+1],NULL,NULL,NULL);
hold->e2->f2 |= EDGEINNER;
- //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
+ //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) {
// hold->e2->h |= EM_FGON;
//}
- facecopy(em, efa,hold);
+ facecopy(efa,hold);
repeats = ((numcuts+1) / 2)-1;
}
-
+
// cuts for 1 and 2 do not have the repeating quads
if(numcuts < 3) {repeats = 0;}
for(i=0;i<repeats;i++) {
//Make side repeating Quads
- hold = addfacelist(em, verts[1][i+1],verts[1][i+2],verts[0][vertsize-i-3],verts[0][vertsize-i-2],NULL,NULL);
- hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- hold = addfacelist(em, verts[1][vertsize-i-3],verts[1][vertsize-i-2],verts[2][i+1],verts[2][i+2],NULL,NULL);
+ hold = addfacelist(verts[1][i+1],verts[1][i+2],verts[0][vertsize-i-3],verts[0][vertsize-i-2],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ hold = addfacelist(verts[1][vertsize-i-3],verts[1][vertsize-i-2],verts[2][i+1],verts[2][i+2],NULL,NULL);
hold->e4->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
+ facecopy(efa,hold);
}
- // Do repeating bottom quads
+ // Do repeating bottom quads
for(i=0;i<repeats;i++) {
- if(numcuts % 2 == 1) {
- hold = addfacelist(em, verts[0][1+i],verts[0][2+i],verts[2][vertsize-3-i],verts[2][vertsize-2-i],NULL,NULL);
+ if(numcuts % 2 == 1) {
+ hold = addfacelist(verts[0][1+i],verts[0][2+i],verts[2][vertsize-3-i],verts[2][vertsize-2-i],NULL,NULL);
} else {
- hold = addfacelist(em, verts[0][2+i],verts[0][3+i],verts[2][vertsize-4-i],verts[2][vertsize-3-i],NULL,NULL);
+ hold = addfacelist(verts[0][2+i],verts[0][3+i],verts[2][vertsize-4-i],verts[2][vertsize-3-i],NULL,NULL);
}
hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- }
- //EM_fgon_flags(em);
+ facecopy(efa,hold);
+ }
+ //EM_fgon_flags();
}
-static void fill_quad_quadruple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, float smooth, float fractal, int beauty)
+static void fill_quad_quadruple(EditFace *efa, struct GHash *gh, int numcuts, float rad, int beauty)
{
EditVert **verts[4], ***innerverts;
- EditFace *hold;
+ EditFace *hold;
EditEdge temp;
short vertsize, i, j;
-
+
// Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
verts[0] = BLI_ghash_lookup(gh, efa->e1);
verts[1] = BLI_ghash_lookup(gh, efa->e2);
@@ -2300,87 +2077,87 @@ static void fill_quad_quadruple(EditMesh *em, EditFace *efa, struct GHash *gh, i
// the array to the correct direction
if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);}
- if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);}
+ if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);}
if(verts[2][0] == efa->v3) {flipvertarray(verts[2],numcuts+2);}
- if(verts[3][0] == efa->v4) {flipvertarray(verts[3],numcuts+2);}
+ if(verts[3][0] == efa->v4) {flipvertarray(verts[3],numcuts+2);}
/*
We should have something like this now
1
-
- 3 2 1 0
- 0|---*---*---|0
+
+ 3 2 1 0
+ 0|---*---*---|0
| |
1* *1
- 2 | | 4
- 2* *2
+ 2 | | 4
+ 2* *2
| |
- 3|---*---*---|3
+ 3|---*---*---|3
3 2 1 0
3
// we will fill a 2 dim array of editvert*s to make filling easier
// the innervert order is shown
- 0 0---1---2---3
+ 0 0---1---2---3
| | | |
- 1 0---1---2---3
+ 1 0---1---2---3
| | | |
- 2 0---1---2---3
+ 2 0---1---2---3
| | | |
- 3 0---1---2---3
-
+ 3 0---1---2---3
+
*/
- innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts outer array");
+ innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts outer array");
for(i=0;i<numcuts+2;i++) {
innerverts[i] = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts inner array");
- }
-
+ }
+
// first row is e1 last row is e3
for(i=0;i<numcuts+2;i++) {
innerverts[0][i] = verts[0][(numcuts+1)-i];
innerverts[numcuts+1][i] = verts[2][(numcuts+1)-i];
}
-
+
for(i=1;i<=numcuts;i++) {
/* we create a fake edge for the next loop */
temp.v2 = innerverts[i][0] = verts[1][i];
temp.v1 = innerverts[i][numcuts+1] = verts[3][i];
-
- for(j=1;j<=numcuts;j++) {
+
+ for(j=1;j<=numcuts;j++) {
float percent= (float)j/(float)(numcuts+1);
- innerverts[i][(numcuts+1)-j]= subdivide_edge_addvert(em, &temp, smooth, fractal, beauty, percent);
- }
- }
+ innerverts[i][(numcuts+1)-j]= subdivide_edge_addvert(&temp, rad, beauty, percent);
+ }
+ }
// Fill with faces
for(i=0;i<numcuts+1;i++) {
for(j=0;j<numcuts+1;j++) {
- hold = addfacelist(em, innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],innerverts[i+1][j+1],NULL,NULL);
- hold->e1->f2 = EDGENEW;
- hold->e2->f2 = EDGENEW;
- hold->e3->f2 = EDGENEW;
- hold->e4->f2 = EDGENEW;
-
+ hold = addfacelist(innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],innerverts[i+1][j+1],NULL,NULL);
+ hold->e1->f2 = EDGENEW;
+ hold->e2->f2 = EDGENEW;
+ hold->e3->f2 = EDGENEW;
+ hold->e4->f2 = EDGENEW;
+
if(i != 0) { hold->e1->f2 |= EDGEINNER; }
if(j != 0) { hold->e2->f2 |= EDGEINNER; }
if(i != numcuts) { hold->e3->f2 |= EDGEINNER; }
if(j != numcuts) { hold->e4->f2 |= EDGEINNER; }
-
- facecopy(em, efa,hold);
- }
+
+ facecopy(efa,hold);
+ }
}
// Clean up our dynamic multi-dim array
for(i=0;i<numcuts+2;i++) {
- MEM_freeN(innerverts[i]);
- }
+ MEM_freeN(innerverts[i]);
+ }
MEM_freeN(innerverts);
}
-static void fill_tri_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, float smooth, float fractal, int beauty)
+static void fill_tri_triple(EditFace *efa, struct GHash *gh, int numcuts, float rad, int beauty)
{
EditVert **verts[3], ***innerverts;
short vertsize, i, j;
- EditFace *hold;
+ EditFace *hold;
EditEdge temp;
// Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
@@ -2396,20 +2173,20 @@ static void fill_tri_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int n
// the array to the correct direction
if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);}
- if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);}
- if(verts[2][0] != efa->v3) {flipvertarray(verts[2],numcuts+2);}
+ if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);}
+ if(verts[2][0] != efa->v3) {flipvertarray(verts[2],numcuts+2);}
/*
We should have something like this now
3
-
- 3 2 1 0
- 0|---*---*---|3
- | /
- 1 1* *2
- | /
- 2* *1 2
- | /
- 3|/
+
+ 3 2 1 0
+ 0|---*---*---|3
+ | /
+ 1 1* *2
+ | /
+ 2* *1 2
+ | /
+ 3|/
0
we will fill a 2 dim array of editvert*s to make filling easier
@@ -2417,75 +2194,74 @@ static void fill_tri_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int n
3
0 0---1---2---3---4
- | / | / |/ | /
- 1 0---1----2---3
- 1 | / | / | /
+ | / | / |/ | /
+ 1 0---1----2---3
+ 1 | / | / | /
2 0----1---2 2
- | / | /
- |/ |/
- 3 0---1
+ | / | /
+ |/ |/
+ 3 0---1
| /
|/
- 4 0
-
+ 4 0
+
*/
-
- innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"tri-tri subdiv inner verts outer array");
+
+ innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"tri-tri subdiv inner verts outer array");
for(i=0;i<numcuts+2;i++) {
innerverts[i] = MEM_mallocN(sizeof(EditVert*)*((numcuts+2)-i),"tri-tri subdiv inner verts inner array");
}
//top row is e3 backwards
for(i=0;i<numcuts+2;i++) {
innerverts[0][i] = verts[2][(numcuts+1)-i];
- }
-
+ }
+
for(i=1;i<=numcuts+1;i++) {
//fake edge, first vert is from e1, last is from e2
temp.v1= innerverts[i][0] = verts[0][i];
temp.v2= innerverts[i][(numcuts+1)-i] = verts[1][(numcuts+1)-i];
-
+
for(j=1;j<(numcuts+1)-i;j++) {
float percent= (float)j/(float)((numcuts+1)-i);
- innerverts[i][((numcuts+1)-i)-j]= subdivide_edge_addvert(em, &temp, smooth, fractal, beauty, 1-percent);
+ innerverts[i][((numcuts+1)-i)-j]= subdivide_edge_addvert(&temp, rad, beauty, 1-percent);
}
}
// Now fill the verts with happy little tris :)
for(i=0;i<=numcuts+1;i++) {
- for(j=0;j<(numcuts+1)-i;j++) {
+ for(j=0;j<(numcuts+1)-i;j++) {
//We always do the first tri
- hold = addfacelist(em, innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],NULL,NULL,NULL);
- hold->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
+ hold = addfacelist(innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],NULL,NULL,NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
if(i != 0) { hold->e1->f2 |= EDGEINNER; }
if(j != 0) { hold->e2->f2 |= EDGEINNER; }
if(j+1 != (numcuts+1)-i) {hold->e3->f2 |= EDGEINNER;}
-
- facecopy(em, efa,hold);
- //if there are more to come, we do the 2nd
+
+ facecopy(efa,hold);
+ //if there are more to come, we do the 2nd
if(j+1 <= numcuts-i) {
- hold = addfacelist(em, innerverts[i+1][j],innerverts[i+1][j+1],innerverts[i][j+1],NULL,NULL,NULL);
- facecopy(em, efa,hold);
- hold->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
+ hold = addfacelist(innerverts[i+1][j],innerverts[i+1][j+1],innerverts[i][j+1],NULL,NULL,NULL);
+ facecopy(efa,hold);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
}
- }
+ }
}
// Clean up our dynamic multi-dim array
for(i=0;i<numcuts+2;i++) {
- MEM_freeN(innerverts[i]);
- }
+ MEM_freeN(innerverts[i]);
+ }
MEM_freeN(innerverts);
}
//Next two fill types are for knife exact only and are provided to allow for knifing through vertices
//This means there is no multicut!
-static void fill_quad_doublevert(EditMesh *em, EditFace *efa, int v1, int v2)
-{
+static void fill_quad_doublevert(EditFace *efa, int v1, int v2){
EditFace *hold;
/*
Depending on which two vertices have been knifed through (v1 and v2), we
@@ -2496,55 +2272,55 @@ static void fill_quad_doublevert(EditMesh *em, EditFace *efa, int v1, int v2)
| \ | | / |
--------X X--------
*/
-
+
if(v1 == 1 && v2 == 3){
- hold= addfacelist(em, efa->v1, efa->v2, efa->v3, 0, efa, NULL);
+ hold= addfacelist(efa->v1, efa->v2, efa->v3, 0, efa, NULL);
hold->e1->f2 |= EDGENEW;
hold->e2->f2 |= EDGENEW;
hold->e3->f2 |= EDGENEW;
hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
-
- hold= addfacelist(em, efa->v1, efa->v3, efa->v4, 0, efa, NULL);
+ facecopy(efa, hold);
+
+ hold= addfacelist(efa->v1, efa->v3, efa->v4, 0, efa, NULL);
hold->e1->f2 |= EDGENEW;
hold->e2->f2 |= EDGENEW;
hold->e3->f2 |= EDGENEW;
hold->e1->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
+ facecopy(efa, hold);
}
else{
- hold= addfacelist(em, efa->v1, efa->v2, efa->v4, 0, efa, NULL);
+ hold= addfacelist(efa->v1, efa->v2, efa->v4, 0, efa, NULL);
hold->e1->f2 |= EDGENEW;
hold->e2->f2 |= EDGENEW;
hold->e3->f2 |= EDGENEW;
hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
-
- hold= addfacelist(em, efa->v2, efa->v3, efa->v4, 0, efa, NULL);
+ facecopy(efa, hold);
+
+ hold= addfacelist(efa->v2, efa->v3, efa->v4, 0, efa, NULL);
hold->e1->f2 |= EDGENEW;
hold->e2->f2 |= EDGENEW;
hold->e3->f2 |= EDGENEW;
hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
+ facecopy(efa, hold);
}
}
-static void fill_quad_singlevert(EditMesh *em, EditFace *efa, struct GHash *gh)
+static void fill_quad_singlevert(EditFace *efa, struct GHash *gh)
{
EditEdge *cedge=NULL;
EditVert *v[4], **verts;
EditFace *hold;
- short start=0, end, left, right, vertsize;
-
+ short start=0, end, left, right, vertsize;
+
v[0] = efa->v1;
v[1] = efa->v2;
v[2] = efa->v3;
- v[3] = efa->v4;
+ v[3] = efa->v4;
if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;}
- else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;}
- else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;}
- else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;}
+ else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;}
+ else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;}
+ else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;}
// Point verts to the array of new verts for cedge
verts = BLI_ghash_lookup(gh, cedge);
@@ -2558,25 +2334,25 @@ static void fill_quad_singlevert(EditMesh *em, EditFace *efa, struct GHash *gh)
if(verts[0] != v[start]) {flipvertarray(verts,3);}
end = (start+1)%4;
left = (start+2)%4;
- right = (start+3)%4;
+ right = (start+3)%4;
/*
We should have something like this now
- end start
- 2 1 0
+ end start
+ 2 1 0
|-----*-----|
| |
+ | |
| |
- | |
- -------------
+ -------------
left right
where start,end,left, right are indexes of EditFace->v1, etc (stored in v)
and 0,1,2 are the indexes of the new verts stored in verts. We fill like
this, depending on whether its vertex 'left' or vertex 'right' thats
been knifed through...
-
+
|---*---| |---*---|
| / | | \ |
| / | | \ |
@@ -2586,72 +2362,111 @@ static void fill_quad_singlevert(EditMesh *em, EditFace *efa, struct GHash *gh)
if(v[left]->f1){
//triangle is composed of cutvert, end and left
- hold = addfacelist(em, verts[1],v[end],v[left],NULL, NULL,NULL);
+ hold = addfacelist(verts[1],v[end],v[left],NULL, NULL,NULL);
hold->e1->f2 |= EDGENEW;
hold->e2->f2 |= EDGENEW;
hold->e3->f2 |= EDGENEW;
hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
-
+ facecopy(efa, hold);
+
//quad is composed of cutvert, left, right and start
- hold = addfacelist(em, verts[1],v[left],v[right],v[start], NULL, NULL);
+ hold = addfacelist(verts[1],v[left],v[right],v[start], NULL, NULL);
hold->e1->f2 |= EDGENEW;
hold->e2->f2 |= EDGENEW;
hold->e3->f2 |= EDGENEW;
hold->e4->f2 |= EDGENEW;
hold->e1->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
+ facecopy(efa, hold);
}
else if(v[right]->f1){
//triangle is composed of cutvert, right and start
- hold = addfacelist(em, verts[1],v[right],v[start], NULL, NULL, NULL);
+ hold = addfacelist(verts[1],v[right],v[start], NULL, NULL, NULL);
hold->e1->f2 |= EDGENEW;
hold->e2->f2 |= EDGENEW;
hold->e3->f2 |= EDGENEW;
hold->e1->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
+ facecopy(efa, hold);
//quad is composed of cutvert, end, left, right
- hold = addfacelist(em, verts[1],v[end], v[left], v[right], NULL, NULL);
+ hold = addfacelist(verts[1],v[end], v[left], v[right], NULL, NULL);
hold->e1->f2 |= EDGENEW;
hold->e2->f2 |= EDGENEW;
hold->e3->f2 |= EDGENEW;
hold->e4->f2 |= EDGENEW;
hold->e4->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
+ facecopy(efa, hold);
}
+
+}
-}
-
-// This function takes an example edge, the current point to create and
+// This function takes an example edge, the current point to create and
// the total # of points to create, then creates the point and return the
// editvert pointer to it.
-static EditVert *subdivideedgenum(EditMesh *em, EditEdge *edge, int curpoint, int totpoint, float smooth, float fractal, int beauty)
+static EditVert *subdivideedgenum(EditEdge *edge, int curpoint, int totpoint, float rad, int beauty)
{
EditVert *ev;
float percent;
-
+
if (beauty & (B_PERCENTSUBD) && totpoint == 1)
//percent=(float)(edge->tmp.l)/32768.0f;
percent= edge->tmp.fp;
else
percent= (float)curpoint/(float)(totpoint+1);
- ev= subdivide_edge_addvert(em, edge, smooth, fractal, beauty, percent);
+ ev= subdivide_edge_addvert(edge, rad, beauty, percent);
ev->f = edge->v1->f;
-
+
return ev;
}
-void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float fractal, int beauty, int numcuts, int corner_pattern, int seltype)
+#if 1
+#include "bmesh.h"
+
+void esubdivideflag(int flag, float rad, int beauty, int numcuts, int seltype)
+{
+ BMesh *bm;
+ BMOperator subdop, conv;
+ EditMesh *em = G.editMesh;
+ BMEdge **list, *bed;
+ BMIter iter;
+ int tot;
+
+ /*convert from editmesh*/
+ bm = editmesh_to_bmesh(G.editMesh);
+
+ BMO_Init_Op(&subdop, BMOP_ESUBDIVIDE);
+ for (tot=0, bed=BMIter_New(&iter, bm, BM_EDGES, NULL); bed; bed=BMIter_Step(&iter)) {
+ if (BM_Selected(bm, bed)) tot++;
+ }
+
+ list = MEM_callocN(sizeof(void*)*tot, "vert ptr list");
+
+ for (tot=0, bed=BMIter_New(&iter, bm, BM_EDGES, NULL); bed; bed=BMIter_Step(&iter)) {
+ if (BM_Selected(bm, bed)) list[tot++] = bed;
+ }
+
+ BMO_Set_PntBuf(&subdop, BMOP_ESUBDIVIDE_EDGES, list, tot);
+ BMO_Exec_Op(bm, &subdop);
+ BMO_Finish_Op(bm, &subdop);
+
+ free_editMesh(G.editMesh);
+ bmesh_to_editmesh(bm);
+ BM_Free_Mesh(bm);
+
+ if (list) MEM_freeN(list);
+}
+#else
+void esubdivideflag(int flag, float rad, int beauty, int numcuts, int seltype)
{
+ EditMesh *em = G.editMesh;
EditFace *ef;
EditEdge *eed, *cedge, *sort[4];
EditVert *eve, **templist;
struct GHash *gh;
float length[4], v1mat[3], v2mat[3], v3mat[3], v4mat[3];
int i, j, edgecount, touchcount, facetype,hold;
- ModifierData *md= obedit->modifiers.first;
- int ctrl= 0; // XXX
+ ModifierData *md= G.obedit->modifiers.first;
+
+ if(multires_test()) return;
//Set faces f1 to 0 cause we need it later
for(ef=em->faces.first;ef;ef = ef->next) ef->f1 = 0;
@@ -2663,8 +2478,8 @@ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float
for (; md; md=md->next) {
if (md->type==eModifierType_Mirror) {
- MirrorModifierData *mmd = (MirrorModifierData*) md;
-
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
if(mmd->flag & MOD_MIR_CLIPPING) {
for (eve= em->verts.first; eve; eve= eve->next) {
eve->f2= 0;
@@ -2686,23 +2501,23 @@ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float
}
}
}
-
+
//Flush vertex flags upward to the edges
for(eed = em->edges.first;eed;eed = eed->next) {
//if(eed->f & flag && eed->v1->f == eed->v2->f) {
- // eed->f |= eed->v1->f;
+ // eed->f |= eed->v1->f;
// }
- eed->f2 = 0;
+ eed->f2 = 0;
if(eed->f & flag) {
eed->f2 |= EDGEOLD;
}
}
-
+
// We store an array of verts for each edge that is subdivided,
// we put this array as a value in a ghash which is keyed by the EditEdge*
// Now for beauty subdivide deselect edges based on length
- if(beauty & B_BEAUTY) {
+ if(beauty & B_BEAUTY) {
for(ef = em->faces.first;ef;ef = ef->next) {
if(!ef->v4) {
continue;
@@ -2711,12 +2526,12 @@ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float
VECCOPY(v1mat, ef->v1->co);
VECCOPY(v2mat, ef->v2->co);
VECCOPY(v3mat, ef->v3->co);
- VECCOPY(v4mat, ef->v4->co);
- mul_mat3_m4_v3(obedit->obmat, v1mat);
- mul_mat3_m4_v3(obedit->obmat, v2mat);
- mul_mat3_m4_v3(obedit->obmat, v3mat);
- mul_mat3_m4_v3(obedit->obmat, v4mat);
-
+ VECCOPY(v4mat, ef->v4->co);
+ mul_mat3_m4_v3(G.obedit->obmat, v1mat);
+ mul_mat3_m4_v3(G.obedit->obmat, v2mat);
+ mul_mat3_m4_v3(G.obedit->obmat, v3mat);
+ mul_mat3_m4_v3(G.obedit->obmat, v4mat);
+
length[0] = len_v3v3(v1mat, v2mat);
length[1] = len_v3v3(v2mat, v3mat);
length[2] = len_v3v3(v3mat, v4mat);
@@ -2725,69 +2540,65 @@ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float
sort[1] = ef->e2;
sort[2] = ef->e3;
sort[3] = ef->e4;
-
-
+
+
// Beauty Short Edges
if(beauty & B_BEAUTY_SHORT) {
for(j=0;j<2;j++) {
hold = -1;
for(i=0;i<4;i++) {
if(length[i] < 0) {
- continue;
- } else if(hold == -1) {
- hold = i;
+ continue;
+ } else if(hold == -1) {
+ hold = i;
} else {
if(length[hold] < length[i]) {
- hold = i;
+ hold = i;
}
}
}
- if (hold > -1) {
- sort[hold]->f &= ~SELECT;
- sort[hold]->f2 |= EDGENEW;
- length[hold] = -1;
- }
- }
- }
-
+ sort[hold]->f &= ~SELECT;
+ sort[hold]->f2 |= EDGENEW;
+ length[hold] = -1;
+ }
+ }
+
// Beauty Long Edges
else {
for(j=0;j<2;j++) {
hold = -1;
for(i=0;i<4;i++) {
if(length[i] < 0) {
- continue;
- } else if(hold == -1) {
- hold = i;
+ continue;
+ } else if(hold == -1) {
+ hold = i;
} else {
if(length[hold] > length[i]) {
- hold = i;
+ hold = i;
}
}
}
- if (hold > -1) {
- sort[hold]->f &= ~SELECT;
- sort[hold]->f2 |= EDGENEW;
- length[hold] = -1;
- }
- }
- }
+ sort[hold]->f &= ~SELECT;
+ sort[hold]->f2 |= EDGENEW;
+ length[hold] = -1;
+ }
+ }
}
- }
+ }
}
- gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "subdivideedgenum gh");
+ gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
// If we are knifing, We only need the selected edges that were cut, so deselect if it was not cut
- if(beauty & B_KNIFE) {
- for(eed= em->edges.first;eed;eed=eed->next) {
+ if(beauty & B_KNIFE) {
+ for(eed= em->edges.first;eed;eed=eed->next) {
if( eed->tmp.fp == 0 ) {
EM_select_edge(eed,0);
}
}
- }
+ }
// So for each edge, if it is selected, we allocate an array of size cuts+2
- // so we can have a place for the v1, the new verts and v2
+ // so we can have a place for the v1, the new verts and v2
for(eed=em->edges.first;eed;eed = eed->next) {
if(eed->f & flag) {
templist = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"vertlist");
@@ -2795,22 +2606,22 @@ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float
for(i=0;i<numcuts;i++) {
// This function creates the new vert and returns it back
// to the array
- templist[i+1] = subdivideedgenum(em, eed, i+1, numcuts, smooth, fractal, beauty);
+ templist[i+1] = subdivideedgenum(eed, i+1, numcuts, rad, beauty);
//while we are here, we can copy edge info from the original edge
- cedge = addedgelist(em, templist[i],templist[i+1],eed);
+ cedge = addedgelist(templist[i],templist[i+1],eed);
// Also set the edge f2 to EDGENEW so that we can use this info later
cedge->f2 = EDGENEW;
}
templist[i+1] = eed->v2;
//Do the last edge too
- cedge = addedgelist(em, templist[i],templist[i+1],eed);
+ cedge = addedgelist(templist[i],templist[i+1],eed);
cedge->f2 = EDGENEW;
- // Now that the edge is subdivided, we can put its verts in the ghash
- BLI_ghash_insert(gh, eed, templist);
- }
+ // Now that the edge is subdivided, we can put its verts in the ghash
+ BLI_ghash_insert(gh, eed, templist);
+ }
}
-// DAG_id_tag_update(obedit->data, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
// Now for each face in the mesh we need to figure out How many edges were cut
// and which filling method to use for that face
for(ef = em->faces.first;ef;ef = ef->next) {
@@ -2822,7 +2633,7 @@ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float
if(ef->v4) {
facetype = 4;
if(ef->e4->f & flag) {edgecount++;}
- }
+ }
if(facetype == 4) {
switch(edgecount) {
case 0:
@@ -2834,19 +2645,19 @@ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float
if(ef->v3->f1) touchcount++;
if(ef->v4->f1) touchcount++;
if(touchcount == 2){
- if(ef->v1->f1 && ef->v3->f1){
+ if(ef->v1->f1 && ef->v3->f1){
ef->f1 = SELECT;
- fill_quad_doublevert(em, ef, 1, 3);
+ fill_quad_doublevert(ef, 1, 3);
}
else if(ef->v2->f1 && ef->v4->f1){
ef->f1 = SELECT;
- fill_quad_doublevert(em, ef, 2, 4);
+ fill_quad_doublevert(ef, 2, 4);
}
}
}
- break;
-
- case 1:
+ break;
+
+ case 1:
if(beauty & B_KNIFE && numcuts == 1){
/*Test for when knifing through an edge and one vert*/
touchcount = 0;
@@ -2854,87 +2665,87 @@ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float
if(ef->v2->f1) touchcount++;
if(ef->v3->f1) touchcount++;
if(ef->v4->f1) touchcount++;
-
+
if(touchcount == 1){
if( (ef->e1->f & flag && ( !ef->e1->v1->f1 && !ef->e1->v2->f1 )) ||
(ef->e2->f & flag && ( !ef->e2->v1->f1 && !ef->e2->v2->f1 )) ||
(ef->e3->f & flag && ( !ef->e3->v1->f1 && !ef->e3->v2->f1 )) ||
(ef->e4->f & flag && ( !ef->e4->v1->f1 && !ef->e4->v2->f1 )) ){
-
- ef->f1 = SELECT;
- fill_quad_singlevert(em, ef, gh);
+
+ ef->f1 = SELECT;
+ fill_quad_singlevert(ef, gh);
}
else{
ef->f1 = SELECT;
- fill_quad_single(em, ef, gh, numcuts, seltype);
+ fill_quad_single(ef, gh, numcuts, seltype);
}
}
- else{
- ef->f1 = SELECT;
- fill_quad_single(em, ef, gh, numcuts, seltype);
+ else{
+ ef->f1 = SELECT;
+ fill_quad_single(ef, gh, numcuts, seltype);
}
}
- else{
+ else{
ef->f1 = SELECT;
- fill_quad_single(em, ef, gh, numcuts, seltype);
+ fill_quad_single(ef, gh, numcuts, seltype);
}
- break;
+ break;
case 2: ef->f1 = SELECT;
// if there are 2, we check if edge 1 and 3 are either both on or off that way
// we can tell if the selected pair is Adjacent or Opposite of each other
- if((ef->e1->f & flag && ef->e3->f & flag) ||
+ if((ef->e1->f & flag && ef->e3->f & flag) ||
(ef->e2->f & flag && ef->e4->f & flag)) {
- fill_quad_double_op(em, ef, gh, numcuts);
+ fill_quad_double_op(ef, gh, numcuts);
}else{
- switch(corner_pattern) {
- case 0: fill_quad_double_adj_path(em, ef, gh, numcuts); break;
- case 1: fill_quad_double_adj_inner(em, ef, gh, numcuts); break;
- case 2: fill_quad_double_adj_fan(em, ef, gh, numcuts); break;
+ switch(G.scene->toolsettings->cornertype) {
+ case 0: fill_quad_double_adj_path(ef, gh, numcuts); break;
+ case 1: fill_quad_double_adj_inner(ef, gh, numcuts); break;
+ case 2: fill_quad_double_adj_fan(ef, gh, numcuts); break;
}
-
+
}
- break;
+ break;
case 3: ef->f1 = SELECT;
- fill_quad_triple(em, ef, gh, numcuts);
- break;
+ fill_quad_triple(ef, gh, numcuts);
+ break;
case 4: ef->f1 = SELECT;
- fill_quad_quadruple(em, ef, gh, numcuts, smooth, fractal, beauty);
- break;
+ fill_quad_quadruple(ef, gh, numcuts, rad, beauty);
+ break;
}
} else {
switch(edgecount) {
case 0: break;
case 1: ef->f1 = SELECT;
- fill_tri_single(em, ef, gh, numcuts, seltype);
- break;
+ fill_tri_single(ef, gh, numcuts, seltype);
+ break;
case 2: ef->f1 = SELECT;
- fill_tri_double(em, ef, gh, numcuts);
- break;
+ fill_tri_double(ef, gh, numcuts);
+ break;
case 3: ef->f1 = SELECT;
- fill_tri_triple(em, ef, gh, numcuts, smooth, fractal, beauty);
- break;
- }
- }
+ fill_tri_triple(ef, gh, numcuts, rad, beauty);
+ break;
+ }
+ }
}
-
+
// Delete Old Edges and Faces
for(eed = em->edges.first;eed;eed = eed->next) {
if(BLI_ghash_haskey(gh,eed)) {
- eed->f1 = SELECT;
+ eed->f1 = SELECT;
} else {
- eed->f1 = 0;
+ eed->f1 = 0;
}
- }
- free_tagged_edges_faces(em, em->edges.first, em->faces.first);
-
- if(seltype == SUBDIV_SELECT_ORIG && !ctrl) {
+ }
+ free_tagged_edges_faces(em->edges.first, em->faces.first);
+
+ if(seltype == SUBDIV_SELECT_ORIG && G.qual != LR_CTRLKEY) {
/* bugfix: vertex could get flagged as "not-selected"
// solution: clear flags before, not at the same time as setting SELECT flag -dg
*/
for(eed = em->edges.first;eed;eed = eed->next) {
if(!(eed->f2 & EDGENEW || eed->f2 & EDGEOLD)) {
eed->f &= !flag;
- EM_select_edge(eed,0);
+ EM_select_edge(eed,0);
}
}
for(eed = em->edges.first;eed;eed = eed->next) {
@@ -2943,18 +2754,18 @@ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float
EM_select_edge(eed,1);
}
}
- } else if ((seltype == SUBDIV_SELECT_INNER || seltype == SUBDIV_SELECT_INNER_SEL)|| ctrl) {
+ } else if ((seltype == SUBDIV_SELECT_INNER || seltype == SUBDIV_SELECT_INNER_SEL)|| G.qual == LR_CTRLKEY) {
for(eed = em->edges.first;eed;eed = eed->next) {
if(eed->f2 & EDGEINNER) {
eed->f |= flag;
- EM_select_edge(eed,1);
+ EM_select_edge(eed,1);
if(eed->v1->f & EDGEINNER) eed->v1->f |= SELECT;
if(eed->v2->f & EDGEINNER) eed->v2->f |= SELECT;
}else{
eed->f &= !flag;
- EM_select_edge(eed,0);
+ EM_select_edge(eed,0);
}
- }
+ }
} else if(seltype == SUBDIV_SELECT_LOOPCUT){
for(eed = em->edges.first;eed;eed = eed->next) {
if(eed->f2 & DOUBLEOPFILL){
@@ -2965,16 +2776,16 @@ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float
EM_select_edge(eed,0);
}
}
- }
- if(em->selectmode & SCE_SELECT_VERTEX) {
+ }
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
for(eed = em->edges.first;eed;eed = eed->next) {
if(eed->f & SELECT) {
eed->v1->f |= SELECT;
eed->v2->f |= SELECT;
}
- }
+ }
}
-
+
//fix hide flags for edges. First pass, hide edges of hidden faces
for(ef=em->faces.first; ef; ef=ef->next){
if(ef->h){
@@ -2993,34 +2804,31 @@ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float
if(ef->e4) ef->e4->h &= ~1;
}
}
-
- //third pass: unhide edges that have both verts visible
- //(these were missed if all faces were hidden, bug #21976)
- for(eed=em->edges.first; eed; eed=eed->next){
- if(eed->v1->h == 0 && eed->v2->h == 0)
- eed->h &= ~1;
- }
-
- // Free the ghash and call MEM_freeN on all the value entries to return
+
+ // Free the ghash and call MEM_freeN on all the value entries to return
// that memory
- BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
-
- EM_selectmode_flush(em);
+ BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
+
+ EM_selectmode_flush();
for(ef=em->faces.first;ef;ef = ef->next) {
if(ef->e4) {
if( (ef->e1->f & SELECT && ef->e2->f & SELECT) &&
(ef->e3->f & SELECT && ef->e4->f & SELECT) ) {
- ef->f |= SELECT;
- }
+ ef->f |= SELECT;
+ }
} else {
if( (ef->e1->f & SELECT && ef->e2->f & SELECT) && ef->e3->f & SELECT) {
- ef->f |= SELECT;
+ ef->f |= SELECT;
}
}
}
-
- recalc_editnormals(em);
+
+ recalc_editnormals();
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
}
+#endif
static int count_selected_edges(EditEdge *ed)
{
@@ -3057,15 +2865,15 @@ static int collect_quadedges(EVPTuple *efaa, EditEdge *eed, EditFace *efa)
i++;
}
else eed->tmp.p = NULL;
-
+
eed= eed->next;
}
-
-
+
+
/* find edges pointing to 2 faces by procedure:
-
+
- run through faces and their edges, increase
- face counter e->f1 for each face
+ face counter e->f1 for each face
*/
while(efa) {
@@ -3110,20 +2918,20 @@ static int collect_quadedges(EVPTuple *efaa, EditEdge *eed, EditFace *efa)
}
-/* returns vertices of two adjacent triangles forming a quad
+/* returns vertices of two adjacent triangles forming a quad
- can be righthand or lefthand
4-----3
|\ |
| \ 2 | <- efa1
- | \ |
- efa-> | 1 \ |
- | \|
+ | \ |
+ efa-> | 1 \ |
+ | \|
1-----2
*/
#define VTEST(face, num, other) \
- (face->v##num != other->v1 && face->v##num != other->v2 && face->v##num != other->v3)
+ (face->v##num != other->v1 && face->v##num != other->v2 && face->v##num != other->v3)
static void givequadverts(EditFace *efa, EditFace *efa1, EditVert **v1, EditVert **v2, EditVert **v3, EditVert **v4, int *vindex)
{
@@ -3145,24 +2953,24 @@ static void givequadverts(EditFace *efa, EditFace *efa1, EditVert **v1, EditVert
vindex[0]= 2;
vindex[1]= 0;
}
-
+
if VTEST(efa1, 1, efa) {
*v3= efa1->v1;
- *v4= (efa1->v2 == *v2)? efa1->v3: efa1->v2;
+ *v4= efa1->v2;
vindex[2]= 0;
- vindex[3]= (efa1->v2 == *v2)? 2: 1;
+ vindex[3]= 1;
}
else if VTEST(efa1, 2, efa) {
*v3= efa1->v2;
- *v4= (efa1->v3 == *v2)? efa1->v1: efa1->v3;
+ *v4= efa1->v3;
vindex[2]= 1;
- vindex[3]= (efa1->v3 == *v2)? 0: 2;
+ vindex[3]= 2;
}
else if VTEST(efa1, 3, efa) {
*v3= efa1->v3;
- *v4= (efa1->v1 == *v2)? efa1->v2: efa1->v1;
+ *v4= efa1->v1;
vindex[2]= 2;
- vindex[3]= (efa1->v1 == *v2)? 1: 0;
+ vindex[3]= 0;
}
else
*v3= *v4= NULL;
@@ -3178,8 +2986,9 @@ static void untag_edges(EditFace *f)
}
/** remove and free list of tagged edges and faces */
-static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa)
+static void free_tagged_edges_faces(EditEdge *eed, EditFace *efa)
{
+ EditMesh *em= G.editMesh;
EditEdge *nexted;
EditFace *nextvl;
@@ -3187,7 +2996,7 @@ static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa)
nextvl= efa->next;
if(efa->f1) {
BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
+ free_editface(efa);
}
else
/* avoid deleting edges that are still in use */
@@ -3198,69 +3007,242 @@ static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa)
while(eed) {
nexted= eed->next;
if(eed->f1) {
- remedge(em, eed);
- free_editedge(em, eed);
+ remedge(eed);
+ free_editedge(eed);
}
eed= nexted;
+ }
+}
+
+/* note; the EM_selectmode_set() calls here illustrate how badly constructed it all is... from before the
+ edge/face flags, with very mixed results.... */
+void beauty_fill(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *v1, *v2, *v3, *v4;
+ EditEdge *eed, *nexted;
+ EditEdge dia1, dia2;
+ EditFace *efa, *w;
+ // void **efaar, **efaa;
+ EVPTuple *efaar;
+ EVPtr *efaa;
+ float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2;
+ int totedge, ok, notbeauty=8, onedone, vindex[4];
+
+ if(multires_test()) return;
+
+ /* - all selected edges with two faces
+ * - find the faces: store them in edges (using datablock)
+ * - per edge: - test convex
+ * - test edge: flip?
+ * - if true: remedge, addedge, all edges at the edge get new face pointers
+ */
+
+ EM_selectmode_set(); // makes sure in selectmode 'face' the edges of selected faces are selected too
+
+ totedge = count_selected_edges(em->edges.first);
+ if(totedge==0) return;
+
+ /* temp block with face pointers */
+ efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "beautyfill");
+
+ while (notbeauty) {
+ notbeauty--;
+
+ ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
+
+ /* there we go */
+ onedone= 0;
+
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+
+ /* f2 is set in collect_quadedges() */
+ if(eed->f2==2 && eed->h==0) {
+
+ efaa = (EVPtr *) eed->tmp.p;
+
+ /* none of the faces should be treated before, nor be part of fgon */
+ ok= 1;
+ efa= efaa[0];
+ if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
+ if(efa->fgonf) ok= 0;
+ efa= efaa[1];
+ if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
+ if(efa->fgonf) ok= 0;
+
+ if(ok) {
+ /* test convex */
+ givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
+ if(v1 && v2 && v3 && v4) {
+ if( convex(v1->co, v2->co, v3->co, v4->co) ) {
+
+ /* test edges */
+ if( (v1) > (v3) ) {
+ dia1.v1= v3;
+ dia1.v2= v1;
+ }
+ else {
+ dia1.v1= v1;
+ dia1.v2= v3;
+ }
+
+ if( (v2) > (v4) ) {
+ dia2.v1= v4;
+ dia2.v2= v2;
+ }
+ else {
+ dia2.v1= v2;
+ dia2.v2= v4;
+ }
+
+ /* testing rule:
+ * the area divided by the total edge lengths
+ */
+
+ len1= len_v3v3(v1->co, v2->co);
+ len2= len_v3v3(v2->co, v3->co);
+ len3= len_v3v3(v3->co, v4->co);
+ len4= len_v3v3(v4->co, v1->co);
+ len5= len_v3v3(v1->co, v3->co);
+ len6= len_v3v3(v2->co, v4->co);
+
+ opp1= area_tri_v3(v1->co, v2->co, v3->co);
+ opp2= area_tri_v3(v1->co, v3->co, v4->co);
+
+ fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5);
+
+ opp1= area_tri_v3(v2->co, v3->co, v4->co);
+ opp2= area_tri_v3(v2->co, v4->co, v1->co);
+
+ fac2= opp1/(len2+len3+len6) + opp2/(len4+len1+len6);
+
+ ok= 0;
+ if(fac1 > fac2) {
+ if(dia2.v1==eed->v1 && dia2.v2==eed->v2) {
+ eed->f1= 1;
+ efa= efaa[0];
+ efa->f1= 1;
+ efa= efaa[1];
+ efa->f1= 1;
+
+ w= EM_face_from_faces(efaa[0], efaa[1],
+ vindex[0], vindex[1], 4+vindex[2], -1);
+ w->f |= SELECT;
+
+
+ w= EM_face_from_faces(efaa[0], efaa[1],
+ vindex[0], 4+vindex[2], 4+vindex[3], -1);
+ w->f |= SELECT;
+
+ onedone= 1;
+ }
+ }
+ else if(fac1 < fac2) {
+ if(dia1.v1==eed->v1 && dia1.v2==eed->v2) {
+ eed->f1= 1;
+ efa= efaa[0];
+ efa->f1= 1;
+ efa= efaa[1];
+ efa->f1= 1;
+
+
+ w= EM_face_from_faces(efaa[0], efaa[1],
+ vindex[1], 4+vindex[2], 4+vindex[3], -1);
+ w->f |= SELECT;
+
+
+ w= EM_face_from_faces(efaa[0], efaa[1],
+ vindex[0], 4+vindex[1], 4+vindex[3], -1);
+ w->f |= SELECT;
+
+ onedone= 1;
+ }
+ }
+ }
+ }
+ }
+
+ }
+ eed= nexted;
+ }
+
+ free_tagged_edges_faces(em->edges.first, em->faces.first);
+
+ if(onedone==0) break;
+
+ EM_selectmode_set(); // new edges/faces were added
}
+
+ MEM_freeN(efaar);
+
+ EM_select_flush();
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+ BIF_undo_push("Beauty Fill");
}
/* ******************** BEGIN TRIANGLE TO QUAD ************************************* */
-static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, float limit)
-{
-
+static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, float limit){
+
/*gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would make*/
/*Note: this is more complicated than it needs to be and should be cleaned up...*/
float measure = 0.0, noA1[3], noA2[3], noB1[3], noB2[3], normalADiff, normalBDiff,
edgeVec1[3], edgeVec2[3], edgeVec3[3], edgeVec4[3], diff,
minarea, maxarea, areaA, areaB;
-
+
/*First Test: Normal difference*/
normal_tri_v3( noA1,v1->co, v2->co, v3->co);
normal_tri_v3( noA2,v1->co, v3->co, v4->co);
-
+
if(noA1[0] == noA2[0] && noA1[1] == noA2[1] && noA1[2] == noA2[2]) normalADiff = 0.0;
- else normalADiff = RAD2DEG(angle_v2v2(noA1, noA2));
+ else normalADiff = angle_v2v2(noA1, noA2);
//if(!normalADiff) normalADiff = 179;
normal_tri_v3( noB1,v2->co, v3->co, v4->co);
normal_tri_v3( noB2,v4->co, v1->co, v2->co);
-
+
if(noB1[0] == noB2[0] && noB1[1] == noB2[1] && noB1[2] == noB2[2]) normalBDiff = 0.0;
- else normalBDiff = RAD2DEG(angle_v2v2(noB1, noB2));
+ else normalBDiff = angle_v2v2(noB1, noB2);
//if(!normalBDiff) normalBDiff = 179;
-
+
measure += (normalADiff/360) + (normalBDiff/360);
if(measure > limit) return measure;
-
+
/*Second test: Colinearity*/
sub_v3_v3v3(edgeVec1, v1->co, v2->co);
sub_v3_v3v3(edgeVec2, v2->co, v3->co);
sub_v3_v3v3(edgeVec3, v3->co, v4->co);
sub_v3_v3v3(edgeVec4, v4->co, v1->co);
-
+
diff = 0.0;
-
+
diff = (
- fabs(RAD2DEG(angle_v2v2(edgeVec1, edgeVec2)) - 90) +
- fabs(RAD2DEG(angle_v2v2(edgeVec2, edgeVec3)) - 90) +
- fabs(RAD2DEG(angle_v2v2(edgeVec3, edgeVec4)) - 90) +
- fabs(RAD2DEG(angle_v2v2(edgeVec4, edgeVec1)) - 90)) / 360;
+ fabs(angle_v2v2(edgeVec1, edgeVec2) - 90) +
+ fabs(angle_v2v2(edgeVec2, edgeVec3) - 90) +
+ fabs(angle_v2v2(edgeVec3, edgeVec4) - 90) +
+ fabs(angle_v2v2(edgeVec4, edgeVec1) - 90)) / 360;
if(!diff) return 0.0;
-
+
measure += diff;
if(measure > limit) return measure;
/*Third test: Concavity*/
areaA = area_tri_v3(v1->co, v2->co, v3->co) + area_tri_v3(v1->co, v3->co, v4->co);
areaB = area_tri_v3(v2->co, v3->co, v4->co) + area_tri_v3(v4->co, v1->co, v2->co);
-
+
if(areaA <= areaB) minarea = areaA;
else minarea = areaB;
-
+
if(areaA >= areaB) maxarea = areaA;
else maxarea = areaB;
-
+
if(!maxarea) measure += 1;
else measure += (1 - (minarea / maxarea));
@@ -3269,38 +3251,38 @@ static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert
#define T2QUV_LIMIT 0.005
#define T2QCOL_LIMIT 3
-static int compareFaceAttribs(EditMesh *em, EditFace *f1, EditFace *f2, EditEdge *eed)
+static int compareFaceAttribs(EditFace *f1, EditFace *f2, EditEdge *eed)
{
- /*Test to see if the per-face attributes for the joining edge match within limit*/
+ /*Test to see if the per-face attributes for the joining edge match within limit*/
MTFace *tf1, *tf2;
unsigned int *col1, *col2;
- short i,attrok=0, flag = 0, /* XXX scene->toolsettings->editbutflag,*/ fe1[2], fe2[2];
-
- tf1 = CustomData_em_get(&em->fdata, f1->data, CD_MTFACE);
- tf2 = CustomData_em_get(&em->fdata, f2->data, CD_MTFACE);
-
- col1 = CustomData_em_get(&em->fdata, f1->data, CD_MCOL);
- col2 = CustomData_em_get(&em->fdata, f2->data, CD_MCOL);
+ short i,attrok=0, flag = G.scene->toolsettings->editbutflag, fe1[2], fe2[2];
+
+ tf1 = CustomData_em_get(&G.editMesh->fdata, f1->data, CD_MTFACE);
+ tf2 = CustomData_em_get(&G.editMesh->fdata, f2->data, CD_MTFACE);
+ col1 = CustomData_em_get(&G.editMesh->fdata, f1->data, CD_MCOL);
+ col2 = CustomData_em_get(&G.editMesh->fdata, f2->data, CD_MCOL);
+
/*store indices for faceedges*/
f1->v1->f1 = 0;
f1->v2->f1 = 1;
f1->v3->f1 = 2;
-
+
fe1[0] = eed->v1->f1;
fe1[1] = eed->v2->f1;
-
+
f2->v1->f1 = 0;
f2->v2->f1 = 1;
f2->v3->f1 = 2;
-
+
fe2[0] = eed->v1->f1;
fe2[1] = eed->v2->f1;
-
+
/*compare faceedges for each face attribute. Additional per face attributes can be added later*/
/*do UVs*/
if(flag & B_JOINTRIA_UV){
-
+
if(tf1 == NULL || tf2 == NULL) attrok |= B_JOINTRIA_UV;
else if(tf1->tpage != tf2->tpage); /*do nothing*/
else{
@@ -3310,7 +3292,7 @@ static int compareFaceAttribs(EditMesh *em, EditFace *f1, EditFace *f2, EditEdge
}
}
}
-
+
/*do VCOLs*/
if(flag & B_JOINTRIA_VCOL){
if(!col1 || !col2) attrok |= B_JOINTRIA_VCOL;
@@ -3319,7 +3301,7 @@ static int compareFaceAttribs(EditMesh *em, EditFace *f1, EditFace *f2, EditEdge
for(i = 0; i < 2; i++){
f1vcol = (char *)&(col1[fe1[i]]);
f2vcol = (char *)&(col2[fe2[i]]);
-
+
/*compare f1vcol with f2vcol*/
if( f1vcol[1] + T2QCOL_LIMIT > f2vcol[1] && f1vcol[1] - T2QCOL_LIMIT < f2vcol[1] &&
f1vcol[2] + T2QCOL_LIMIT > f2vcol[2] && f1vcol[2] - T2QCOL_LIMIT < f2vcol[2] &&
@@ -3327,18 +3309,18 @@ static int compareFaceAttribs(EditMesh *em, EditFace *f1, EditFace *f2, EditEdge
}
}
}
-
+
if( ((attrok & B_JOINTRIA_UV) == (flag & B_JOINTRIA_UV)) && ((attrok & B_JOINTRIA_VCOL) == (flag & B_JOINTRIA_VCOL)) ) return 1;
return 0;
-}
-
+}
+
static int fplcmp(const void *v1, const void *v2)
{
const EditEdge *e1= *((EditEdge**)v1), *e2=*((EditEdge**)v2);
-
+
if( e1->crease > e2->crease) return 1;
else if( e1->crease < e2->crease) return -1;
-
+
return 0;
}
@@ -3346,8 +3328,9 @@ static int fplcmp(const void *v1, const void *v2)
#define T2QDELETE 1
#define T2QCOMPLEX 2
#define T2QJOIN 4
-void join_triangles(EditMesh *em)
+void join_triangles(void)
{
+ EditMesh *em=G.editMesh;
EditVert *v1, *v2, *v3, *v4, *eve;
EditEdge *eed, **edsortblock = NULL, **edb = NULL;
EditFace *efa;
@@ -3355,23 +3338,26 @@ void join_triangles(EditMesh *em)
EVPtr *efaa = NULL;
float *creases = NULL;
float measure; /*Used to set tolerance*/
- float limit = 0.8f; // XXX scene->toolsettings->jointrilimit;
+ float limit = G.scene->toolsettings->jointrilimit;
int i, ok, totedge=0, totseledge=0, complexedges, vindex[4];
+
+ /*test for multi-resolution data*/
+ if(multires_test()) return;
/*if we take a long time on very dense meshes we want waitcursor to display*/
waitcursor(1);
-
+
totseledge = count_selected_edges(em->edges.first);
if(totseledge==0) return;
-
+
/*abusing crease value to store weights for edge pairs. Nasty*/
for(eed=em->edges.first; eed; eed=eed->next) totedge++;
- if(totedge) creases = MEM_callocN(sizeof(float) * totedge, "Join Triangles Crease Array");
+ if(totedge) creases = MEM_callocN(sizeof(float) * totedge, "Join Triangles Crease Array");
for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++){
- creases[i] = eed->crease;
+ creases[i] = eed->crease;
eed->crease = 0.0;
}
-
+
/*clear temp flags*/
for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = eve->f2 = 0;
for(eed=em->edges.first; eed; eed=eed->next) eed->f2 = eed->f1 = 0;
@@ -3381,11 +3367,11 @@ void join_triangles(EditMesh *em)
efaar= (EVPTuple *) MEM_callocN(totseledge * sizeof(EVPTuple), "Tri2Quad");
ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
complexedges = 0;
-
+
if(ok){
-
-
- /*clear tmp.l flag and store number of faces that are selected and coincident to current face here.*/
+
+
+ /*clear tmp.l flag and store number of faces that are selected and coincident to current face here.*/
for(eed=em->edges.first; eed; eed=eed->next){
/* eed->f2 is 2 only if this edge is part of exactly two
triangles, and both are selected, and it has EVPTuple assigned */
@@ -3395,7 +3381,7 @@ void join_triangles(EditMesh *em)
efaa[1]->tmp.l++;
}
}
-
+
for(eed=em->edges.first; eed; eed=eed->next){
if(eed->f2 == 2){
efaa= (EVPtr *) eed->tmp.p;
@@ -3404,46 +3390,48 @@ void join_triangles(EditMesh *em)
if(v1 && v2 && v3 && v4){
/*test if simple island first. This mimics 2.42 behaviour and the tests are less restrictive.*/
if(efaa[0]->tmp.l == 1 && efaa[1]->tmp.l == 1){
- eed->f1 |= T2QJOIN;
- efaa[0]->f1 = 1; //mark for join
- efaa[1]->f1 = 1; //mark for join
+ if( convex(v1->co, v2->co, v3->co, v4->co) ){
+ eed->f1 |= T2QJOIN;
+ efaa[0]->f1 = 1; //mark for join
+ efaa[1]->f1 = 1; //mark for join
+ }
}
- else{
-
+ else{
+
/* The face pair is part of a 'complex' island, so the rules for dealing with it are more involved.
Depending on what options the user has chosen, this face pair can be 'thrown out' based upon the following criteria:
-
+
1: the two faces do not share the same material
2: the edge joining the two faces is marked as sharp.
3: the two faces UV's do not make a good match
4: the two faces Vertex colors do not make a good match
-
+
If the face pair passes all the applicable tests, it is then given a 'weight' with the measure_facepair() function.
This measures things like concavity, colinearity ect. If this weight is below the threshold set by the user
the edge joining them is marked as being 'complex' and will be compared against other possible pairs which contain one of the
same faces in the current pair later.
-
+
This technique is based upon an algorithm that Campbell Barton developed for his Tri2Quad script that was previously part of
the python scripts bundled with Blender releases.
*/
-
-// XXX if(scene->toolsettings->editbutflag & B_JOINTRIA_SHARP && eed->sharp); /*do nothing*/
-// else if(scene->toolsettings->editbutflag & B_JOINTRIA_MAT && efaa[0]->mat_nr != efaa[1]->mat_nr); /*do nothing*/
-// else if(((scene->toolsettings->editbutflag & B_JOINTRIA_UV) || (scene->toolsettings->editbutflag & B_JOINTRIA_VCOL)) &&
- compareFaceAttribs(em, efaa[0], efaa[1], eed); // XXX == 0); /*do nothing*/
-// else{
+
+ if(G.scene->toolsettings->editbutflag & B_JOINTRIA_SHARP && eed->sharp); /*do nothing*/
+ else if(G.scene->toolsettings->editbutflag & B_JOINTRIA_MAT && efaa[0]->mat_nr != efaa[1]->mat_nr); /*do nothing*/
+ else if(((G.scene->toolsettings->editbutflag & B_JOINTRIA_UV) || (G.scene->toolsettings->editbutflag & B_JOINTRIA_VCOL)) &&
+ compareFaceAttribs(efaa[0], efaa[1], eed) == 0); /*do nothing*/
+ else{
measure = measure_facepair(v1, v2, v3, v4, limit);
if(measure < limit){
complexedges++;
eed->f1 |= T2QCOMPLEX;
eed->crease = measure; /*we dont mark edges for join yet*/
}
-// }
+ }
}
}
}
}
-
+
/*Quicksort the complex edges according to their weighting*/
if(complexedges){
edsortblock = edb = MEM_callocN(sizeof(EditEdge*) * complexedges, "Face Pairs quicksort Array");
@@ -3455,7 +3443,7 @@ void join_triangles(EditMesh *em)
}
qsort(edsortblock, complexedges, sizeof(EditEdge*), fplcmp);
/*now go through and mark the edges who get the highest weighting*/
- for(edb=edsortblock, i=0; i < complexedges; edb++, i++){
+ for(edb=edsortblock, i=0; i < complexedges; edb++, i++){
efaa = (EVPtr *)((*edb)->tmp.p); /*suspect!*/
if( !efaa[0]->f1 && !efaa[1]->f1){
efaa[0]->f1 = 1; //mark for join
@@ -3464,18 +3452,18 @@ void join_triangles(EditMesh *em)
}
}
}
-
- /*finally go through all edges marked for join (simple and complex) and create new faces*/
+
+ /*finally go through all edges marked for join (simple and complex) and create new faces*/
for(eed=em->edges.first; eed; eed=eed->next){
if(eed->f1 & T2QJOIN){
efaa= (EVPtr *)eed->tmp.p;
v1 = v2 = v3 = v4 = NULL;
givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
- if((v1 && v2 && v3 && v4) && (exist_face(em, v1, v2, v3, v4)==0)){ /*exist_face is very slow! Needs to be addressed.*/
+ if((v1 && v2 && v3 && v4) && (exist_face(v1, v2, v3, v4)==0)){ /*exist_face is very slow! Needs to be adressed.*/
/*flag for delete*/
eed->f1 |= T2QDELETE;
/*create new quad and select*/
- efa = EM_face_from_faces(em, efaa[0], efaa[1], vindex[0], vindex[1], 4+vindex[2], 4+vindex[3]);
+ efa = EM_face_from_faces(efaa[0], efaa[1], vindex[0], vindex[1], 4+vindex[2], 4+vindex[3]);
EM_select_face(efa,1);
}
else{
@@ -3485,30 +3473,39 @@ void join_triangles(EditMesh *em)
}
}
}
-
+
/*free data and cleanup*/
if(creases){
- for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++) eed->crease = creases[i];
+ for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++) eed->crease = creases[i];
MEM_freeN(creases);
}
for(eed=em->edges.first; eed; eed=eed->next){
if(eed->f1 & T2QDELETE) eed->f1 = 1;
else eed->f1 = 0;
}
- free_tagged_edges_faces(em, em->edges.first, em->faces.first);
+ free_tagged_edges_faces(em->edges.first, em->faces.first);
if(efaar) MEM_freeN(efaar);
if(edsortblock) MEM_freeN(edsortblock);
-
- EM_selectmode_flush(em);
-
+
+ EM_selectmode_flush();
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ #ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+ #endif
+ waitcursor(0);
+ BIF_undo_push("Convert Triangles to Quads");
}
/* ******************** END TRIANGLE TO QUAD ************************************* */
#define FACE_MARKCLEAR(f) (f->f1 = 1)
-/* quick hack, basically a copy of beautify_fill */
-static void edge_flip(EditMesh *em)
+/* quick hack, basically a copy of beauty_fill */
+void edge_flip(void)
{
+ EditMesh *em = G.editMesh;
EditVert *v1, *v2, *v3, *v4;
EditEdge *eed, *nexted;
EditFace *efa, *w;
@@ -3516,7 +3513,7 @@ static void edge_flip(EditMesh *em)
EVPTuple *efaar;
EVPtr *efaa;
int totedge, ok, vindex[4];
-
+
/* - all selected edges with two faces
* - find the faces: store them in edges (using datablock)
* - per edge: - test convex
@@ -3524,7 +3521,7 @@ static void edge_flip(EditMesh *em)
- if true: remedge, addedge, all edges at the edge get new face pointers
*/
- EM_selectmode_flush(em); // makes sure in selectmode 'face' the edges of selected faces are selected too
+ EM_selectmode_flush(); // makes sure in selectmode 'face' the edges of selected faces are selected too
totedge = count_selected_edges(em->edges.first);
if(totedge==0) return;
@@ -3533,15 +3530,15 @@ static void edge_flip(EditMesh *em)
efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "edgeflip");
ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
-
+
eed= em->edges.first;
while(eed) {
nexted= eed->next;
-
+
if(eed->f2==2) { /* points to 2 faces */
-
+
efaa= (EVPtr *) eed->tmp.p;
-
+
/* don't do it if flagged */
ok= 1;
@@ -3549,7 +3546,7 @@ static void edge_flip(EditMesh *em)
if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
efa= efaa[1];
if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
-
+
if(ok) {
/* test convex */
givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
@@ -3558,23 +3555,23 @@ static void edge_flip(EditMesh *em)
4-----3 4-----3
|\ | | /|
| \ 1 | | 1 / |
- | \ | -> | / |
- | 0 \ | | / 0 |
+ | \ | -> | / |
+ | 0 \ | | / 0 |
| \| |/ |
1-----2 1-----2
*/
/* make new faces */
if (v1 && v2 && v3) {
if( convex(v1->co, v2->co, v3->co, v4->co) ) {
- if(exist_face(em, v1, v2, v3, v4)==0) {
- /* outch this may break seams */
- w= EM_face_from_faces(em, efaa[0], efaa[1], vindex[0],
+ if(exist_face(v1, v2, v3, v4)==0) {
+ /* outch this may break seams */
+ w= EM_face_from_faces(efaa[0], efaa[1], vindex[0],
vindex[1], 4+vindex[2], -1);
EM_select_face(w, 1);
/* outch this may break seams */
- w= EM_face_from_faces(em, efaa[0], efaa[1], vindex[0],
+ w= EM_face_from_faces(efaa[0], efaa[1], vindex[0],
4+vindex[2], 4+vindex[3], -1);
EM_select_face(w, 1);
@@ -3582,8 +3579,8 @@ static void edge_flip(EditMesh *em)
/* tag as to-be-removed */
FACE_MARKCLEAR(efaa[1]);
FACE_MARKCLEAR(efaa[0]);
- eed->f1 = 1;
-
+ eed->f1 = 1;
+
} /* endif test convex */
}
}
@@ -3592,35 +3589,29 @@ static void edge_flip(EditMesh *em)
}
/* clear tagged edges and faces: */
- free_tagged_edges_faces(em, em->edges.first, em->faces.first);
-
+ free_tagged_edges_faces(em->edges.first, em->faces.first);
+
MEM_freeN(efaar);
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+ BIF_undo_push("Flip Triangle Edges");
+
}
-#define DIRECTION_CW 1
-#define DIRECTION_CCW 2
-
-static const EnumPropertyItem direction_items[]= {
- {DIRECTION_CW, "CW", 0, "Clockwise", ""},
- {DIRECTION_CCW, "CCW", 0, "Counter Clockwise", ""},
- {0, NULL, 0, NULL, NULL}};
-
-#define AXIS_X 1
-#define AXIS_Y 2
-
-static const EnumPropertyItem axis_items_xy[]= {
- {AXIS_X, "X", 0, "X", ""},
- {AXIS_Y, "Y", 0, "Y", ""},
- {0, NULL, 0, NULL, NULL}};
-
-static void edge_rotate(EditMesh *em, wmOperator *op, EditEdge *eed, int dir)
+static void edge_rotate(EditEdge *eed,int dir)
{
+ EditMesh *em = G.editMesh;
EditVert **verts[2];
EditFace *face[2], *efa, *newFace[2];
EditEdge **edges[2], **hiddenedges, *srchedge;
int facecount, p1, p2, p3, p4, fac1, fac2, i, j;
int numhidden, numshared, p[2][4];
-
+
/* check to make sure that the edge is only part of 2 faces */
facecount = 0;
for(efa = em->faces.first;efa;efa = efa->next) {
@@ -3635,17 +3626,17 @@ static void edge_rotate(EditMesh *em, wmOperator *op, EditEdge *eed, int dir)
}
}
}
-
+
if(facecount < 2)
return;
/* how many edges does each face have */
- if(face[0]->e4) fac1= 4;
+ if(face[0]->e4) fac1= 4;
else fac1= 3;
if(face[1]->e4) fac2= 4;
else fac2= 3;
-
+
/* make a handy array for verts and edges */
verts[0]= &face[0]->v1;
edges[0]= &face[0]->e1;
@@ -3661,7 +3652,11 @@ static void edge_rotate(EditMesh *em, wmOperator *op, EditEdge *eed, int dir)
if(numshared > 1)
return;
-
+
+ /* coplaner faces only please */
+ if(dot_v3v3(face[0]->n,face[1]->n) <= 0.000001)
+ return;
+
/* we want to construct an array of vertex indicis in both faces, starting at
the last vertex of the edge being rotated.
- first we find the two vertices that lie on the rotating edge
@@ -3675,12 +3670,12 @@ static void edge_rotate(EditMesh *em, wmOperator *op, EditEdge *eed, int dir)
if(eed->v1 == verts[1][i]) p3 = i;
if(eed->v2 == verts[1][i]) p4 = i;
}
-
+
if((p1+1)%fac1 == p2)
SWAP(int, p1, p2);
if((p3+1)%fac2 == p4)
SWAP(int, p3, p4);
-
+
for (i = 0; i < 4; i++) {
p[0][i]= (p1 + i)%fac1;
p[1][i]= (p3 + i)%fac2;
@@ -3694,11 +3689,11 @@ static void edge_rotate(EditMesh *em, wmOperator *op, EditEdge *eed, int dir)
hiddenedges = MEM_mallocN(sizeof(EditVert*)*numhidden+1, "RotateEdgeHiddenVerts");
if(!hiddenedges) {
- BKE_report(op->reports, RPT_ERROR, "Memory allocation failed");
- return;
- }
+ error("Malloc Was not happy!");
+ return;
+ }
- numhidden = 0;
+ numhidden = 0;
for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next)
if(srchedge->h && (srchedge->v1->f & SELECT || srchedge->v2->f & SELECT))
hiddenedges[numhidden++] = srchedge;
@@ -3707,54 +3702,54 @@ static void edge_rotate(EditMesh *em, wmOperator *op, EditEdge *eed, int dir)
if(fac1 == 3 && fac2 == 3) {
/* no need of reverse setup */
- newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1);
- newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1);
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1);
}
else if(fac1 == 4 && fac2 == 3) {
- if(dir == DIRECTION_CCW) {
- newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]);
- newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1);
- } else if (dir == DIRECTION_CW) {
- newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][2], 4+p[1][1], p[0][0], p[0][1]);
- newFace[1]= EM_face_from_faces(em, face[1], face[0], 4+p[0][2], p[1][0], p[1][1], -1);
-
+ if(dir == 1) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1);
+ } else if (dir == 2) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][2], 4+p[1][1], p[0][0], p[0][1]);
+ newFace[1]= EM_face_from_faces(face[1], face[0], 4+p[0][2], p[1][0], p[1][1], -1);
+
verts[0][p[0][2]]->f |= SELECT;
- verts[1][p[1][1]]->f |= SELECT;
+ verts[1][p[1][1]]->f |= SELECT;
}
}
else if(fac1 == 3 && fac2 == 4) {
- if(dir == DIRECTION_CCW) {
- newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1);
- newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]);
- } else if (dir == DIRECTION_CW) {
- newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][0], p[0][1], 4+p[1][2], -1);
- newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], 4+p[0][2]);
-
+ if(dir == 1) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]);
+ } else if (dir == 2) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][0], p[0][1], 4+p[1][2], -1);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], 4+p[0][1], 4+p[0][2]);
+
verts[0][p[0][1]]->f |= SELECT;
- verts[1][p[1][2]]->f |= SELECT;
+ verts[1][p[1][2]]->f |= SELECT;
}
-
+
}
else if(fac1 == 4 && fac2 == 4) {
- if(dir == DIRECTION_CCW) {
- newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]);
- newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]);
- } else if (dir == DIRECTION_CW) {
- newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][2], p[0][3], 4+p[1][1], 4+p[1][2]);
- newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][2], p[1][3], 4+p[0][1], 4+p[0][2]);
-
+ if(dir == 1) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]);
+ } else if (dir == 2) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][2], p[0][3], 4+p[1][1], 4+p[1][2]);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][2], p[1][3], 4+p[0][1], 4+p[0][2]);
+
verts[0][p[0][2]]->f |= SELECT;
- verts[1][p[1][2]]->f |= SELECT;
+ verts[1][p[1][2]]->f |= SELECT;
}
- }
+ }
else
return; /* This should never happen */
- if(dir == DIRECTION_CCW || (fac1 == 3 && fac2 == 3)) {
+ if(dir == 1 || (fac1 == 3 && fac2 == 3)) {
verts[0][p[0][1]]->f |= SELECT;
verts[1][p[1][1]]->f |= SELECT;
}
-
+
/* copy old edge's flags to new center edge*/
for(srchedge=em->edges.first;srchedge;srchedge=srchedge->next) {
if((srchedge->v1->f & SELECT) && (srchedge->v2->f & SELECT)) {
@@ -3766,47 +3761,44 @@ static void edge_rotate(EditMesh *em, wmOperator *op, EditEdge *eed, int dir)
srchedge->bweight = eed->bweight;
}
}
-
+
/* resetting hidden flag */
for(numhidden--; numhidden>=0; numhidden--)
hiddenedges[numhidden]->h= 1;
-
+
/* check for orhphan edges */
for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next)
- srchedge->f1= -1;
-
+ srchedge->f1= -1;
+
/* cleanup */
MEM_freeN(hiddenedges);
-
+
/* get rid of the old edge and faces*/
- remedge(em, eed);
- free_editedge(em, eed);
+ remedge(eed);
+ free_editedge(eed);
BLI_remlink(&em->faces, face[0]);
- free_editface(em, face[0]);
+ free_editface(face[0]);
BLI_remlink(&em->faces, face[1]);
- free_editface(em, face[1]);
+ free_editface(face[1]);
}
/* only accepts 1 selected edge, or 2 selected faces */
-static int edge_rotate_selected(bContext *C, wmOperator *op)
+void edge_rotate_selected(int dir)
{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
EditEdge *eed;
EditFace *efa;
- int dir = RNA_enum_get(op->ptr, "direction"); // dir == 2 when clockwise and ==1 for counter CW.
short edgeCount = 0;
-
+
/*clear new flag for new edges, count selected edges */
- for(eed= em->edges.first; eed; eed= eed->next) {
+ for(eed= G.editMesh->edges.first; eed; eed= eed->next) {
eed->f1= 0;
eed->f2 &= ~2;
- if(eed->f & SELECT) edgeCount++;
+ if(eed->f & SELECT) edgeCount++;
}
-
+
if(edgeCount>1) {
/* more selected edges, check faces */
- for(efa= em->faces.first; efa; efa= efa->next) {
+ for(efa= G.editMesh->faces.first; efa; efa= efa->next) {
if(efa->f & SELECT) {
efa->e1->f1++;
efa->e2->f1++;
@@ -3815,81 +3807,734 @@ static int edge_rotate_selected(bContext *C, wmOperator *op)
}
}
edgeCount= 0;
- for(eed= em->edges.first; eed; eed= eed->next) {
+ for(eed= G.editMesh->edges.first; eed; eed= eed->next) {
if(eed->f1==2) edgeCount++;
}
if(edgeCount==1) {
- for(eed= em->edges.first; eed; eed= eed->next) {
+ for(eed= G.editMesh->edges.first; eed; eed= eed->next) {
if(eed->f1==2) {
- edge_rotate(em, op, eed,dir);
+ edge_rotate(eed,dir);
break;
}
}
}
- else
- {
- BKE_report(op->reports, RPT_WARNING, "Select one edge or two adjacent faces");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
+ else error("Select one edge or two adjacent faces");
}
else if(edgeCount==1) {
- for(eed= em->edges.first; eed; eed= eed->next) {
+ for(eed= G.editMesh->edges.first; eed; eed= eed->next) {
if(eed->f & SELECT) {
EM_select_edge(eed, 0);
- edge_rotate(em, op, eed,dir);
+ edge_rotate(eed,dir);
break;
}
}
}
- else {
- BKE_report(op->reports, RPT_WARNING, "Select one edge or two adjacent faces");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
+ else error("Select one edge or two adjacent faces");
+
/* flush selected vertices (again) to edges/faces */
- EM_select_flush(em);
+ EM_select_flush();
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
- BKE_mesh_end_editmesh(obedit->data, em);
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+
+ BIF_undo_push("Rotate Edge");
+}
+
+/******************* BEVEL CODE STARTS HERE ********************/
+
+static void bevel_displace_vec(float *midvec, float *v1, float *v2, float *v3, float d, float no[3])
+{
+ float a[3], c[3], n_a[3], n_c[3], mid[3], ac, ac2, fac;
+
+ sub_v3_v3v3(a, v1, v2);
+ sub_v3_v3v3(c, v3, v2);
+
+ cross_v3_v3v3(n_a, a, no);
+ normalize_v3(n_a);
+ cross_v3_v3v3(n_c, no, c);
+ normalize_v3(n_c);
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+ normalize_v3(a);
+ normalize_v3(c);
+ ac = dot_v3v3(a, c);
- return OPERATOR_FINISHED;
+ if (ac == 1 || ac == -1) {
+ midvec[0] = midvec[1] = midvec[2] = 0;
+ return;
+ }
+ ac2 = ac * ac;
+ fac = (float)sqrt((ac2 + 2*ac + 1)/(1 - ac2) + 1);
+ add_v3_v3v3(mid, n_c, n_a);
+ normalize_v3(mid);
+ mul_v3_fl(mid, d * fac);
+ add_v3_v3v3(mid, mid, v2);
+ copy_v3_v3(midvec, mid);
}
-void MESH_OT_edge_rotate(wmOperatorType *ot)
+/* Finds the new point using the sinus law to extrapolate a triangle
+ Lots of sqrts which would not be good for a real time algo
+ Using the mid point of the extrapolation of both sides
+ Useless for coplanar quads, but that doesn't happen too often */
+static void fix_bevel_wrap(float *midvec, float *v1, float *v2, float *v3, float *v4, float d, float no[3])
{
- /* identifiers */
- ot->name= "Rotate Selected Edge";
- ot->description= "Rotate selected edge or adjoining faces";
- ot->idname= "MESH_OT_edge_rotate";
+ float a[3], b[3], c[3], l_a, l_b, l_c, s_a, s_b, s_c, Pos1[3], Pos2[3], Dir[3];
+
+ sub_v3_v3v3(a, v3, v2);
+ l_a = normalize_v3(a);
+ sub_v3_v3v3(b, v4, v3);
+ normalize_v3(b);
+ sub_v3_v3v3(c, v1, v2);
+ normalize_v3(c);
+
+ s_b = dot_v3v3(a, c);
+ s_b = (float)sqrt(1 - (s_b * s_b));
+ s_a = dot_v3v3(b, c);
+ s_a = (float)sqrt(1 - (s_a * s_a));
+ mul_v3_fl(a, -1);
+ s_c = dot_v3v3(a, b);
+ s_c = (float)sqrt(1 - (s_c * s_c));
+
+ l_b = s_b * l_a / s_a;
+ l_c = s_c * l_a / s_a;
- /* api callbacks */
- ot->exec= edge_rotate_selected;
- ot->poll= ED_operator_editmesh;
+ mul_v3_fl(b, l_b);
+ mul_v3_fl(c, l_c);
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ add_v3_v3v3(Pos1, v2, c);
+ add_v3_v3v3(Pos2, v3, b);
+
+ add_v3_v3v3(Dir, Pos1, Pos2);
+ mul_v3_fl(Dir, 0.5);
+
+ bevel_displace_vec(midvec, v3, Dir, v2, d, no);
- /* props */
- RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate the edge around.");
}
-/******************* BEVEL CODE STARTS HERE ********************/
+static char detect_wrap(float *o_v1, float *o_v2, float *v1, float *v2, float *no)
+{
+ float o_a[3], a[3], o_c[3], c[3];
+
+ sub_v3_v3v3(o_a, o_v1, o_v2);
+ sub_v3_v3v3(a, v1, v2);
+
+ cross_v3_v3v3(o_c, o_a, no);
+ cross_v3_v3v3(c, a, no);
+
+ if (dot_v3v3(c, o_c) <= 0)
+ return 1;
+ else
+ return 0;
+}
+
+// Detects and fix a quad wrapping after the resize
+// Arguments are the orginal verts followed by the final verts and then the bevel size and the normal
+static void fix_bevel_quad_wrap(float *o_v1, float *o_v2, float *o_v3, float *o_v4, float *v1, float *v2, float *v3, float *v4, float d, float *no)
+{
+ float vec[3];
+ char wrap[4];
+
+ // Quads can wrap partially. Watch out
+ wrap[0] = detect_wrap(o_v1, o_v2, v1, v2, no); // Edge 1-2
+ wrap[1] = detect_wrap(o_v2, o_v3, v2, v3, no); // Edge 2-3
+ wrap[2] = detect_wrap(o_v3, o_v4, v3, v4, no); // Edge 3-4
+ wrap[3] = detect_wrap(o_v4, o_v1, v4, v1, no); // Edge 4-1
+
+ // Edge 1 inverted
+ if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 0) {
+ fix_bevel_wrap(vec, o_v2, o_v3, o_v4, o_v1, d, no);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ }
+ // Edge 2 inverted
+ else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 0) {
+ fix_bevel_wrap(vec, o_v3, o_v4, o_v1, o_v2, d, no);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ }
+ // Edge 3 inverted
+ else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) {
+ fix_bevel_wrap(vec, o_v4, o_v1, o_v2, o_v3, d, no);
+ VECCOPY(v3, vec);
+ VECCOPY(v4, vec);
+ }
+ // Edge 4 inverted
+ else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 1) {
+ fix_bevel_wrap(vec, o_v1, o_v2, o_v3, o_v4, d, no);
+ VECCOPY(v4, vec);
+ VECCOPY(v1, vec);
+ }
+ // Edge 2 and 4 inverted
+ else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 1) {
+ add_v3_v3v3(vec, v2, v3);
+ mul_v3_fl(vec, 0.5);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ add_v3_v3v3(vec, v1, v4);
+ mul_v3_fl(vec, 0.5);
+ VECCOPY(v1, vec);
+ VECCOPY(v4, vec);
+ }
+ // Edge 1 and 3 inverted
+ else if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) {
+ add_v3_v3v3(vec, v1, v2);
+ mul_v3_fl(vec, 0.5);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ add_v3_v3v3(vec, v3, v4);
+ mul_v3_fl(vec, 0.5);
+ VECCOPY(v3, vec);
+ VECCOPY(v4, vec);
+ }
+ // Totally inverted
+ else if (wrap[0] == 1 && wrap[1] == 1 && wrap[2] == 1 && wrap[3] == 1) {
+ add_v3_v3v3(vec, v1, v2);
+ add_v3_v3v3(vec, vec, v3);
+ add_v3_v3v3(vec, vec, v4);
+ mul_v3_fl(vec, 0.25);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ VECCOPY(v4, vec);
+ }
+
+}
+
+// Detects and fix a tri wrapping after the resize
+// Arguments are the orginal verts followed by the final verts and the normal
+// Triangles cannot wrap partially (not in this situation
+static void fix_bevel_tri_wrap(float *o_v1, float *o_v2, float *o_v3, float *v1, float *v2, float *v3, float *no)
+{
+ if (detect_wrap(o_v1, o_v2, v1, v2, no)) {
+ float vec[3];
+ add_v3_v3v3(vec, o_v1, o_v2);
+ add_v3_v3v3(vec, vec, o_v3);
+ mul_v3_fl(vec, 1.0f/3.0f);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ }
+}
+
+static void bevel_shrink_faces(float d, int flag)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ float vec[3], no[3], v1[3], v2[3], v3[3], v4[3];
+
+ /* move edges of all faces with efa->f1 & flag closer towards their centers */
+ efa= em->faces.first;
+ while (efa) {
+ if (efa->f1 & flag) {
+ VECCOPY(v1, efa->v1->co);
+ VECCOPY(v2, efa->v2->co);
+ VECCOPY(v3, efa->v3->co);
+ VECCOPY(no, efa->n);
+ if (efa->v4 == NULL) {
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(efa->v2->co, vec);
+ bevel_displace_vec(vec, v2, v3, v1, d, no);
+ VECCOPY(efa->v3->co, vec);
+ bevel_displace_vec(vec, v3, v1, v2, d, no);
+ VECCOPY(efa->v1->co, vec);
+
+ fix_bevel_tri_wrap(v1, v2, v3, efa->v1->co, efa->v2->co, efa->v3->co, no);
+ } else {
+ VECCOPY(v4, efa->v4->co);
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(efa->v2->co, vec);
+ bevel_displace_vec(vec, v2, v3, v4, d, no);
+ VECCOPY(efa->v3->co, vec);
+ bevel_displace_vec(vec, v3, v4, v1, d, no);
+ VECCOPY(efa->v4->co, vec);
+ bevel_displace_vec(vec, v4, v1, v2, d, no);
+ VECCOPY(efa->v1->co, vec);
+
+ fix_bevel_quad_wrap(v1, v2, v3, v4, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, d, no);
+ }
+ }
+ efa= efa->next;
+ }
+}
+
+static void bevel_shrink_draw(float d, int flag)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ float vec[3], no[3], v1[3], v2[3], v3[3], v4[3], fv1[3], fv2[3], fv3[3], fv4[3];
+
+ /* move edges of all faces with efa->f1 & flag closer towards their centers */
+ efa= em->faces.first;
+ while (efa) {
+ VECCOPY(v1, efa->v1->co);
+ VECCOPY(v2, efa->v2->co);
+ VECCOPY(v3, efa->v3->co);
+ VECCOPY(no, efa->n);
+ if (efa->v4 == NULL) {
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(fv2, vec);
+ bevel_displace_vec(vec, v2, v3, v1, d, no);
+ VECCOPY(fv3, vec);
+ bevel_displace_vec(vec, v3, v1, v2, d, no);
+ VECCOPY(fv1, vec);
+
+ fix_bevel_tri_wrap(v1, v2, v3, fv1, fv2, fv3, no);
+
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv2);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv2);
+ glVertex3fv(fv3);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv3);
+ glEnd();
+ } else {
+ VECCOPY(v4, efa->v4->co);
+ bevel_displace_vec(vec, v4, v1, v2, d, no);
+ VECCOPY(fv1, vec);
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(fv2, vec);
+ bevel_displace_vec(vec, v2, v3, v4, d, no);
+ VECCOPY(fv3, vec);
+ bevel_displace_vec(vec, v3, v4, v1, d, no);
+ VECCOPY(fv4, vec);
+
+ fix_bevel_quad_wrap(v1, v2, v3, v4, fv1, fv2, fv3, fv4, d, no);
+
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv2);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv2);
+ glVertex3fv(fv3);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv3);
+ glVertex3fv(fv4);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv4);
+ glEnd();
+ }
+ efa= efa->next;
+ }
+}
+
+static void bevel_mesh(float bsize, int allfaces)
+{
+ EditMesh *em = G.editMesh;
+//#define BEV_DEBUG
+/* Enables debug printfs and assigns material indices: */
+/* 2 = edge quad */
+/* 3 = fill polygon (vertex clusters) */
+
+ EditFace *efa, *example; //, *nextvl;
+ EditEdge *eed, *eed2;
+ EditVert *neweve[1024], *eve, *eve2, *eve3, *v1, *v2, *v3, *v4; //, *eve4;
+ //short found4, search;
+ //float f1, f2, f3, f4;
+ float cent[3], min[3], max[3];
+ int a, b, c;
+ float limit= 0.001f;
+
+ if(multires_test()) return;
+
+ waitcursor(1);
+
+ removedoublesflag(1, 0, limit);
+
+ /* tag all original faces */
+ efa= em->faces.first;
+ while (efa) {
+ efa->f1= 0;
+ if (faceselectedAND(efa, 1)||allfaces) {
+ efa->f1= 1;
+ efa->v1->f |= 128;
+ efa->v2->f |= 128;
+ efa->v3->f |= 128;
+ if (efa->v4) efa->v4->f |= 128;
+ }
+ efa->v1->f &= ~64;
+ efa->v2->f &= ~64;
+ efa->v3->f &= ~64;
+ if (efa->v4) efa->v4->f &= ~64;
+
+ efa= efa->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: split\n");
+#endif
+
+ efa= em->faces.first;
+ while (efa) {
+ if (efa->f1 & 1) {
+ efa->f1-= 1;
+ v1= addvertlist(efa->v1->co, efa->v1);
+ v1->f= efa->v1->f & ~128;
+ efa->v1->tmp.v = v1;
+
+ v1= addvertlist(efa->v2->co, efa->v2);
+ v1->f= efa->v2->f & ~128;
+ efa->v2->tmp.v = v1;
+
+ v1= addvertlist(efa->v3->co, efa->v3);
+ v1->f= efa->v3->f & ~128;
+ efa->v3->tmp.v = v1;
+
+ if (efa->v4) {
+ v1= addvertlist(efa->v4->co, efa->v4);
+ v1->f= efa->v4->f & ~128;
+ efa->v4->tmp.v = v1;
+ }
+
+ /* Needs better adaption of creases? */
+ addedgelist(efa->e1->v1->tmp.v,
+ efa->e1->v2->tmp.v,
+ efa->e1);
+ addedgelist(efa->e2->v1->tmp.v,
+ efa->e2->v2->tmp.v,
+ efa->e2);
+ addedgelist(efa->e3->v1->tmp.v,
+ efa->e3->v2->tmp.v,
+ efa->e3);
+ if (efa->e4) addedgelist(efa->e4->v1->tmp.v,
+ efa->e4->v2->tmp.v,
+ efa->e4);
+
+ if(efa->v4) {
+ v1 = efa->v1->tmp.v;
+ v2 = efa->v2->tmp.v;
+ v3 = efa->v3->tmp.v;
+ v4 = efa->v4->tmp.v;
+ addfacelist(v1, v2, v3, v4, efa,NULL);
+ } else {
+ v1= efa->v1->tmp.v;
+ v2= efa->v2->tmp.v;
+ v3= efa->v3->tmp.v;
+ addfacelist(v1, v2, v3, 0, efa,NULL);
+ }
+
+ efa= efa-> next;
+ } else {
+ efa= efa->next;
+ }
+ }
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if( (efa->v1->f & 128) && (efa->v2->f & 128) && (efa->v3->f & 128) ) {
+ if(efa->v4==NULL || (efa->v4->f & 128)) efa->f |= 128;
+ }
+ }
+
+ delfaceflag(128); // works with face flag now
+
+ /* tag all faces for shrink*/
+ efa= em->faces.first;
+ while (efa) {
+ if (faceselectedAND(efa, 1)||allfaces) {
+ efa->f1= 2;
+ }
+ efa= efa->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: make edge quads\n");
+#endif
+
+ /* find edges that are on each other and make quads between them */
+
+ eed= em->edges.first;
+ while(eed) {
+ eed->f2= eed->f1= 0;
+ if ( ((eed->v1->f & eed->v2->f) & 1) || allfaces)
+ eed->f1 |= 4; /* original edges */
+ eed->tmp.v = 0;
+ eed= eed->next;
+ }
+
+ eed= em->edges.first;
+ while (eed) {
+ if ( ((eed->f1 & 2)==0) && (eed->f1 & 4) ) {
+ eed2= em->edges.first;
+ while (eed2) {
+ if ( (eed2 != eed) && ((eed2->f1 & 2)==0) && (eed->f1 & 4) ) {
+ if (
+ (eed->v1 != eed2->v1) &&
+ (eed->v1 != eed2->v2) &&
+ (eed->v2 != eed2->v1) &&
+ (eed->v2 != eed2->v2) && (
+ ( compare_v3v3(eed->v1->co, eed2->v1->co, limit) &&
+ compare_v3v3(eed->v2->co, eed2->v2->co, limit) ) ||
+ ( compare_v3v3(eed->v1->co, eed2->v2->co, limit) &&
+ compare_v3v3(eed->v2->co, eed2->v1->co, limit) ) ) )
+ {
+
+#ifdef BEV_DEBUG
+ fprintf(stderr, "bevel_mesh: edge quad\n");
+#endif
+
+ eed->f1 |= 2; /* these edges are finished */
+ eed2->f1 |= 2;
+
+ example= NULL;
+ efa= em->faces.first; /* search example face (for mat_nr, ME_SMOOTH, ...) */
+ while (efa) {
+ if ( (efa->e1 == eed) ||
+ (efa->e2 == eed) ||
+ (efa->e3 == eed) ||
+ (efa->e4 && (efa->e4 == eed)) ) {
+ example= efa;
+ efa= NULL;
+ }
+ if (efa) efa= efa->next;
+ }
+
+ neweve[0]= eed->v1; neweve[1]= eed->v2;
+ neweve[2]= eed2->v1; neweve[3]= eed2->v2;
+
+ if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
+ efa= NULL;
+
+ if (compare_v3v3(eed->v1->co, eed2->v2->co, limit)) {
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], example,NULL);
+ } else {
+ efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], example,NULL);
+ }
+
+ if(efa) {
+ float inp;
+ normal_tri_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co);
+ inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2];
+ if(inp < 0.0) flipface(efa);
+#ifdef BEV_DEBUG
+ efa->mat_nr= 1;
+#endif
+ } else fprintf(stderr,"bevel_mesh: error creating face\n");
+ }
+ eed2= NULL;
+ }
+ }
+ if (eed2) eed2= eed2->next;
+ }
+ }
+ eed= eed->next;
+ }
+
+ eed= em->edges.first;
+ while(eed) {
+ eed->f2= eed->f1= 0;
+ eed->f1= 0;
+ eed->v1->f1 &= ~1;
+ eed->v2->f1 &= ~1;
+ eed->tmp.v = 0;
+ eed= eed->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: find clusters\n");
+#endif
+
+ /* Look for vertex clusters */
+
+ eve= em->verts.first;
+ while (eve) {
+ eve->f &= ~(64|128);
+ eve->tmp.v = NULL;
+ eve= eve->next;
+ }
+
+ /* eve->f: 128: first vertex in a list (->tmp.v) */
+ /* 64: vertex is in a list */
+
+ eve= em->verts.first;
+ while (eve) {
+ eve2= em->verts.first;
+ eve3= NULL;
+ while (eve2) {
+ if ((eve2 != eve) && ((eve2->f & (64|128))==0)) {
+ if (compare_v3v3(eve->co, eve2->co, limit)) {
+ if ((eve->f & (128|64)) == 0) {
+ /* fprintf(stderr,"Found vertex cluster:\n *\n *\n"); */
+ eve->f |= 128;
+ eve->tmp.v = eve2;
+ eve3= eve2;
+ } else if ((eve->f & 64) == 0) {
+ /* fprintf(stderr," *\n"); */
+ if (eve3) eve3->tmp.v = eve2;
+ eve2->f |= 64;
+ eve3= eve2;
+ }
+ }
+ }
+ eve2= eve2->next;
+ if (!eve2) {
+ if (eve3) eve3->tmp.v = NULL;
+ }
+ }
+ eve= eve->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: shrink faces\n");
+#endif
- /* XXX old bevel not ported yet */
+ bevel_shrink_faces(bsize, 2);
-static void bevel_menu(EditMesh *em)
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: fill clusters\n");
+#endif
+
+ /* Make former vertex clusters faces */
+
+ eve= em->verts.first;
+ while (eve) {
+ eve->f &= ~64;
+ eve= eve->next;
+ }
+
+ eve= em->verts.first;
+ while (eve) {
+ if (eve->f & 128) {
+ eve->f &= ~128;
+ a= 0;
+ neweve[a]= eve;
+ eve2 = eve->tmp.v;
+ while (eve2) {
+ a++;
+ neweve[a]= eve2;
+ eve2 = eve2->tmp.v;
+ }
+ a++;
+ efa= NULL;
+ if (a>=3) {
+ example= NULL;
+ efa= em->faces.first; /* search example face */
+ while (efa) {
+ if ( (efa->v1 == neweve[0]) ||
+ (efa->v2 == neweve[0]) ||
+ (efa->v3 == neweve[0]) ||
+ (efa->v4 && (efa->v4 == neweve[0])) ) {
+ example= efa;
+ efa= NULL;
+ }
+ if (efa) efa= efa->next;
+ }
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: Making %d-gon\n", a);
+#endif
+ if (a>4) {
+ cent[0]= cent[1]= cent[2]= 0.0;
+ INIT_MINMAX(min, max);
+ for (b=0; b<a; b++) {
+ add_v3_v3v3(cent, cent, neweve[b]->co);
+ DO_MINMAX(neweve[b]->co, min, max);
+ }
+ cent[0]= (min[0]+max[0])/2;
+ cent[1]= (min[1]+max[1])/2;
+ cent[2]= (min[2]+max[2])/2;
+ eve2= addvertlist(cent, NULL);
+ eve2->f |= 1;
+ eed= em->edges.first;
+ while (eed) {
+ c= 0;
+ for (b=0; b<a; b++)
+ if ((neweve[b]==eed->v1) || (neweve[b]==eed->v2)) c++;
+ if (c==2) {
+ if(exist_face(eed->v1, eed->v2, eve2, 0)==0) {
+ efa= addfacelist(eed->v1, eed->v2, eve2, 0, example,NULL);
+#ifdef BEV_DEBUG
+ efa->mat_nr= 2;
+#endif
+ }
+ }
+ eed= eed->next;
+ }
+ } else if (a==4) {
+ if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
+ /* the order of vertices can be anything, three cases to check */
+ if( convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co) ) {
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], NULL, NULL);
+ }
+ else if( convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co) ) {
+ efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], NULL, NULL);
+ }
+ else if( convex(neweve[0]->co, neweve[2]->co, neweve[1]->co, neweve[3]->co) ) {
+ efa= addfacelist(neweve[0], neweve[2], neweve[1], neweve[3], NULL, NULL);
+ }
+ }
+ }
+ else if (a==3) {
+ if(exist_face(neweve[0], neweve[1], neweve[2], 0)==0)
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], 0, example, NULL);
+ }
+ if(efa) {
+ float inp;
+ normal_tri_v3( efa->n,neweve[0]->co, neweve[1]->co, neweve[2]->co);
+ inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2];
+ if(inp < 0.0) flipface(efa);
+#ifdef BEV_DEBUG
+ efa->mat_nr= 2;
+#endif
+ }
+ }
+ }
+ eve= eve->next;
+ }
+
+ eve= em->verts.first;
+ while (eve) {
+ eve->f1= 0;
+ eve->f &= ~(128|64);
+ eve->tmp.v= NULL;
+ eve= eve->next;
+ }
+
+ recalc_editnormals();
+ waitcursor(0);
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ removedoublesflag(1, 0, limit);
+
+ /* flush selected vertices to edges/faces */
+ EM_select_flush();
+
+#undef BEV_DEBUG
+}
+
+static void bevel_mesh_recurs(float bsize, short recurs, int allfaces)
{
+ float d;
+ short nr;
+
+ d= bsize;
+ for (nr=0; nr<recurs; nr++) {
+ bevel_mesh(d, allfaces);
+ if (nr==0) d /= 3; else d /= 2;
+ }
+}
+
+void bevel_menu(void) {
BME_Mesh *bm;
BME_TransData_Head *td;
-// TransInfo *t;
+ TransInfo *t;
int options, res, gbm_free = 0;
-// t = BIF_GetTransInfo();
+ t = BIF_GetTransInfo();
if (!G.editBMesh) {
G.editBMesh = MEM_callocN(sizeof(*(G.editBMesh)),"bevel_menu() G.editBMesh");
gbm_free = 1;
@@ -3901,21 +4546,21 @@ static void bevel_menu(EditMesh *em)
while(G.editBMesh->options & BME_BEVEL_RUNNING) {
options = G.editBMesh->options;
res = G.editBMesh->res;
- bm = BME_editmesh_to_bmesh(em);
-// BIF_undo_push("Pre-Bevel");
- free_editMesh(em);
+ bm = BME_editmesh_to_bmesh(G.editMesh);
+ BIF_undo_push("Pre-Bevel");
+ free_editMesh(G.editMesh);
BME_bevel(bm,0.1f,res,options,0,0,&td);
- BME_bmesh_to_editmesh(bm, td, em);
- EM_selectmode_flush(em);
+ BME_bmesh_to_editmesh(bm, td);
+ EM_selectmode_flush();
G.editBMesh->bm = bm;
G.editBMesh->td = td;
-// initTransform(TFM_BEVEL,CTX_BMESH);
-// Transform();
+ initTransform(TFM_BEVEL,CTX_BMESH);
+ Transform();
BME_free_transdata(td);
BME_free_mesh(bm);
-// if (t->state != TRANS_CONFIRM) {
-// BIF_undo();
-// }
+ if (t->state != TRANS_CONFIRM) {
+ BIF_undo();
+ }
if (options == G.editBMesh->options) {
G.editBMesh->options &= ~BME_BEVEL_RUNNING;
}
@@ -3928,33 +4573,128 @@ static void bevel_menu(EditMesh *em)
}
-/* *********** END BEVEL *********/
-
-/* this utility function checks to see if 2 edit edges share a face,
-returns 1 if they do
-returns 0 if they do not, or if the function is passed the same edge 2 times
-*/
-short sharesFace(EditMesh *em, EditEdge* e1, EditEdge* e2)
+void bevel_menu_old()
{
- EditFace *search=NULL;
+ char Finished = 0, Canceled = 0, str[100], Recalc = 0;
+ short mval[2], oval[2], curval[2], event = 0, recurs = 1, nr;
+ float vec[3], d, drawd=0.0, center[3], fac = 1;
+
+ getmouseco_areawin(mval);
+ oval[0] = mval[0]; oval[1] = mval[1];
- search = em->faces.first;
- if (e1 == e2){
- return 0 ;
+ // Silly hackish code to initialise the variable (warning if not done)
+ // while still drawing in the first iteration (and without using another variable)
+ curval[0] = mval[0] + 1; curval[1] = mval[1] + 1;
+
+ // Init grabz for window to vec conversions
+ initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]);
+ window_to_3d(center, mval[0], mval[1]);
+
+ if(button(&recurs, 1, 4, "Recursion:")==0) return;
+
+ for (nr=0; nr<recurs-1; nr++) {
+ if (nr==0) fac += 1.0f/3.0f; else fac += 1.0f/(3 * nr * 2.0f);
}
- while(search){
- if(
- ((search->e1 == e1 || search->e2 == e1) || (search->e3 == e1 || search->e4 == e1)) &&
- ((search->e1 == e2 || search->e2 == e2) || (search->e3 == e2 || search->e4 == e2))
- ) {
- return 1;
- }
- search = search->next;
+
+ EM_set_flag_all(SELECT);
+
+ SetBlenderCursor(SYSCURSOR);
+
+ while (Finished == 0)
+ {
+ getmouseco_areawin(mval);
+ if (mval[0] != curval[0] || mval[1] != curval[1] || (Recalc == 1))
+ {
+ Recalc = 0;
+ curval[0] = mval[0];
+ curval[1] = mval[1];
+
+ window_to_3d(vec, mval[0]-oval[0], mval[1]-oval[1]);
+ d = normalize_v3(vec) / 10;
+
+
+ drawd = d * fac;
+ if (G.qual & LR_CTRLKEY)
+ drawd = (float) floor(drawd * 10.0f)/10.0f;
+ if (G.qual & LR_SHIFTKEY)
+ drawd /= 10;
+
+ /*------------- Preview lines--------------- */
+
+ /* uses callback mechanism to draw it all in current area */
+ scrarea_do_windraw(curarea);
+
+ /* set window matrix to perspective, default an area returns with buttons transform */
+ persp(PERSP_VIEW);
+ /* make a copy, for safety */
+ glPushMatrix();
+ /* multiply with the object transformation */
+ mymultmatrix(G.obedit->obmat);
+
+ glColor3ub(255, 255, 0);
+
+ // PREVIEW CODE GOES HERE
+ bevel_shrink_draw(drawd, 2);
+
+ /* restore matrix transform */
+ glPopMatrix();
+
+ sprintf(str, "Bevel Size: %.4f LMB to confirm, RMB to cancel, SPACE to input directly.", drawd);
+ headerprint(str);
+
+ /* this also verifies other area/windows for clean swap */
+ screen_swapbuffers();
+
+ persp(PERSP_WIN);
+
+ glDrawBuffer(GL_FRONT);
+
+ BIF_ThemeColor(TH_WIRE);
+
+ setlinestyle(3);
+ glBegin(GL_LINE_STRIP);
+ glVertex2sv(mval);
+ glVertex2sv(oval);
+ glEnd();
+ setlinestyle(0);
+
+ persp(PERSP_VIEW);
+ bglFlush(); // flush display for frontbuffer
+ glDrawBuffer(GL_BACK);
+ }
+ while(qtest()) {
+ short val=0;
+ event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle
+
+ /* val==0 on key-release event */
+ if(val && (event==ESCKEY || event==RIGHTMOUSE || event==LEFTMOUSE || event==RETKEY || event==ESCKEY)) {
+ if (event==RIGHTMOUSE || event==ESCKEY)
+ Canceled = 1;
+ Finished = 1;
+ }
+ else if (val && event==SPACEKEY) {
+ if (fbutton(&d, 0.000, 10.000, 10, 0, "Width:")!=0) {
+ drawd = d * fac;
+ Finished = 1;
+ }
+ }
+ else if (val) {
+ /* On any other keyboard event, recalc */
+ Recalc = 1;
+ }
+
+ }
+ }
+ if (Canceled==0) {
+ SetBlenderCursor(BC_WAITCURSOR);
+ bevel_mesh_recurs(drawd/fac, recurs, 1);
+ righthandfaces(1);
+ SetBlenderCursor(SYSCURSOR);
+ BIF_undo_push("Bevel");
}
- return 0;
}
-
+/* *********** END BEVEL *********/
typedef struct SlideUv {
float origuv[2];
float *uv_up, *uv_down;
@@ -3967,16 +4707,31 @@ typedef struct SlideVert {
EditVert origvert;
} SlideVert;
-#if 0
-int EdgeSlide(EditMesh *em, wmOperator *op, short immediate, float imperc)
-{
- return 0;
-/* XXX REFACTOR - #if 0'd for now, otherwise can't make 64bit windows builds on 64bit machine */
-useless:
- goto useless // because it doesn't do anything right now
+int EdgeLoopDelete(void) {
+
+ /* temporal flag setting so we keep UVs when deleting edge loops,
+ * this is a bit of a hack but it works how you would want in almost all cases */
+ short uvcalc_flag_orig = G.scene->toolsettings->uvcalc_flag;
+ G.scene->toolsettings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT;
+
+ if(!EdgeSlide(1, 1)) {
+ return 0;
+ }
+
+ /* restore uvcalc flag */
+ G.scene->toolsettings->uvcalc_flag = uvcalc_flag_orig;
+
+ EM_select_more();
+ removedoublesflag(1,0, 0.001);
+ EM_select_flush();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ return 1;
+}
-// NumInput num; XXX
- Mesh *me= NULL; // XXX
+int EdgeSlide(short immediate, float imperc)
+{
+ NumInput num;
+ EditMesh *em = G.editMesh;
EditFace *efa;
EditEdge *eed,*first=NULL,*last=NULL, *temp = NULL;
EditVert *ev, *nearest;
@@ -3984,42 +4739,42 @@ useless:
GHash *vertgh;
SlideVert *tempsv;
- float perc = 0, percp = 0,vertdist; // XXX, projectMat[4][4];
+ float perc = 0, percp = 0,vertdist, projectMat[4][4], viewMat[4][4];
float shiftlabda= 0.0f,len = 0.0f;
int i = 0,j, numsel, numadded=0, timesthrough = 0, vertsel=0, prop=1, cancel = 0,flip=0;
int wasshift = 0;
-
+
/* UV correction vars */
GHash **uvarray= NULL;
- int uvlay_tot= CustomData_number_of_layers(&em->fdata, CD_MTFACE);
+ int uvlay_tot= CustomData_number_of_layers(&G.editMesh->fdata, CD_MTFACE);
int uvlay_idx;
- SlideUv *slideuvs=NULL, *suv=NULL, *suv_last=NULL;
+ SlideUv *slideuvs=NULL, *suv=NULL, *suv_last=NULL;
float uv_tmp[2];
LinkNode *fuv_link;
-
+
short event, draw=1;
short mval[2], mvalo[2];
- char str[128];
+ char str[128];
float labda = 0.0f;
-
-// initNumInput(&num);
-
-// view3d_get_object_project_mat(curarea, obedit, projectMat);
-
- mvalo[0] = -1; mvalo[1] = -1;
- numsel =0;
-
+
+ initNumInput(&num);
+
+ view3d_get_object_project_mat(curarea, G.obedit, projectMat, viewMat);
+
+ mvalo[0] = -1; mvalo[1] = -1;
+ numsel =0;
+
// Get number of selected edges and clear some flags
for(eed=em->edges.first;eed;eed=eed->next) {
eed->f1 = 0;
- eed->f2 = 0;
+ eed->f2 = 0;
if(eed->f & SELECT) numsel++;
}
-
+
for(ev=em->verts.first;ev;ev=ev->next) {
- ev->f1 = 0;
- }
-
+ ev->f1 = 0;
+ }
+
//Make sure each edge only has 2 faces
// make sure loop doesn't cross face
for(efa=em->faces.first;efa;efa=efa->next) {
@@ -4028,51 +4783,51 @@ useless:
ct++;
efa->e1->f1++;
if(efa->e1->f1 > 2) {
- BKE_report(op->reports, RPT_ERROR, "3+ face edge");
- return 0;
+ error("3+ face edge");
+ return 0;
}
}
if(efa->e2->f & SELECT) {
ct++;
efa->e2->f1++;
if(efa->e2->f1 > 2) {
- BKE_report(op->reports, RPT_ERROR, "3+ face edge");
- return 0;
+ error("3+ face edge");
+ return 0;
}
}
if(efa->e3->f & SELECT) {
ct++;
efa->e3->f1++;
if(efa->e3->f1 > 2) {
- BKE_report(op->reports, RPT_ERROR, "3+ face edge");
- return 0;
+ error("3+ face edge");
+ return 0;
}
}
if(efa->e4 && efa->e4->f & SELECT) {
ct++;
efa->e4->f1++;
if(efa->e4->f1 > 2) {
- BKE_report(op->reports, RPT_ERROR, "3+ face edge");
- return 0;
+ error("3+ face edge");
+ return 0;
}
- }
- // Make sure loop is not 2 edges of same face
+ }
+ // Make sure loop is not 2 edges of same face
if(ct > 1) {
- BKE_report(op->reports, RPT_ERROR, "Loop crosses itself");
- return 0;
+ error("loop crosses itself");
+ return 0;
}
- }
+ }
// Get # of selected verts
- for(ev=em->verts.first;ev;ev=ev->next) {
+ for(ev=em->verts.first;ev;ev=ev->next) {
if(ev->f & SELECT) vertsel++;
- }
-
+ }
+
// Test for multiple segments
if(vertsel > numsel+1) {
- BKE_report(op->reports, RPT_ERROR, "Please choose a single edge loop");
- return 0;
- }
-
+ error("Was not a single edge loop");
+ return 0;
+ }
+
// Get the edgeloop in order - mark f1 with SELECT once added
for(eed=em->edges.first;eed;eed=eed->next) {
if((eed->f & SELECT) && !(eed->f1 & SELECT)) {
@@ -4081,35 +4836,35 @@ useless:
BLI_linklist_prepend(&edgelist,eed);
numadded++;
first = eed;
- last = eed;
+ last = eed;
eed->f1 = SELECT;
- } else {
+ } else {
if(editedge_getSharedVert(eed, last)) {
BLI_linklist_append(&edgelist,eed);
eed->f1 = SELECT;
numadded++;
- last = eed;
+ last = eed;
} else if(editedge_getSharedVert(eed, first)) {
BLI_linklist_prepend(&edgelist,eed);
eed->f1 = SELECT;
numadded++;
- first = eed;
- }
+ first = eed;
+ }
}
- }
+ }
if(eed->next == NULL && numadded != numsel) {
- eed=em->edges.first;
+ eed=em->edges.first;
timesthrough++;
}
-
+
// It looks like there was an unexpected case - Hopefully should not happen
if(timesthrough >= numsel*2) {
- BLI_linklist_free(edgelist,NULL);
- BKE_report(op->reports, RPT_ERROR, "Could not order loop");
- return 0;
+ BLI_linklist_free(edgelist,NULL);
+ error("could not order loop");
+ return 0;
}
}
-
+
// Put the verts in order in a linklist
look = edgelist;
while(look) {
@@ -4120,33 +4875,33 @@ useless:
//This is the first entry takes care of extra vert
if(eed->v1 != temp->v1 && eed->v1 != temp->v2) {
- BLI_linklist_append(&vertlist,eed->v1);
- eed->v1->f1 = 1;
+ BLI_linklist_append(&vertlist,eed->v1);
+ eed->v1->f1 = 1;
} else {
- BLI_linklist_append(&vertlist,eed->v2);
- eed->v2->f1 = 1;
- }
+ BLI_linklist_append(&vertlist,eed->v2);
+ eed->v2->f1 = 1;
+ }
} else {
//This is the case that we only have 1 edge
- BLI_linklist_append(&vertlist,eed->v1);
- eed->v1->f1 = 1;
+ BLI_linklist_append(&vertlist,eed->v1);
+ eed->v1->f1 = 1;
}
- }
+ }
// for all the entries
if(eed->v1->f1 != 1) {
- BLI_linklist_append(&vertlist,eed->v1);
- eed->v1->f1 = 1;
+ BLI_linklist_append(&vertlist,eed->v1);
+ eed->v1->f1 = 1;
} else if(eed->v2->f1 != 1) {
- BLI_linklist_append(&vertlist,eed->v2);
- eed->v2->f1 = 1;
- }
- look = look->next;
- }
-
+ BLI_linklist_append(&vertlist,eed->v2);
+ eed->v2->f1 = 1;
+ }
+ look = look->next;
+ }
+
// populate the SlideVerts
-
- vertgh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "EdgeSlide gh");
- look = vertlist;
+
+ vertgh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ look = vertlist;
while(look) {
i=0;
j=0;
@@ -4162,14 +4917,14 @@ useless:
tempsv->origvert.no[2] = ev->no[2];
// i is total edges that vert is on
// j is total selected edges that vert is on
-
+
for(eed=em->edges.first;eed;eed=eed->next) {
if(eed->v1 == ev || eed->v2 == ev) {
- i++;
+ i++;
if(eed->f & SELECT) {
- j++;
+ j++;
}
- }
+ }
}
// If the vert is in the middle of an edge loop, it touches 2 selected edges and 2 unselected edges
if(i == 4 && j == 2) {
@@ -4179,11 +4934,11 @@ useless:
if(!tempsv->up) {
tempsv->up = eed;
} else if (!(tempsv->down)) {
- tempsv->down = eed;
+ tempsv->down = eed;
}
}
- }
- }
+ }
+ }
}
// If it is on the end of the loop, it touches 1 selected and as least 2 more unselected
if(i >= 3 && j == 1) {
@@ -4195,67 +4950,67 @@ useless:
if(!tempsv->up) {
tempsv->up = efa->e1;
} else if (!(tempsv->down)) {
- tempsv->down = efa->e1;
- }
+ tempsv->down = efa->e1;
+ }
}
if(editedge_containsVert(efa->e2, ev) && efa->e2 != eed) {
if(!tempsv->up) {
tempsv->up = efa->e2;
} else if (!(tempsv->down)) {
- tempsv->down = efa->e2;
- }
- }
+ tempsv->down = efa->e2;
+ }
+ }
if(editedge_containsVert(efa->e3, ev) && efa->e3 != eed) {
if(!tempsv->up) {
tempsv->up = efa->e3;
} else if (!(tempsv->down)) {
- tempsv->down = efa->e3;
- }
- }
+ tempsv->down = efa->e3;
+ }
+ }
if(efa->e4) {
if(editedge_containsVert(efa->e4, ev) && efa->e4 != eed) {
if(!tempsv->up) {
tempsv->up = efa->e4;
} else if (!(tempsv->down)) {
- tempsv->down = efa->e4;
- }
+ tempsv->down = efa->e4;
+ }
}
- }
-
+ }
+
}
}
- }
- }
- }
+ }
+ }
+ }
if(i > 4 && j == 2) {
BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN);
- BLI_linklist_free(vertlist,NULL);
- BLI_linklist_free(edgelist,NULL);
- return 0;
+ BLI_linklist_free(vertlist,NULL);
+ BLI_linklist_free(edgelist,NULL);
+ return 0;
}
BLI_ghash_insert(vertgh,ev,tempsv);
-
- look = look->next;
- }
-
+
+ look = look->next;
+ }
+
// make sure the UPs nad DOWNs are 'faceloops'
// Also find the nearest slidevert to the cursor
-// XXX getmouseco_areawin(mval);
- look = vertlist;
+ getmouseco_areawin(mval);
+ look = vertlist;
nearest = NULL;
- vertdist = -1;
- while(look) {
+ vertdist = -1;
+ while(look) {
tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link);
-
+
if(!tempsv->up || !tempsv->down) {
- BKE_report(op->reports, RPT_ERROR, "Missing rails");
+ error("Missing rails");
BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN);
- BLI_linklist_free(vertlist,NULL);
- BLI_linklist_free(edgelist,NULL);
+ BLI_linklist_free(vertlist,NULL);
+ BLI_linklist_free(edgelist,NULL);
return 0;
}
- if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
+ if(G.f & G_DRAW_EDGELEN) {
if(!(tempsv->up->f & SELECT)) {
tempsv->up->f |= SELECT;
tempsv->up->f2 |= 16;
@@ -4278,43 +5033,43 @@ useless:
if(sv) {
float tempdist, co[2];
- if(!sharesFace(em, tempsv->up,sv->up)) {
+ if(!sharesFace(tempsv->up,sv->up)) {
EditEdge *swap;
swap = sv->up;
sv->up = sv->down;
- sv->down = swap;
+ sv->down = swap;
}
-// view3d_project_float(curarea, tempsv->origvert.co, co, projectMat);
-
+ view3d_project_float(curarea, tempsv->origvert.co, co, projectMat);
+
tempdist = sqrt(pow(co[0] - mval[0],2)+pow(co[1] - mval[1],2));
if(vertdist < 0) {
vertdist = tempdist;
- nearest = (EditVert*)look->link;
+ nearest = (EditVert*)look->link;
} else if ( tempdist < vertdist ) {
vertdist = tempdist;
- nearest = (EditVert*)look->link;
- }
+ nearest = (EditVert*)look->link;
+ }
}
- }
-
-
-
- look = look->next;
- }
-
-
- if (uvlay_tot) { // XXX && (scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) {
+ }
+
+
+
+ look = look->next;
+ }
+
+
+ if (uvlay_tot && (G.scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) {
int maxnum = 0;
uvarray = MEM_callocN( uvlay_tot * sizeof(GHash *), "SlideUVs Array");
suv_last = slideuvs = MEM_callocN( uvlay_tot * (numadded+1) * sizeof(SlideUv), "SlideUVs"); /* uvLayers * verts */
suv = NULL;
-
+
for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
-
- uvarray[uvlay_idx] = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "EdgeSlideUV gh");
-
+
+ uvarray[uvlay_idx] = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
for(ev=em->verts.first;ev;ev=ev->next) {
ev->tmp.l = 0;
}
@@ -4322,25 +5077,25 @@ useless:
while(look) {
float *uv_new;
tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link);
-
+
ev = look->link;
suv = NULL;
for(efa = em->faces.first;efa;efa=efa->next) {
if (ev->tmp.l != -1) { /* test for self, in this case its invalid */
int k=-1; /* face corner */
-
+
/* Is this vert in the faces corner? */
if (efa->v1==ev) k=0;
else if (efa->v2==ev) k=1;
else if (efa->v3==ev) k=2;
else if (efa->v4 && efa->v4==ev) k=3;
-
+
if (k != -1) {
MTFace *tf = CustomData_em_get_n(&em->fdata, efa->data, CD_MTFACE, uvlay_idx);
EditVert *ev_up, *ev_down;
-
+
uv_new = tf->uv[k];
-
+
if (ev->tmp.l) {
if (fabs(suv->origuv[0]-uv_new[0]) > 0.0001 || fabs(suv->origuv[1]-uv_new[1])) {
ev->tmp.l = -1; /* Tag as invalid */
@@ -4358,14 +5113,14 @@ useless:
suv->uv_up = suv->uv_down = NULL;
suv->origuv[0] = uv_new[0];
suv->origuv[1] = uv_new[1];
-
+
BLI_linklist_prepend(&suv->fuv_list, uv_new);
BLI_ghash_insert(uvarray[uvlay_idx],ev,suv);
-
+
suv_last++; /* advance to next slide UV */
maxnum++;
}
-
+
/* Now get the uvs along the up or down edge if we can */
if (suv) {
if (!suv->uv_up) {
@@ -4382,7 +5137,7 @@ useless:
else if (efa->v3==ev_down) suv->uv_down = tf->uv[2];
else if (efa->v4 && efa->v4==ev_down) suv->uv_down = tf->uv[3];
}
-
+
/* Copy the pointers to the face UV's */
BLI_linklist_prepend(&suv->fuv_list, uv_new);
}
@@ -4393,32 +5148,31 @@ useless:
}
} /* end uv layer loop */
} /* end uvlay_tot */
-
-
-
+
+
+
// we should have enough info now to slide
- len = 0.0f;
-
+ len = 0.0f;
+
percp = -1;
while(draw) {
- /* For the % calculation */
- short mval[2];
+ /* For the % calculation */
+ short mval[2];
float rc[2];
float v2[2], v3[2];
EditVert *centerVert, *upVert, *downVert;
-
-// XXX getmouseco_areawin(mval);
-
+
+ getmouseco_areawin(mval);
+
if (!immediate && (mval[0] == mvalo[0] && mval[1] == mvalo[1])) {
PIL_sleep_ms(10);
} else {
- char *p = str;
- int ctrl= 0, shift= 0; // XXX
+ char *p = str;;
mvalo[0] = mval[0];
mvalo[1] = mval[1];
-
+
tempsv = BLI_ghash_lookup(vertgh,nearest);
@@ -4426,55 +5180,55 @@ useless:
upVert = editedge_getOtherVert(tempsv->up, centerVert);
downVert = editedge_getOtherVert(tempsv->down, centerVert);
-// view3d_project_float(curarea, upVert->co, v2, projectMat);
-// view3d_project_float(curarea, downVert->co, v3, projectMat);
+ view3d_project_float(curarea, upVert->co, v2, projectMat);
+ view3d_project_float(curarea, downVert->co, v3, projectMat);
- /* Determine the % on which the loop should be cut */
+ /* Determine the % on which the loop should be cut */
- rc[0]= v3[0]-v2[0];
- rc[1]= v3[1]-v2[1];
+ rc[0]= v3[0]-v2[0];
+ rc[1]= v3[1]-v2[1];
len= rc[0]*rc[0]+ rc[1]*rc[1];
if (len==0) {len = 0.0001;}
- if (shift) {
+ if ((G.qual & LR_SHIFTKEY)==0) {
wasshift = 0;
- labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len;
+ labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len;
}
else {
if (wasshift==0) {
wasshift = 1;
shiftlabda = labda;
- }
- labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len / 10.0 + shiftlabda;
+ }
+ labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len / 10.0 + shiftlabda;
}
+
+ if(labda<=0.0) labda=0.0;
+ else if(labda>=1.0)labda=1.0;
- if(labda<=0.0) labda=0.0;
- else if(labda>=1.0)labda=1.0;
-
- perc=((1-labda)*2)-1;
-
- if(shift == 0 && ctrl==0) {
+ perc=((1-labda)*2)-1;
+
+ if(G.qual == 0) {
perc *= 100;
perc = floor(perc);
perc /= 100;
- } else if (ctrl) {
+ } else if (G.qual == LR_CTRLKEY) {
perc *= 10;
perc = floor(perc);
- perc /= 10;
- }
-
+ perc /= 10;
+ }
+
if(prop == 0) {
len = len_v3v3(upVert->co,downVert->co)*((perc+1)/2);
if(flip == 1) {
len = len_v3v3(upVert->co,downVert->co) - len;
- }
+ }
}
-
- if (0) // XXX hasNumInput(&num))
+
+ if (hasNumInput(&num))
{
-// XXX applyNumInput(&num, &perc);
-
+ applyNumInput(&num, &perc);
+
if (prop)
{
perc = MIN2(perc, 1);
@@ -4489,20 +5243,20 @@ useless:
//Adjust Edgeloop
if(immediate) {
- perc = imperc;
+ perc = imperc;
}
percp = perc;
if(prop) {
- look = vertlist;
- while(look) {
+ look = vertlist;
+ while(look) {
EditVert *tempev;
ev = look->link;
tempsv = BLI_ghash_lookup(vertgh,ev);
-
+
tempev = editedge_getOtherVert((perc>=0)?tempsv->up:tempsv->down, ev);
interp_v3_v3v3(ev->co, tempsv->origvert.co, tempev->co, fabs(perc));
-
- if (0) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) {
+
+ if (G.scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) {
for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev );
if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) {
@@ -4515,14 +5269,14 @@ useless:
}
}
}
-
- look = look->next;
+
+ look = look->next;
}
}
else {
- //Non prop code
- look = vertlist;
- while(look) {
+ //Non prop code
+ look = vertlist;
+ while(look) {
float newlen;
ev = look->link;
tempsv = BLI_ghash_lookup(vertgh,ev);
@@ -4530,8 +5284,8 @@ useless:
if(newlen > 1.0) {newlen = 1.0;}
if(newlen < 0.0) {newlen = 0.0;}
if(flip == 0) {
- interp_v3_v3v3(ev->co, editedge_getOtherVert(tempsv->down,ev)->co, editedge_getOtherVert(tempsv->up,ev)->co, fabs(newlen));
- if (0) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) {
+ interp_v3_v3v3(ev->co, editedge_getOtherVert(tempsv->down,ev)->co, editedge_getOtherVert(tempsv->up,ev)->co, fabs(newlen));
+ if (G.scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) {
/* dont do anything if no UVs */
for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev );
@@ -4546,9 +5300,9 @@ useless:
}
}
} else{
- interp_v3_v3v3(ev->co, editedge_getOtherVert(tempsv->up,ev)->co, editedge_getOtherVert(tempsv->down,ev)->co, fabs(newlen));
-
- if (0) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) {
+ interp_v3_v3v3(ev->co, editedge_getOtherVert(tempsv->up,ev)->co, editedge_getOtherVert(tempsv->down,ev)->co, fabs(newlen));
+
+ if (G.scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) {
/* dont do anything if no UVs */
for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev );
@@ -4563,23 +5317,23 @@ useless:
}
}
}
- look = look->next;
+ look = look->next;
}
}
-
+
// Highlight the Control Edges
-// scrarea_do_windraw(curarea);
-// persp(PERSP_VIEW);
-// glPushMatrix();
-// mymultmatrix(obedit->obmat);
+ scrarea_do_windraw(curarea);
+ persp(PERSP_VIEW);
+ glPushMatrix();
+ mymultmatrix(G.obedit->obmat);
- glColor3ub(0, 255, 0);
+ glColor3ub(0, 255, 0);
glBegin(GL_LINES);
glVertex3fv(upVert->co);
glVertex3fv(downVert->co);
- glEnd();
-
+ glEnd();
+
if(prop == 0) {
// draw start edge for non-prop
glPointSize(5);
@@ -4588,25 +5342,25 @@ useless:
if(flip) {
glVertex3fv(upVert->co);
} else {
- glVertex3fv(downVert->co);
+ glVertex3fv(downVert->co);
}
- glEnd();
+ glEnd();
}
-
-
- glPopMatrix();
+
+
+ glPopMatrix();
if(prop) {
p += sprintf(str, "(P)ercentage: ");
} else {
p += sprintf(str, "Non (P)rop Length: ");
}
-
- if (0) // XXX hasNumInput(&num))
+
+ if (hasNumInput(&num))
{
char num_str[20];
-
- // XX outputNumInput(&num, num_str);
+
+ outputNumInput(&num, num_str);
p += sprintf(p, "%s", num_str);
}
else
@@ -4620,20 +5374,20 @@ useless:
p += sprintf(p, "%f", len);
}
}
-
-
+
+
if (prop == 0) {
p += sprintf(p, ", Press (F) to flip control side");
}
-// headerprint(str);
-// screen_swapbuffers();
+ headerprint(str);
+ screen_swapbuffers();
}
if(!immediate) {
while(qtest()) {
- short val=0;
- event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle
-
+ short val=0;
+ event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle
+
/* val==0 on key-release event */
if (val) {
if(ELEM(event, ESCKEY, RIGHTMOUSE)) {
@@ -4645,72 +5399,72 @@ useless:
} else if(ELEM3(event, PADENTER, LEFTMOUSE, RETKEY)) {
draw = 0; // End looping now
} else if(event==MIDDLEMOUSE) {
- perc = 0;
+ perc = 0;
immediate = 1;
} else if(event==PKEY) {
-// XXX initNumInput(&num); /* reset num input */
+ initNumInput(&num); /* reset num input */
if (prop) {
prop = 0;
-// XXX num.flag |= NUM_NO_NEGATIVE;
+ num.flag |= NUM_NO_NEGATIVE;
}
else {
prop = 1;
}
- mvalo[0] = -1;
+ mvalo[0] = -1;
} else if(event==FKEY) {
- (flip == 1) ? (flip = 0):(flip = 1);
- mvalo[0] = -1;
+ (flip == 1) ? (flip = 0):(flip = 1);
+ mvalo[0] = -1;
} else if(ELEM(event, RIGHTARROWKEY, WHEELUPMOUSE)) { // Scroll through Control Edges
- look = vertlist;
- while(look) {
+ look = vertlist;
+ while(look) {
if(nearest == (EditVert*)look->link) {
if(look->next == NULL) {
- nearest = (EditVert*)vertlist->link;
+ nearest = (EditVert*)vertlist->link;
} else {
nearest = (EditVert*)look->next->link;
- }
+ }
mvalo[0] = -1;
- break;
+ break;
}
- look = look->next;
- }
+ look = look->next;
+ }
} else if(ELEM(event, LEFTARROWKEY, WHEELDOWNMOUSE)) { // Scroll through Control Edges
- look = vertlist;
- while(look) {
+ look = vertlist;
+ while(look) {
if(look->next) {
if(look->next->link == nearest) {
nearest = (EditVert*)look->link;
mvalo[0] = -1;
break;
- }
+ }
} else {
if((EditVert*)vertlist->link == nearest) {
nearest = look->link;
mvalo[0] = -1;
- break;
- }
- }
- look = look->next;
- }
+ break;
+ }
+ }
+ look = look->next;
+ }
}
-
-// XXX if (handleNumInput(&num, event))
+
+ if (handleNumInput(&num, event))
{
mvalo[0] = -1; /* NEED A BETTER WAY TO TRIGGER REDRAW */
}
}
-
- }
+
+ }
} else {
draw = 0;
}
-// DAG_id_tag_update(obedit->data, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
}
-
-
- if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
+
+
+ if(G.f & G_DRAW_EDGELEN) {
look = vertlist;
- while(look) {
+ while(look) {
tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link);
if(tempsv != NULL) {
tempsv->up->f &= !SELECT;
@@ -4719,26 +5473,26 @@ useless:
look = look->next;
}
}
-
-// force_draw(0);
-
+
+ force_draw(0);
+
if(!immediate)
EM_automerge(0);
-// DAG_id_tag_update(obedit->data, 0);
-// scrarea_queue_winredraw(curarea);
-
- //BLI_ghash_free(edgesgh, freeGHash, NULL);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ scrarea_queue_winredraw(curarea);
+
+ //BLI_ghash_free(edgesgh, freeGHash, NULL);
BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN);
- BLI_linklist_free(vertlist,NULL);
- BLI_linklist_free(edgelist,NULL);
-
- if (uvlay_tot) { // XXX && (scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) {
+ BLI_linklist_free(vertlist,NULL);
+ BLI_linklist_free(edgelist,NULL);
+
+ if (uvlay_tot && (G.scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) {
for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
BLI_ghash_free(uvarray[uvlay_idx], NULL, NULL);
}
MEM_freeN(uvarray);
MEM_freeN(slideuvs);
-
+
suv = suv_last-1;
while (suv >= slideuvs) {
if (suv->fuv_list) {
@@ -4746,61 +5500,45 @@ useless:
}
suv--;
}
+
+ allqueue(REDRAWIMAGE, 0);
}
if(cancel == 1) {
return -1;
}
-
- return 1;
-}
-#endif // END OF XXX
-
-int EdgeLoopDelete(EditMesh *UNUSED(em), wmOperator *UNUSED(op))
-{
-#if 0 //XXX won't work with new edgeslide
-
- /* temporal flag setting so we keep UVs when deleting edge loops,
- * this is a bit of a hack but it works how you would want in almost all cases */
- // short uvcalc_flag_orig = 0; // XXX scene->toolsettings->uvcalc_flag;
- // scene->toolsettings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT;
-
- if(!EdgeSlide(em, op, 1, 1)) {
- return 0;
+ else {
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode) {
+ sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode);
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
}
-
- /* restore uvcalc flag */
- // scene->toolsettings->uvcalc_flag = uvcalc_flag_orig;
-
- EM_select_more(em);
- removedoublesflag(em, 1,0, 0.001);
- EM_select_flush(em);
- // DAG_id_tag_update(obedit->data, 0);
- return 1;
#endif
- return 0;
+ }
+ return 1;
}
-
/* -------------------- More tools ------------------ */
-#if 0
-void mesh_set_face_flags(EditMesh *em, short mode)
+
+void mesh_set_face_flags(short mode)
{
+ EditMesh *em = G.editMesh;
EditFace *efa;
MTFace *tface;
- short m_tex=0, m_shared=0,
+ short m_tex=0, m_tiles=0, m_shared=0,
m_light=0, m_invis=0, m_collision=0,
m_twoside=0, m_obcolor=0, m_halo=0,
m_billboard=0, m_shadow=0, m_text=0,
m_sort=0;
short flag = 0, change = 0;
-
-// XXX if (!EM_texFaceCheck()) {
-// error("not a mesh with uv/image layers");
-// return;
-// }
-
+
+ if (!EM_texFaceCheck()) {
+ error("not a mesh with uv/image layers");
+ return;
+ }
+
add_numbut(0, TOG|SHO, "Texture", 0, 0, &m_tex, NULL);
+ add_numbut(1, TOG|SHO, "Tiles", 0, 0, &m_tiles, NULL);
add_numbut(2, TOG|SHO, "Light", 0, 0, &m_light, NULL);
add_numbut(3, TOG|SHO, "Invisible", 0, 0, &m_invis, NULL);
add_numbut(4, TOG|SHO, "Collision", 0, 0, &m_collision, NULL);
@@ -4812,16 +5550,17 @@ void mesh_set_face_flags(EditMesh *em, short mode)
add_numbut(10, TOG|SHO, "Shadow", 0, 0, &m_shadow, NULL);
add_numbut(11, TOG|SHO, "Text", 0, 0, &m_text, NULL);
add_numbut(12, TOG|SHO, "Sort", 0, 0, &m_sort, NULL);
-
+
if (!do_clever_numbuts((mode ? "Set Flags" : "Clear Flags"), 13, REDRAW))
- return;
-
+ return;
+
/* these 2 cant both be on */
if (mode) /* are we seeting*/
if (m_halo)
m_billboard = 0;
-
+
if (m_tex) flag |= TF_TEX;
+ if (m_tiles) flag |= TF_TILES;
if (m_shared) flag |= TF_SHAREDCOL;
if (m_light) flag |= TF_LIGHT;
if (m_invis) flag |= TF_INVISIBLE;
@@ -4833,10 +5572,10 @@ void mesh_set_face_flags(EditMesh *em, short mode)
if (m_shadow) flag |= TF_SHADOW;
if (m_text) flag |= TF_BMFONT;
if (m_sort) flag |= TF_ALPHASORT;
-
+
if (flag==0)
return;
-
+
efa= em->faces.first;
while(efa) {
if(efa->f & SELECT) {
@@ -4847,79 +5586,111 @@ void mesh_set_face_flags(EditMesh *em, short mode)
}
efa= efa->next;
}
-
+
+ if (change) {
+ BIF_undo_push((mode ? "Set Flags" : "Clear Flags"));
+
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ }
}
-#endif
-/********************** Rip Operator *************************/
+void mesh_set_smooth_faces(short event)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ if(G.obedit==0) return;
+
+ if(G.obedit->type != OB_MESH) return;
+
+ efa= em->faces.first;
+ while(efa) {
+ if(efa->f & SELECT) {
+ if(event==1) efa->flag |= ME_SMOOTH;
+ else if(event==0) efa->flag &= ~ME_SMOOTH;
+ }
+ efa= efa->next;
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+
+ if(event==1) BIF_undo_push("Set Smooth");
+ else if(event==0) BIF_undo_push("Set Solid");
+}
/* helper to find edge for edge_rip */
-static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *co2, short *mval)
+static float mesh_rip_edgedist(float mat[][4], float *co1, float *co2, short *mval)
{
float vec1[3], vec2[3], mvalf[2];
-
- view3d_project_float(ar, co1, vec1, mat);
- view3d_project_float(ar, co2, vec2, mat);
+
+ view3d_project_float(curarea, co1, vec1, mat);
+ view3d_project_float(curarea, co2, vec2, mat);
mvalf[0]= (float)mval[0];
mvalf[1]= (float)mval[1];
-
+
return dist_to_line_segment_v2(mvalf, vec1, vec2);
}
/* helper for below */
-static void mesh_rip_setface(EditMesh *em, EditFace *sefa)
+static void mesh_rip_setface(EditFace *sefa)
{
/* put new vertices & edges in best face */
if(sefa->v1->tmp.v) sefa->v1= sefa->v1->tmp.v;
if(sefa->v2->tmp.v) sefa->v2= sefa->v2->tmp.v;
if(sefa->v3->tmp.v) sefa->v3= sefa->v3->tmp.v;
if(sefa->v4 && sefa->v4->tmp.v) sefa->v4= sefa->v4->tmp.v;
-
- sefa->e1= addedgelist(em, sefa->v1, sefa->v2, sefa->e1);
- sefa->e2= addedgelist(em, sefa->v2, sefa->v3, sefa->e2);
+
+ sefa->e1= addedgelist(sefa->v1, sefa->v2, sefa->e1);
+ sefa->e2= addedgelist(sefa->v2, sefa->v3, sefa->e2);
if(sefa->v4) {
- sefa->e3= addedgelist(em, sefa->v3, sefa->v4, sefa->e3);
- sefa->e4= addedgelist(em, sefa->v4, sefa->v1, sefa->e4);
+ sefa->e3= addedgelist(sefa->v3, sefa->v4, sefa->e3);
+ sefa->e4= addedgelist(sefa->v4, sefa->v1, sefa->e4);
}
- else
- sefa->e3= addedgelist(em, sefa->v3, sefa->v1, sefa->e3);
-
+ else
+ sefa->e3= addedgelist(sefa->v3, sefa->v1, sefa->e3);
+
}
/* based on mouse cursor position, it defines how is being ripped */
-static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+void mesh_rip(void)
{
- ARegion *ar= CTX_wm_region(C);
- RegionView3D *rv3d= ar->regiondata;
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ extern void faceloop_select(EditEdge *startedge, int select);
+ EditMesh *em = G.editMesh;
EditVert *eve, *nextve;
EditEdge *eed, *seed= NULL;
EditFace *efa, *sefa= NULL;
- float projectMat[4][4], vec[3], dist, mindist;
- short doit= 1, *mval= event->mval;
-
+ float projectMat[4][4], viewMat[4][4], vec[3], dist, mindist;
+ short doit= 1, mval[2],propmode,prop;
+
+ propmode = G.scene->prop_mode;
+ G.scene->prop_mode = 0;
+ prop = G.scene->proportional;
+ G.scene->proportional = 0;
+
/* select flush... vertices are important */
- EM_selectmode_set(em);
-
- view3d_get_object_project_mat(rv3d, obedit, projectMat);
+ EM_selectmode_set();
+
+ getmouseco_areawin(mval);
+ view3d_get_object_project_mat(curarea, G.obedit, projectMat, viewMat);
/* find best face, exclude triangles and break on face select or faces with 2 edges select */
mindist= 1000000.0f;
for(efa= em->faces.first; efa; efa=efa->next) {
- if( efa->f & 1)
+ if( efa->f & 1)
break;
if(efa->v4 && faceselectedOR(efa, SELECT) ) {
int totsel=0;
-
+
if(efa->e1->f & SELECT) totsel++;
if(efa->e2->f & SELECT) totsel++;
if(efa->e3->f & SELECT) totsel++;
if(efa->e4->f & SELECT) totsel++;
-
+
if(totsel>1)
break;
- view3d_project_float(ar, efa->cent, vec, projectMat);
+ view3d_project_float(curarea, efa->cent, vec, projectMat);
dist= sqrt( (vec[0]-mval[0])*(vec[0]-mval[0]) + (vec[1]-mval[1])*(vec[1]-mval[1]) );
if(dist<mindist) {
mindist= dist;
@@ -4927,42 +5698,40 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
}
}
-
+
if(efa) {
- BKE_report(op->reports, RPT_WARNING, "Can't perform ripping with faces selected this way");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
+ error("Can't perform ripping with faces selected this way");
+ return;
}
if(sefa==NULL) {
- BKE_report(op->reports, RPT_WARNING, "No proper selection or faces included");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
+ error("No proper selection or faces included");
+ return;
}
-
+
/* duplicate vertices, new vertices get selected */
for(eve = em->verts.last; eve; eve= eve->prev) {
eve->tmp.v = NULL;
if(eve->f & SELECT) {
- eve->tmp.v = addvertlist(em, eve->co, eve);
+ eve->tmp.v = addvertlist(eve->co, eve);
eve->f &= ~SELECT;
eve->tmp.v->f |= SELECT;
}
}
-
+
/* find the best candidate edge */
/* or one of sefa edges is selected... */
if(sefa->e1->f & SELECT) seed= sefa->e2;
if(sefa->e2->f & SELECT) seed= sefa->e1;
if(sefa->e3->f & SELECT) seed= sefa->e2;
if(sefa->e4 && sefa->e4->f & SELECT) seed= sefa->e3;
-
+
/* or we do the distance trick */
if(seed==NULL) {
mindist= 1000000.0f;
if(sefa->e1->v1->tmp.v || sefa->e1->v2->tmp.v) {
- dist = mesh_rip_edgedist(ar, projectMat,
- sefa->e1->v1->co,
+ dist = mesh_rip_edgedist(projectMat,
+ sefa->e1->v1->co,
sefa->e1->v2->co, mval);
if(dist<mindist) {
seed= sefa->e1;
@@ -4970,8 +5739,8 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
}
if(sefa->e2->v1->tmp.v || sefa->e2->v2->tmp.v) {
- dist = mesh_rip_edgedist(ar, projectMat,
- sefa->e2->v1->co,
+ dist = mesh_rip_edgedist(projectMat,
+ sefa->e2->v1->co,
sefa->e2->v2->co, mval);
if(dist<mindist) {
seed= sefa->e2;
@@ -4979,8 +5748,8 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
}
if(sefa->e3->v1->tmp.v || sefa->e3->v2->tmp.v) {
- dist= mesh_rip_edgedist(ar, projectMat,
- sefa->e3->v1->co,
+ dist= mesh_rip_edgedist(projectMat,
+ sefa->e3->v1->co,
sefa->e3->v2->co, mval);
if(dist<mindist) {
seed= sefa->e3;
@@ -4988,8 +5757,8 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
}
if(sefa->e4 && (sefa->e4->v1->tmp.v || sefa->e4->v2->tmp.v)) {
- dist= mesh_rip_edgedist(ar, projectMat,
- sefa->e4->v1->co,
+ dist= mesh_rip_edgedist(projectMat,
+ sefa->e4->v1->co,
sefa->e4->v2->co, mval);
if(dist<mindist) {
seed= sefa->e4;
@@ -4997,27 +5766,25 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
}
}
-
+
if(seed==NULL) { // never happens?
- BKE_report(op->reports, RPT_WARNING, "No proper edge found to start");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
+ error("No proper edge found to start");
+ return;
}
-
- faceloop_select(em, seed, 2); // tmp abuse for finding all edges that need duplicated, returns OK faces with f1
+
+ faceloop_select(seed, 2); // tmp abuse for finding all edges that need duplicated, returns OK faces with f1
/* duplicate edges in the loop, with at least 1 vertex selected, needed for selection flip */
for(eed = em->edges.last; eed; eed= eed->prev) {
eed->tmp.v = NULL;
if((eed->v1->tmp.v) || (eed->v2->tmp.v)) {
EditEdge *newed;
-
- newed= addedgelist(em, eed->v1->tmp.v?eed->v1->tmp.v:eed->v1,
+
+ newed= addedgelist(eed->v1->tmp.v?eed->v1->tmp.v:eed->v1,
eed->v2->tmp.v?eed->v2->tmp.v:eed->v2, eed);
if(eed->f & SELECT) {
- EM_select_edge(eed, 0);
- EM_remove_selection(em, eed, EDITEDGE);
- EM_select_edge(newed, 1);
+ eed->f &= ~SELECT;
+ newed->f |= SELECT;
}
eed->tmp.v = (EditVert *)newed;
}
@@ -5027,28 +5794,28 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
/* put new vertices & edges && flag in best face */
- mesh_rip_setface(em, sefa);
-
+ mesh_rip_setface(sefa);
+
/* starting with neighbours of best face, we loop over the seam */
sefa->f1= 2;
doit= 1;
while(doit) {
doit= 0;
-
+
for(efa= em->faces.first; efa; efa=efa->next) {
/* new vert in face */
- if (efa->v1->tmp.v || efa->v2->tmp.v ||
+ if (efa->v1->tmp.v || efa->v2->tmp.v ||
efa->v3->tmp.v || (efa->v4 && efa->v4->tmp.v)) {
/* face is tagged with loop */
if(efa->f1==1) {
- mesh_rip_setface(em, efa);
+ mesh_rip_setface(efa);
efa->f1= 2;
doit= 1;
}
}
- }
+ }
}
-
+
/* remove loose edges, that were part of a ripped face */
for(eve = em->verts.first; eve; eve= eve->next) eve->f1= 0;
for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
@@ -5058,14 +5825,14 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
efa->e3->f1= 1;
if(efa->e4) efa->e4->f1= 1;
}
-
+
for(eed = em->edges.last; eed; eed= seed) {
seed= eed->prev;
if(eed->f1==0) {
- if(eed->v1->tmp.v || eed->v2->tmp.v ||
+ if(eed->v1->tmp.v || eed->v2->tmp.v ||
(eed->v1->f & SELECT) || (eed->v2->f & SELECT)) {
- remedge(em, eed);
- free_editedge(em, eed);
+ remedge(eed);
+ free_editedge(eed);
eed= NULL;
}
}
@@ -5074,228 +5841,227 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
eed->v2->f1= 1;
}
}
-
+
/* and remove loose selected vertices, that got duplicated accidentally */
for(eve = em->verts.first; eve; eve= nextve) {
nextve= eve->next;
if(eve->f1==0 && (eve->tmp.v || (eve->f & SELECT))) {
BLI_remlink(&em->verts,eve);
- free_editvert(em, eve);
+ free_editvert(eve);
}
}
+
+ countall(); // apparently always needed when adding stuff, derived mesh
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
-// RNA_enum_set(op->ptr, "proportional", 0);
-// RNA_boolean_set(op->ptr, "mirror", 0);
-// WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_rip(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Rip";
- ot->description= "Rip selection from mesh (quads only)";
- ot->idname= "MESH_OT_rip";
-
- /* api callbacks */
- ot->invoke= mesh_rip_invoke;
- ot->poll= EM_view3d_poll;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode) {
+ sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode);
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+ }
+#endif
- /* to give to transform */
- /* XXX Transform this in a macro */
- Transform_Properties(ot, P_CONSTRAINT|P_MIRROR);
+ BIF_TransformSetUndo("Rip");
+ initTransform(TFM_TRANSLATION, 0);
+ Transform();
+
+ G.scene->prop_mode = propmode;
+ G.scene->proportional = prop;
}
-
-/************************ Shape Operators *************************/
-
-static void shape_propagate(Object *obedit, EditMesh *em, wmOperator *op)
-{
+void shape_propagate(){
+ EditMesh *em = G.editMesh;
EditVert *ev = NULL;
- Mesh* me = (Mesh*)obedit->data;
+ Mesh* me = (Mesh*)G.obedit->data;
Key* ky = NULL;
KeyBlock* kb = NULL;
-
-
+ Base* base=NULL;
+
+
if(me->key){
ky = me->key;
} else {
- BKE_report(op->reports, RPT_WARNING, "Object Has No Key");
+ error("Object Has No Key");
return;
- }
+ }
if(ky->block.first){
for(ev = em->verts.first; ev ; ev = ev->next){
if(ev->f & SELECT){
for(kb=ky->block.first;kb;kb = kb->next){
- float *data;
- data = kb->data;
- VECCOPY(data+(ev->keyindex*3),ev->co);
+ float *data;
+ data = kb->data;
+ VECCOPY(data+(ev->keyindex*3),ev->co);
}
- }
- }
+ }
+ }
} else {
- BKE_report(op->reports, RPT_WARNING, "Object Has No Blendshapes");
- return;
+ error("Object Has No Blendshapes");
+ return;
}
-
-#if 0
+
//TAG Mesh Objects that share this data
- for(base = scene->base.first; base; base = base->next){
+ for(base = G.scene->base.first; base; base = base->next){
if(base->object && base->object->data == me){
base->object->recalc = OB_RECALC_DATA;
}
- }
-#endif
+ }
- DAG_id_tag_update(obedit->data, 0);
- return;
+ BIF_undo_push("Propagate Blendshape Verts");
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ return;
}
-
-static int shape_propagate_to_all_exec(bContext *C, wmOperator *op)
+void shape_copy_from_lerp(KeyBlock* thisBlock, KeyBlock* fromBlock)
{
- Object *obedit= CTX_data_edit_object(C);
- Mesh *me= obedit->data;
- EditMesh *em= BKE_mesh_get_editmesh(me);
-
- shape_propagate(obedit, em, op);
-
- DAG_id_tag_update(&me->id, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
-
- return OPERATOR_FINISHED;
-}
-
-
-void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Shape Propagate";
- ot->description= "Apply selected vertex locations to all other shape keys";
- ot->idname= "MESH_OT_shape_propagate_to_all";
-
- /* api callbacks */
- ot->exec= shape_propagate_to_all_exec;
- ot->poll= ED_operator_editmesh;
+ EditMesh *em = G.editMesh;
+ EditVert *ev = NULL;
+ short mval[2], curval[2], event = 0, finished = 0, canceled = 0, fullcopy=0 ;
+ float perc = 0;
+ char str[64];
+ float *data, *odata;
+
+ data = fromBlock->data;
+ odata = thisBlock->data;
+
+ getmouseco_areawin(mval);
+ curval[0] = mval[0] + 1; curval[1] = mval[1] + 1;
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
+ while (finished == 0)
+ {
+ getmouseco_areawin(mval);
+ if (mval[0] != curval[0] || mval[1] != curval[1])
+ {
+
+ if(mval[0] > curval[0])
+ perc += 0.1;
+ else if(mval[0] < curval[0])
+ perc -= 0.1;
+
+ if(perc < 0) perc = 0;
+ if(perc > 1) perc = 1;
+
+ curval[0] = mval[0];
+ curval[1] = mval[1];
-static int blend_from_shape_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- Mesh *me= obedit->data;
- Key *key= me->key;
- EditMesh *em= BKE_mesh_get_editmesh(me);
- EditVert *eve;
- KeyBlock *kb;
- float *data, co[3];
- float blend= RNA_float_get(op->ptr, "blend");
- int shape= RNA_enum_get(op->ptr, "shape");
- int add= RNA_int_get(op->ptr, "add");
- int blended= 0;
+ if(fullcopy == 1){
+ perc = 1;
+ }
- if(key && (kb= BLI_findlink(&key->block, shape))) {
- data= kb->data;
+ for(ev = em->verts.first; ev ; ev = ev->next){
+ if(ev->f & SELECT){
+ interp_v3_v3v3(ev->co,odata+(ev->keyindex*3),data+(ev->keyindex*3),perc);
+ }
+ }
+ sprintf(str,"Blending at %d%c MMB to Copy at 100%c",(int)(perc*100),'%','%');
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ headerprint(str);
+ force_draw(0);
- for(eve=em->verts.first; eve; eve=eve->next){
- if(eve->f & SELECT) {
- if(eve->keyindex >= 0 && eve->keyindex < kb->totelem) {
- VECCOPY(co, data + eve->keyindex*3);
+ if(fullcopy == 1){
+ break;
+ }
- if(add) {
- mul_v3_fl(co, blend);
- add_v3_v3(eve->co, co);
- }
- else
- interp_v3_v3v3(eve->co, eve->co, co, blend);
+ } else {
+ PIL_sleep_ms(10);
+ }
- blended= 1;
+ while(qtest()) {
+ short val=0;
+ event= extern_qread(&val);
+ if(val){
+ if(ELEM3(event, PADENTER, LEFTMOUSE, RETKEY)){
+ finished = 1;
}
- }
+ else if (event == MIDDLEMOUSE){
+ fullcopy = 1;
+ }
+ else if (ELEM3(event,ESCKEY,RIGHTMOUSE,RIGHTMOUSE)){
+ canceled = 1;
+ finished = 1;
+ }
+ }
}
}
+ if(!canceled)
+ BIF_undo_push("Copy Blendshape Verts");
+ else
+ for(ev = em->verts.first; ev ; ev = ev->next){
+ if(ev->f & SELECT){
+ VECCOPY(ev->co, odata+(ev->keyindex*3));
+ }
+ }
+ return;
+}
- BKE_mesh_end_editmesh(me, em);
-
- if(!blended)
- return OPERATOR_CANCELLED;
-
- DAG_id_tag_update(&me->id, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
- return OPERATOR_FINISHED;
-}
-static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
-{
- Object *obedit= CTX_data_edit_object(C);
- Mesh *me= (obedit) ? obedit->data : NULL;
- Key *key;
- KeyBlock *kb, *actkb;
- EnumPropertyItem tmp= {0, "", 0, "", ""}, *item= NULL;
- int totitem= 0, a;
-
- if(obedit && obedit->type == OB_MESH) {
- key= me->key;
- actkb= ob_get_keyblock(obedit);
-
- if(key && actkb) {
- for(kb=key->block.first, a=0; kb; kb=kb->next, a++) {
- if(kb != actkb) {
- tmp.value= a;
- tmp.identifier= kb->name;
- tmp.name= kb->name;
- RNA_enum_item_add(&item, &totitem, &tmp);
- }
+void shape_copy_select_from()
+{
+ Mesh* me = (Mesh*)G.obedit->data;
+ EditMesh *em = G.editMesh;
+ EditVert *ev = NULL;
+ int totverts = 0,curshape = G.obedit->shapenr;
+
+ Key* ky = NULL;
+ KeyBlock *kb = NULL,*thisBlock = NULL;
+ int maxlen=32, nr=0, a=0;
+ char *menu;
+
+ if(me->key){
+ ky = me->key;
+ } else {
+ error("Object Has No Key");
+ return;
+ }
+
+ if(ky->block.first){
+ for(kb=ky->block.first;kb;kb = kb->next){
+ maxlen += 40; // Size of a block name
+ if(a == curshape-1){
+ thisBlock = kb;
}
+
+ a++;
}
+ a=0;
+ menu = MEM_callocN(maxlen, "Copy Shape Menu Text");
+ strcpy(menu, "Copy Vert Positions from Shape %t|");
+ for(kb=ky->block.first;kb;kb = kb->next){
+ if(a != curshape-1){
+ sprintf(menu,"%s %s %cx%d|",menu,kb->name,'%',a);
+ }
+ a++;
+ }
+ nr = pupmenu_col(menu, 20);
+ MEM_freeN(menu);
+ } else {
+ error("Object Has No Blendshapes");
+ return;
}
-
- RNA_enum_item_end(&item, &totitem);
- *free= 1;
-
- return item;
-}
-
-void MESH_OT_blend_from_shape(wmOperatorType *ot)
-{
- PropertyRNA *prop;
- static EnumPropertyItem shape_items[]= {{0, NULL, 0, NULL, NULL}};
-
- /* identifiers */
- ot->name= "Blend From Shape";
- ot->description= "Blend in shape from a shape key";
- ot->idname= "MESH_OT_blend_from_shape";
-
- /* api callbacks */
- ot->exec= blend_from_shape_exec;
- ot->invoke= WM_operator_props_popup;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- prop= RNA_def_enum(ot->srna, "shape", shape_items, 0, "Shape", "Shape key to use for blending.");
- RNA_def_enum_funcs(prop, shape_itemf);
- RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor.", -2.0f, 2.0f);
- RNA_def_boolean(ot->srna, "add", 1, "Add", "Add rather then blend between shapes.");
+
+ a = 0;
+
+ for(kb=ky->block.first;kb;kb = kb->next){
+ if(a == nr){
+
+ for(ev = em->verts.first;ev;ev = ev->next){
+ totverts++;
+ }
+
+ if(me->totvert != totverts){
+ error("Shape Has had Verts Added/Removed, please cycle editmode before copying");
+ return;
+ }
+ shape_copy_from_lerp(thisBlock,kb);
+
+ return;
+ }
+ a++;
+ }
+ return;
}
-/************************ Merge Operator *************************/
-
/* Collection Routines|Currently used by the improved merge code*/
/* buildEdge_collection() creates a list of lists*/
/* these lists are filled with edges that are topologically connected.*/
@@ -5314,51 +6080,51 @@ typedef struct CollectedEdge{
#define MERGELIMIT 0.000001
-static void build_edgecollection(EditMesh *em, ListBase *allcollections)
+static void build_edgecollection(ListBase *allcollections)
{
EditEdge *eed;
Collection *edgecollection, *newcollection;
CollectedEdge *newedge;
-
+
int currtag = 1;
short ebalanced = 0;
short collectionfound = 0;
-
- for (eed=em->edges.first; eed; eed = eed->next){
+
+ for (eed=G.editMesh->edges.first; eed; eed = eed->next){
eed->tmp.l = 0;
eed->v1->tmp.l = 0;
eed->v2->tmp.l = 0;
}
-
+
/*1st pass*/
- for(eed=em->edges.first; eed; eed=eed->next){
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next){
if(eed->f&SELECT){
eed->v1->tmp.l = currtag;
eed->v2->tmp.l = currtag;
currtag +=1;
}
}
-
+
/*2nd pass - Brute force. Loop through selected faces until there are no 'unbalanced' edges left (those with both vertices 'tmp.l' tag matching */
while(ebalanced == 0){
ebalanced = 1;
- for(eed=em->edges.first; eed; eed = eed->next){
+ for(eed=G.editMesh->edges.first; eed; eed = eed->next){
if(eed->f&SELECT){
if(eed->v1->tmp.l != eed->v2->tmp.l) /*unbalanced*/{
- if(eed->v1->tmp.l > eed->v2->tmp.l && eed->v2->tmp.l !=0) eed->v1->tmp.l = eed->v2->tmp.l;
- else if(eed->v1 != 0) eed->v2->tmp.l = eed->v1->tmp.l;
+ if(eed->v1->tmp.l > eed->v2->tmp.l && eed->v2->tmp.l !=0) eed->v1->tmp.l = eed->v2->tmp.l;
+ else if(eed->v1 != 0) eed->v2->tmp.l = eed->v1->tmp.l;
ebalanced = 0;
}
}
}
}
-
+
/*3rd pass, set all the edge flags (unnessecary?)*/
- for(eed=em->edges.first; eed; eed = eed->next){
+ for(eed=G.editMesh->edges.first; eed; eed = eed->next){
if(eed->f&SELECT) eed->tmp.l = eed->v1->tmp.l;
}
-
- for(eed=em->edges.first; eed; eed=eed->next){
+
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next){
if(eed->f&SELECT){
if(allcollections->first){
for(edgecollection = allcollections->first; edgecollection; edgecollection=edgecollection->next){
@@ -5377,28 +6143,28 @@ static void build_edgecollection(EditMesh *em, ListBase *allcollections)
newcollection->index = eed->tmp.l;
newcollection->collectionbase.first = 0;
newcollection->collectionbase.last = 0;
-
+
newedge = MEM_mallocN(sizeof(CollectedEdge), "collected edge");
newedge->eed = eed;
-
+
BLI_addtail(&(newcollection->collectionbase), newedge);
BLI_addtail(allcollections, newcollection);
}
}
-
+
}
}
static void freecollections(ListBase *allcollections)
{
struct Collection *curcollection;
-
+
for(curcollection = allcollections->first; curcollection; curcollection = curcollection->next)
BLI_freelistN(&(curcollection->collectionbase));
BLI_freelistN(allcollections);
}
-/*Begin UV Edge Collapse Code
+/*Begin UV Edge Collapse Code
Like Edge subdivide, Edge Collapse should handle UV's intelligently, but since UV's are a per-face attribute, normal edge collapse will fail
in areas such as the boundries of 'UV islands'. So for each edge collection we need to build a set of 'welded' UV vertices and edges for it.
The welded UV edges can then be sorted and collapsed.
@@ -5428,18 +6194,18 @@ typedef struct wUVEdge{
typedef struct wUVEdgeCollect{ /*used for grouping*/
struct wUVEdgeCollect *next, *prev;
wUVEdge *uved;
- int id;
+ int id;
} wUVEdgeCollect;
-static void append_weldedUV(EditMesh *em, EditFace *efa, EditVert *eve, int tfindex, ListBase *uvverts)
+static void append_weldedUV(EditFace *efa, EditVert *eve, int tfindex, ListBase *uvverts)
{
wUV *curwvert, *newwvert;
wUVNode *newnode;
int found;
- MTFace *tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
+ MTFace *tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
+
found = 0;
-
+
for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){
if(curwvert->eve == eve && curwvert->u == tf->uv[tfindex][0] && curwvert->v == tf->uv[tfindex][1]){
newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node");
@@ -5450,47 +6216,47 @@ static void append_weldedUV(EditMesh *em, EditFace *efa, EditVert *eve, int tfin
break;
}
}
-
+
if(!found){
newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node");
newnode->u = &(tf->uv[tfindex][0]);
newnode->v = &(tf->uv[tfindex][1]);
-
+
newwvert = MEM_callocN(sizeof(wUV), "Welded UV Vert");
newwvert->u = *(newnode->u);
newwvert->v = *(newnode->v);
newwvert->eve = eve;
-
+
BLI_addtail(&(newwvert->nodes), newnode);
BLI_addtail(uvverts, newwvert);
-
+
}
}
-static void build_weldedUVs(EditMesh *em, ListBase *uvverts)
+static void build_weldedUVs(ListBase *uvverts)
{
EditFace *efa;
- for(efa=em->faces.first; efa; efa=efa->next){
- if(efa->v1->f1) append_weldedUV(em, efa, efa->v1, 0, uvverts);
- if(efa->v2->f1) append_weldedUV(em, efa, efa->v2, 1, uvverts);
- if(efa->v3->f1) append_weldedUV(em, efa, efa->v3, 2, uvverts);
- if(efa->v4 && efa->v4->f1) append_weldedUV(em, efa, efa->v4, 3, uvverts);
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ if(efa->v1->f1) append_weldedUV(efa, efa->v1, 0, uvverts);
+ if(efa->v2->f1) append_weldedUV(efa, efa->v2, 1, uvverts);
+ if(efa->v3->f1) append_weldedUV(efa, efa->v3, 2, uvverts);
+ if(efa->v4 && efa->v4->f1) append_weldedUV(efa, efa->v4, 3, uvverts);
}
}
-static void append_weldedUVEdge(EditMesh *em, EditFace *efa, EditEdge *eed, ListBase *uvedges)
+static void append_weldedUVEdge(EditFace *efa, EditEdge *eed, ListBase *uvedges)
{
wUVEdge *curwedge, *newwedge;
int v1tfindex, v2tfindex, found;
- MTFace *tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
+ MTFace *tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
+
found = 0;
-
+
if(eed->v1 == efa->v1) v1tfindex = 0;
else if(eed->v1 == efa->v2) v1tfindex = 1;
else if(eed->v1 == efa->v3) v1tfindex = 2;
else /* if(eed->v1 == efa->v4) */ v1tfindex = 3;
-
+
if(eed->v2 == efa->v1) v2tfindex = 0;
else if(eed->v2 == efa->v2) v2tfindex = 1;
else if(eed->v2 == efa->v3) v2tfindex = 2;
@@ -5502,7 +6268,7 @@ static void append_weldedUVEdge(EditMesh *em, EditFace *efa, EditEdge *eed, List
break; //do nothing, we don't need another welded uv edge
}
}
-
+
if(!found){
newwedge = MEM_callocN(sizeof(wUVEdge), "Welded UV Edge");
newwedge->v1uv[0] = tf->uv[v1tfindex][0];
@@ -5510,25 +6276,25 @@ static void append_weldedUVEdge(EditMesh *em, EditFace *efa, EditEdge *eed, List
newwedge->v2uv[0] = tf->uv[v2tfindex][0];
newwedge->v2uv[1] = tf->uv[v2tfindex][1];
newwedge->eed = eed;
-
+
BLI_addtail(uvedges, newwedge);
}
}
-static void build_weldedUVEdges(EditMesh *em, ListBase *uvedges, ListBase *uvverts)
+static void build_weldedUVEdges(ListBase *uvedges, ListBase *uvverts)
{
wUV *curwvert;
wUVEdge *curwedge;
EditFace *efa;
-
- for(efa=em->faces.first; efa; efa=efa->next){
- if(efa->e1->f1) append_weldedUVEdge(em, efa, efa->e1, uvedges);
- if(efa->e2->f1) append_weldedUVEdge(em, efa, efa->e2, uvedges);
- if(efa->e3->f1) append_weldedUVEdge(em, efa, efa->e3, uvedges);
- if(efa->e4 && efa->e4->f1) append_weldedUVEdge(em, efa, efa->e4, uvedges);
+
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ if(efa->e1->f1) append_weldedUVEdge(efa, efa->e1, uvedges);
+ if(efa->e2->f1) append_weldedUVEdge(efa, efa->e2, uvedges);
+ if(efa->e3->f1) append_weldedUVEdge(efa, efa->e3, uvedges);
+ if(efa->e4 && efa->e4->f1) append_weldedUVEdge(efa, efa->e4, uvedges);
}
-
-
+
+
//link vertices: for each uvedge, search uvverts to populate v1 and v2 pointers
for(curwedge=uvedges->first; curwedge; curwedge=curwedge->next){
for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){
@@ -5553,7 +6319,7 @@ static void free_weldedUVs(ListBase *uvverts)
BLI_freelistN(uvverts);
}
-static void collapse_edgeuvs(EditMesh *em)
+static void collapse_edgeuvs(void)
{
ListBase uvedges, uvverts, allcollections;
wUVEdge *curwedge;
@@ -5563,22 +6329,22 @@ static void collapse_edgeuvs(EditMesh *em)
int curtag, balanced, collectionfound= 0, vcount;
float avg[2];
- if (!EM_texFaceCheck(em))
+ if (!EM_texFaceCheck())
return;
-
+
uvverts.first = uvverts.last = uvedges.first = uvedges.last = allcollections.first = allcollections.last = NULL;
-
- build_weldedUVs(em, &uvverts);
- build_weldedUVEdges(em, &uvedges, &uvverts);
-
+
+ build_weldedUVs(&uvverts);
+ build_weldedUVEdges(&uvedges, &uvverts);
+
curtag = 0;
-
+
for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){
curwedge->v1->f = curtag;
curwedge->v2->f = curtag;
curtag +=1;
}
-
+
balanced = 0;
while(!balanced){
balanced = 1;
@@ -5590,10 +6356,10 @@ static void collapse_edgeuvs(EditMesh *em)
}
}
}
-
+
for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next) curwedge->f = curwedge->v1->f;
-
-
+
+
for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){
if(allcollections.first){
for(wuvecollection = allcollections.first; wuvecollection; wuvecollection=wuvecollection->next){
@@ -5604,7 +6370,7 @@ static void collapse_edgeuvs(EditMesh *em)
collectionfound = 1;
break;
}
-
+
else collectionfound = 0;
}
}
@@ -5613,32 +6379,32 @@ static void collapse_edgeuvs(EditMesh *em)
newcollection->index = curwedge->f;
newcollection->collectionbase.first = 0;
newcollection->collectionbase.last = 0;
-
+
newcollectedwuve = MEM_callocN(sizeof(wUVEdgeCollect), "Collected Welded UV Edge");
newcollectedwuve->uved = curwedge;
-
+
BLI_addtail(&(newcollection->collectionbase), newcollectedwuve);
BLI_addtail(&allcollections, newcollection);
}
}
-
+
for(wuvecollection=allcollections.first; wuvecollection; wuvecollection=wuvecollection->next){
-
+
vcount = avg[0] = avg[1] = 0;
-
+
for(collectedwuve= wuvecollection->collectionbase.first; collectedwuve; collectedwuve = collectedwuve->next){
avg[0] += collectedwuve->uved->v1uv[0];
avg[1] += collectedwuve->uved->v1uv[1];
-
+
avg[0] += collectedwuve->uved->v2uv[0];
avg[1] += collectedwuve->uved->v2uv[1];
-
+
vcount +=2;
-
+
}
-
+
avg[0] /= vcount; avg[1] /= vcount;
-
+
for(collectedwuve= wuvecollection->collectionbase.first; collectedwuve; collectedwuve = collectedwuve->next){
for(curwnode=collectedwuve->uved->v1->nodes.first; curwnode; curwnode=curwnode->next){
*(curwnode->u) = avg[0];
@@ -5650,7 +6416,7 @@ static void collapse_edgeuvs(EditMesh *em)
}
}
}
-
+
free_weldedUVs(&uvverts);
BLI_freelistN(&uvedges);
freecollections(&allcollections);
@@ -5658,22 +6424,22 @@ static void collapse_edgeuvs(EditMesh *em)
/*End UV Edge collapse code*/
-static void collapseuvs(EditMesh *em, EditVert *mergevert)
+static void collapseuvs(EditVert *mergevert)
{
EditFace *efa;
MTFace *tf;
int uvcount;
float uvav[2];
- if (!EM_texFaceCheck(em))
+ if (!EM_texFaceCheck())
return;
-
+
uvcount = 0;
uvav[0] = 0;
uvav[1] = 0;
-
- for(efa = em->faces.first; efa; efa=efa->next){
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ for(efa = G.editMesh->faces.first; efa; efa=efa->next){
+ tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
if(efa->v1->f1 && ELEM(mergevert, NULL, efa->v1)) {
uvav[0] += tf->uv[0][0];
@@ -5681,7 +6447,7 @@ static void collapseuvs(EditMesh *em, EditVert *mergevert)
uvcount += 1;
}
if(efa->v2->f1 && ELEM(mergevert, NULL, efa->v2)){
- uvav[0] += tf->uv[1][0];
+ uvav[0] += tf->uv[1][0];
uvav[1] += tf->uv[1][1];
uvcount += 1;
}
@@ -5696,20 +6462,20 @@ static void collapseuvs(EditMesh *em, EditVert *mergevert)
uvcount += 1;
}
}
-
+
if(uvcount > 0) {
- uvav[0] /= uvcount;
+ uvav[0] /= uvcount;
uvav[1] /= uvcount;
-
- for(efa = em->faces.first; efa; efa=efa->next){
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ for(efa = G.editMesh->faces.first; efa; efa=efa->next){
+ tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
if(efa->v1->f1){
tf->uv[0][0] = uvav[0];
tf->uv[0][1] = uvav[1];
}
if(efa->v2->f1){
- tf->uv[1][0] = uvav[0];
+ tf->uv[1][0] = uvav[0];
tf->uv[1][1] = uvav[1];
}
if(efa->v3->f1){
@@ -5724,351 +6490,192 @@ static void collapseuvs(EditMesh *em, EditVert *mergevert)
}
}
-static int collapseEdges(EditMesh *em)
+int collapseEdges(void)
{
EditVert *eve;
EditEdge *eed;
-
+
ListBase allcollections;
CollectedEdge *curredge;
Collection *edgecollection;
-
- int totedges, mergecount,vcount /*, groupcount*/;
+
+ int totedges, groupcount, mergecount,vcount;
float avgcount[3];
-
+
allcollections.first = 0;
allcollections.last = 0;
-
+
mergecount = 0;
-
- build_edgecollection(em, &allcollections);
- /*groupcount = BLI_countlist(&allcollections);*/ /*UNUSED*/
-
-
+
+ if(multires_test()) return 0;
+
+ build_edgecollection(&allcollections);
+ groupcount = BLI_countlist(&allcollections);
+
+
for(edgecollection = allcollections.first; edgecollection; edgecollection = edgecollection->next){
totedges = BLI_countlist(&(edgecollection->collectionbase));
mergecount += totedges;
avgcount[0] = 0; avgcount[1] = 0; avgcount[2] = 0;
-
+
vcount = 0;
-
+
for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){
avgcount[0] += ((EditEdge*)curredge->eed)->v1->co[0];
avgcount[1] += ((EditEdge*)curredge->eed)->v1->co[1];
avgcount[2] += ((EditEdge*)curredge->eed)->v1->co[2];
-
+
avgcount[0] += ((EditEdge*)curredge->eed)->v2->co[0];
avgcount[1] += ((EditEdge*)curredge->eed)->v2->co[1];
avgcount[2] += ((EditEdge*)curredge->eed)->v2->co[2];
-
+
vcount +=2;
}
-
+
avgcount[0] /= vcount; avgcount[1] /=vcount; avgcount[2] /= vcount;
-
+
for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){
VECCOPY(((EditEdge*)curredge->eed)->v1->co,avgcount);
VECCOPY(((EditEdge*)curredge->eed)->v2->co,avgcount);
}
-
- if (EM_texFaceCheck(em)) {
+
+ if (EM_texFaceCheck()) {
/*uv collapse*/
- for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = 0;
- for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = 0;
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next) eve->f1 = 0;
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = 0;
for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){
curredge->eed->v1->f1 = 1;
curredge->eed->v2->f1 = 1;
curredge->eed->f1 = 1;
}
- collapse_edgeuvs(em);
+ collapse_edgeuvs();
}
-
+
}
freecollections(&allcollections);
- removedoublesflag(em, 1, 0, MERGELIMIT);
-
+ removedoublesflag(1, 0, MERGELIMIT);
+ /*get rid of this!*/
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
return mergecount;
}
-static int merge_firstlast(EditMesh *em, int first, int uvmerge)
+int merge_firstlast(int first, int uvmerge)
{
EditVert *eve,*mergevert;
EditSelection *ese;
-
+
+ if(multires_test()) return 0;
+
/* do sanity check in mergemenu in edit.c ?*/
- if(first == 0){
- ese = em->selected.last;
+ if(first == 0){
+ ese = G.editMesh->selected.last;
mergevert= (EditVert*)ese->data;
}
- else{
- ese = em->selected.first;
+ else{
+ ese = G.editMesh->selected.first;
mergevert = (EditVert*)ese->data;
}
-
+
if(mergevert->f&SELECT){
- for (eve=em->verts.first; eve; eve=eve->next){
+ for (eve=G.editMesh->verts.first; eve; eve=eve->next){
if (eve->f&SELECT)
VECCOPY(eve->co,mergevert->co);
}
}
-
- if(uvmerge && CustomData_has_layer(&em->fdata, CD_MTFACE)){
-
- for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = 0;
- for(eve=em->verts.first; eve; eve=eve->next){
- if(eve->f&SELECT) eve->f1 = 1;
- }
- collapseuvs(em, mergevert);
- }
-
- return removedoublesflag(em, 1, 0, MERGELIMIT);
-}
-
-static void em_snap_to_center(EditMesh *em)
-{
- EditVert *eve;
- float cent[3] = {0.0f, 0.0f, 0.0f};
- int i=0;
-
- for (eve=em->verts.first; eve; eve=eve->next) {
- if (eve->f & SELECT) {
- add_v3_v3(cent, eve->co);
- i++;
- }
- }
-
- if (!i)
- return;
-
- mul_v3_fl(cent, 1.0f / (float)i);
-
- for (eve=em->verts.first; eve; eve=eve->next) {
- if (eve->f & SELECT) {
- VECCOPY(eve->co, cent);
- }
- }
-}
-
-static void em_snap_to_cursor(EditMesh *em, bContext *C)
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob= CTX_data_edit_object(C);
- View3D *v3d = CTX_wm_view3d(C);
- EditVert *eve;
- float co[3], *vco, invmat[4][4];
+
+ if(uvmerge && CustomData_has_layer(&G.editMesh->fdata, CD_MTFACE)){
- invert_m4_m4(invmat, ob->obmat);
-
- vco = give_cursor(scene, v3d);
- VECCOPY(co, vco);
- mul_m4_v3(invmat, co);
-
- for (eve=em->verts.first; eve; eve=eve->next) {
- if (eve->f & SELECT) {
- VECCOPY(eve->co, co);
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next) eve->f1 = 0;
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next){
+ if(eve->f&SELECT) eve->f1 = 1;
}
+ collapseuvs(mergevert);
}
+
+ countall();
+ return removedoublesflag(1, 0, MERGELIMIT);
}
-static int merge_target(bContext *C, EditMesh *em, int target, int uvmerge)
+int merge_target(int target, int uvmerge)
{
EditVert *eve;
-
- // XXX not working
- if(target) em_snap_to_cursor(em, C);
- else em_snap_to_center(em);
-
- if(uvmerge && CustomData_has_layer(&em->fdata, CD_MTFACE)){
- for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = 0;
- for(eve=em->verts.first; eve; eve=eve->next){
+
+ if(multires_test()) return 0;
+
+ if(target) snap_sel_to_curs();
+ else snap_to_center();
+
+ if(uvmerge && CustomData_has_layer(&G.editMesh->fdata, CD_MTFACE)){
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next) eve->f1 = 0;
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next){
if(eve->f&SELECT) eve->f1 = 1;
}
- collapseuvs(em, NULL);
+ collapseuvs(NULL);
}
-
- return removedoublesflag(em, 1, 0, MERGELIMIT);
-}
-#undef MERGELIMIT
-
-static int merge_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
- int count= 0, uvs= RNA_boolean_get(op->ptr, "uvs");
- EditSelection *ese;
-
- switch(RNA_enum_get(op->ptr, "type")) {
- case 3:
- count = merge_target(C, em, 0, uvs);
- break;
- case 4:
- count = merge_target(C, em, 1, uvs);
- break;
- case 1:
- ese= (EditSelection *)em->selected.last;
- if(ese && ese->type == EDITVERT) {
- count = merge_firstlast(em, 0, uvs);
- } else {
- BKE_report(op->reports, RPT_WARNING, "no last selected vertex set");
- }
- break;
- case 6:
- ese= (EditSelection *)em->selected.first;
- if(ese && ese->type == EDITVERT) {
- count = merge_firstlast(em, 1, uvs);
- }
- else {
- BKE_report(op->reports, RPT_WARNING, "no last selected vertex set");
- }
- break;
- case 5:
- count = collapseEdges(em);
- break;
- }
-
- if(!count)
- return OPERATOR_CANCELLED;
-
- recalc_editnormals(em);
- BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s.", count, (count==1)?"ex":"ices");
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-static EnumPropertyItem merge_type_items[]= {
- {6, "FIRST", 0, "At First", ""},
- {1, "LAST", 0, "At Last", ""},
- {3, "CENTER", 0, "At Center", ""},
- {4, "CURSOR", 0, "At Cursor", ""},
- {5, "COLLAPSE", 0, "Collapse", ""},
- {0, NULL, 0, NULL, NULL}};
-
-static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
-{
- Object *obedit= CTX_data_edit_object(C);
- EnumPropertyItem *item= NULL;
- int totitem= 0;
-
- if (C==NULL) {
- return merge_type_items;
- }
-
- if(obedit && obedit->type == OB_MESH) {
- EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
-
- if(em->selectmode & SCE_SELECT_VERTEX) {
- if(em->selected.first && em->selected.last &&
- ((EditSelection*)em->selected.first)->type == EDITVERT && ((EditSelection*)em->selected.last)->type == EDITVERT) {
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
- }
- else if(em->selected.first && ((EditSelection*)em->selected.first)->type == EDITVERT)
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
- else if(em->selected.last && ((EditSelection*)em->selected.last)->type == EDITVERT)
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
- }
-
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 3);
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 4);
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 5);
- }
-
- RNA_enum_item_end(&item, &totitem);
- *free= 1;
-
- return item;
-}
-
-void MESH_OT_merge(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name= "Merge";
- ot->description= "Merge selected vertices";
- ot->idname= "MESH_OT_merge";
-
- /* api callbacks */
- ot->exec= merge_exec;
- ot->invoke= WM_menu_invoke;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- prop= RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use.");
- RNA_def_enum_funcs(prop, merge_type_itemf);
- ot->prop= prop;
- RNA_def_boolean(ot->srna, "uvs", 0, "UVs", "Move UVs according to merge.");
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ return removedoublesflag(1, 0, MERGELIMIT);
+
}
+#undef MERGELIMIT
-/************************ Vertex Path Operator *************************/
-
-typedef struct PathNode {
+typedef struct PathNode{
int u;
int visited;
ListBase edges;
} PathNode;
-typedef struct PathEdge {
+typedef struct PathEdge{
struct PathEdge *next, *prev;
int v;
float w;
} PathEdge;
-#define PATH_SELECT_EDGE_LENGTH 0
-#define PATH_SELECT_TOPOLOGICAL 1
-
-static int select_vertex_path_exec(bContext *C, wmOperator *op)
+void pathselect(void)
{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
EditVert *eve, *s, *t;
EditEdge *eed;
+ EditSelection *ese;
PathEdge *newpe, *currpe;
PathNode *currpn;
PathNode *Q;
int v, *previous, pathvert, pnindex; /*pnindex redundant?*/
- int unbalanced, totnodes;
+ int unbalanced, totnodes;
+ short physical;
float *cost;
- int type= RNA_enum_get(op->ptr, "type");
Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/
-
+
s = t = NULL;
- for(eve=em->verts.first; eve; eve=eve->next) {
- if(eve->f&SELECT) {
- if(s == NULL) s= eve;
- else if(t == NULL) t= eve;
- else {
- /* more than two vertices are selected,
- show warning message and cancel operator */
- s = t = NULL;
- break;
- }
-
- }
-
+
+ countall(); /*paranoid?*/
+
+ ese = ((EditSelection*)G.editMesh->selected.last);
+ if(ese && ese->type == EDITVERT && ese->prev && ese->prev->type == EDITVERT){
+ physical= pupmenu("Distance Method? %t|Edge Length%x1|Topological%x0");
+
+ t = (EditVert*)ese->data;
+ s = (EditVert*)ese->prev->data;
+
/*need to find out if t is actually reachable by s....*/
- eve->f1 = 0;
- }
-
- if(s != NULL && t != NULL) {
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next){
+ eve->f1 = 0;
+ }
+
s->f1 = 1;
-
+
unbalanced = 1;
totnodes = 1;
while(unbalanced){
unbalanced = 0;
- for(eed=em->edges.first; eed; eed=eed->next){
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next){
if(!eed->h){
- if(eed->v1->f1 && !eed->v2->f1){
+ if(eed->v1->f1 && !eed->v2->f1){
eed->v2->f1 = 1;
totnodes++;
unbalanced = 1;
@@ -6081,11 +6688,13 @@ static int select_vertex_path_exec(bContext *C, wmOperator *op)
}
}
}
-
- if(s->f1 && t->f1){ /* t can be reached by s */
+
+
+
+ if(s->f1 && t->f1){ /*t can be reached by s*/
Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes");
totnodes = 0;
- for(eve=em->verts.first; eve; eve=eve->next){
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next){
if(eve->f1){
Q[totnodes].u = totnodes;
Q[totnodes].edges.first = 0;
@@ -6096,27 +6705,27 @@ static int select_vertex_path_exec(bContext *C, wmOperator *op)
}
else eve->tmp.p = NULL;
}
-
- for(eed=em->edges.first; eed; eed=eed->next){
+
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next){
if(!eed->h){
if(eed->v1->f1){
currpn = ((PathNode*)eed->v1->tmp.p);
-
+
newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
newpe->v = ((PathNode*)eed->v2->tmp.p)->u;
- if (type == PATH_SELECT_EDGE_LENGTH) {
+ if(physical){
newpe->w = len_v3v3(eed->v1->co, eed->v2->co);
}
else newpe->w = 1;
newpe->next = 0;
newpe->prev = 0;
BLI_addtail(&(currpn->edges), newpe);
- }
+ }
if(eed->v2->f1){
- currpn = ((PathNode*)eed->v2->tmp.p);
+ currpn = ((PathNode*)eed->v2->tmp.p);
newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
newpe->v = ((PathNode*)eed->v1->tmp.p)->u;
- if (type == PATH_SELECT_EDGE_LENGTH) {
+ if(physical){
newpe->w = len_v3v3(eed->v1->co, eed->v2->co);
}
else newpe->w = 1;
@@ -6126,28 +6735,28 @@ static int select_vertex_path_exec(bContext *C, wmOperator *op)
}
}
}
-
+
heap = BLI_heap_new();
cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs");
previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices");
-
+
for(v=0; v < totnodes; v++){
cost[v] = 1000000;
previous[v] = -1; /*array of indices*/
}
-
+
pnindex = ((PathNode*)s->tmp.p)->u;
cost[pnindex] = 0;
BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(pnindex));
-
+
while( !BLI_heap_empty(heap) ){
-
+
pnindex = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
currpn = &(Q[pnindex]);
-
+
if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/
break;
-
+
for(currpe=currpn->edges.first; currpe; currpe=currpe->next){
if(!Q[currpe->v].visited){
if( cost[currpe->v] > (cost[currpn->u ] + currpe->w) ){
@@ -6159,125 +6768,78 @@ static int select_vertex_path_exec(bContext *C, wmOperator *op)
}
}
}
-
+
pathvert = ((PathNode*)t->tmp.p)->u;
while(pathvert != -1){
- for(eve=em->verts.first; eve; eve=eve->next){
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next){
if(eve->f1){
if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT;
}
}
pathvert = previous[pathvert];
}
-
+
for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges));
MEM_freeN(Q);
MEM_freeN(cost);
MEM_freeN(previous);
BLI_heap_free(heap, NULL);
- EM_select_flush(em);
+ EM_select_flush();
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
}
}
- else {
- BKE_mesh_end_editmesh(obedit->data, em);
- BKE_report(op->reports, RPT_WARNING, "Path Selection requires that exactly two vertices be selected");
- return OPERATOR_CANCELLED;
+ else{
+ error("Path Selection requires that exactly two vertices be selected");
+ return;
}
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
-
- return OPERATOR_FINISHED;
}
-void MESH_OT_select_vertex_path(wmOperatorType *ot)
+void region_to_loop(void)
{
- static const EnumPropertyItem type_items[] = {
- {PATH_SELECT_EDGE_LENGTH, "EDGE_LENGTH", 0, "Edge Length", NULL},
- {PATH_SELECT_TOPOLOGICAL, "TOPOLOGICAL", 0, "Topological", NULL},
- {0, NULL, 0, NULL, NULL}};
-
- /* identifiers */
- ot->name= "Select Vertex Path";
- ot->description= "Select shortest path between two vertices by distance type";
- ot->idname= "MESH_OT_select_vertex_path";
-
- /* api callbacks */
- ot->exec= select_vertex_path_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- ot->prop= RNA_def_enum(ot->srna, "type", type_items, PATH_SELECT_EDGE_LENGTH, "Type", "Method to compute distance.");
-}
-
-/********************** Region/Loop Operators *************************/
-
-static int region_to_loop(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
EditEdge *eed;
EditFace *efa;
- int selected= 0;
-
- for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = 0;
-
- for(efa=em->faces.first; efa; efa=efa->next){
- if(efa->f&SELECT){
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4)
- efa->e4->f1++;
-
- selected= 1;
+
+ if(G.totfacesel){
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = 0;
+
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ if(efa->f&SELECT){
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ if(efa->e4)
+ efa->e4->f1++;
+ }
}
- }
-
- if(!selected)
- return OPERATOR_CANCELLED;
-
- EM_clear_flag_all(em, SELECT);
+
+ EM_clear_flag_all(SELECT);
+
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next){
+ if(eed->f1 == 1) EM_select_edge(eed, 1);
+ }
+
+ G.scene->selectmode = SCE_SELECT_EDGE;
+ EM_selectmode_set();
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ BIF_undo_push("Face Region to Edge Loop");
- for(eed=em->edges.first; eed; eed=eed->next){
- if(eed->f1 == 1) EM_select_edge(eed, 1);
}
-
- em->selectmode = SCE_SELECT_EDGE;
- CTX_data_tool_settings(C)->selectmode= em->selectmode;
- EM_selectmode_set(em);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_region_to_loop(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Region to Loop";
- ot->description= "Select a region as a loop of connected edges";
- ot->idname= "MESH_OT_region_to_loop";
-
- /* api callbacks */
- ot->exec= region_to_loop;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
-static int validate_loop(EditMesh *em, Collection *edgecollection)
+static int validate_loop(Collection *edgecollection)
{
EditEdge *eed;
EditFace *efa;
CollectedEdge *curredge;
-
+
/*1st test*/
for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
curredge->eed->v1->f1 = 0;
@@ -6291,10 +6853,10 @@ static int validate_loop(EditMesh *em, Collection *edgecollection)
if(curredge->eed->v1->f1 > 2) return(0); else
if(curredge->eed->v2->f1 > 2) return(0);
}
-
+
/*2nd test*/
- for(eed = em->edges.first; eed; eed=eed->next) eed->f1 = 0;
- for(efa=em->faces.first; efa; efa=efa->next){
+ for(eed = G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = 0;
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
efa->e1->f1++;
efa->e2->f1++;
efa->e3->f1++;
@@ -6306,22 +6868,22 @@ static int validate_loop(EditMesh *em, Collection *edgecollection)
return(1);
}
-static int loop_bisect(EditMesh *em, Collection *edgecollection){
-
+static int loop_bisect(Collection *edgecollection){
+
EditFace *efa, *sf1, *sf2;
EditEdge *eed, *sed;
CollectedEdge *curredge;
int totsf1, totsf2, unbalanced,balancededges;
-
- for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = eed->f2 = 0;
- for(efa=em->faces.first; efa; efa=efa->next) efa->f1 = 0;
-
+
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = eed->f2 = 0;
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next) efa->f1 = 0;
+
for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next) curredge->eed->f1 = 1;
-
+
sf1 = sf2 = NULL;
sed = ((CollectedEdge*)edgecollection->collectionbase.first)->eed;
-
- for(efa=em->faces.first; efa; efa=efa->next){
+
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
if(sf2) break;
else if(sf1){
if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf2 = efa;
@@ -6330,29 +6892,29 @@ static int loop_bisect(EditMesh *em, Collection *edgecollection){
if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf1 = efa;
}
}
-
+
if(sf1==NULL || sf2==NULL)
return(-1);
-
+
if(!(sf1->e1->f1)) sf1->e1->f2 = 1;
if(!(sf1->e2->f1)) sf1->e2->f2 = 1;
if(!(sf1->e3->f1)) sf1->e3->f2 = 1;
if(sf1->e4 && !(sf1->e4->f1)) sf1->e4->f2 = 1;
sf1->f1 = 1;
totsf1 = 1;
-
+
if(!(sf2->e1->f1)) sf2->e1->f2 = 2;
if(!(sf2->e2->f1)) sf2->e2->f2 = 2;
if(!(sf2->e3->f1)) sf2->e3->f2 = 2;
if(sf2->e4 && !(sf2->e4->f1)) sf2->e4->f2 = 2;
sf2->f1 = 2;
totsf2 = 1;
-
+
/*do sf1*/
unbalanced = 1;
while(unbalanced){
unbalanced = 0;
- for(efa=em->faces.first; efa; efa=efa->next){
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
balancededges = 0;
if(efa->f1 == 0){
if(efa->e1->f2 == 1 || efa->e2->f2 == 1 || efa->e3->f2 == 1 || ( (efa->e4) ? efa->e4->f2 == 1 : 0) ){
@@ -6369,12 +6931,12 @@ static int loop_bisect(EditMesh *em, Collection *edgecollection){
}
}
}
-
+
/*do sf2*/
unbalanced = 1;
while(unbalanced){
unbalanced = 0;
- for(efa=em->faces.first; efa; efa=efa->next){
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
balancededges = 0;
if(efa->f1 == 0){
if(efa->e1->f2 == 2 || efa->e2->f2 == 2 || efa->e3->f2 == 2 || ( (efa->e4) ? efa->e4->f2 == 2 : 0) ){
@@ -6391,28 +6953,24 @@ static int loop_bisect(EditMesh *em, Collection *edgecollection){
}
}
}
-
+
if(totsf1 < totsf2) return(1);
else return(2);
}
-static int loop_to_region(bContext *C, wmOperator *UNUSED(op))
+void loop_to_region(void)
{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
-
EditFace *efa;
ListBase allcollections={NULL,NULL};
Collection *edgecollection;
int testflag;
-
- build_edgecollection(em, &allcollections);
-
+
+ build_edgecollection(&allcollections);
+
for(edgecollection = (Collection *)allcollections.first; edgecollection; edgecollection=edgecollection->next){
- if(validate_loop(em, edgecollection)){
- testflag = loop_bisect(em, edgecollection);
- for(efa=em->faces.first; efa; efa=efa->next){
+ if(validate_loop(edgecollection)){
+ testflag = loop_bisect(edgecollection);
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
if(efa->f1 == testflag){
if(efa->f&SELECT) EM_select_face(efa, 0);
else EM_select_face(efa,1);
@@ -6420,90 +6978,72 @@ static int loop_to_region(bContext *C, wmOperator *UNUSED(op))
}
}
}
-
- for(efa=em->faces.first; efa; efa=efa->next){ /*fix this*/
+
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){ /*fix this*/
if(efa->f&SELECT) EM_select_face(efa,1);
}
-
+
+ countall();
freecollections(&allcollections);
- BKE_mesh_end_editmesh(obedit->data, em);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_loop_to_region(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Loop to Region";
- ot->description= "Select a loop of connected edges as a region";
- ot->idname= "MESH_OT_loop_to_region";
-
- /* api callbacks */
- ot->exec= loop_to_region;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ BIF_undo_push("Edge Loop to Face Region");
}
-/********************** UV/Color Operators *************************/
-// XXX please check if these functions do what you want them to
/* texface and vertex color editmode tools for the face menu */
-static int mesh_rotate_uvs(bContext *C, wmOperator *op)
+void mesh_rotate_uvs(void)
{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
+ EditMesh *em = G.editMesh;
EditFace *efa;
- short change = 0;
+ short change = 0, ccw;
MTFace *tf;
float u1, v1;
- int dir= RNA_enum_get(op->ptr, "direction");
-
- if (!EM_texFaceCheck(em)) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
+
+ if (!EM_texFaceCheck()) {
+ error("mesh has no uv/image layers");
+ return;
}
-
+
+ ccw = (G.qual == LR_SHIFTKEY);
+
for(efa=em->faces.first; efa; efa=efa->next) {
if (efa->f & SELECT) {
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
u1= tf->uv[0][0];
v1= tf->uv[0][1];
-
- if (dir == DIRECTION_CCW) {
+
+ if (ccw) {
if(efa->v4) {
tf->uv[0][0]= tf->uv[3][0];
tf->uv[0][1]= tf->uv[3][1];
-
+
tf->uv[3][0]= tf->uv[2][0];
tf->uv[3][1]= tf->uv[2][1];
} else {
tf->uv[0][0]= tf->uv[2][0];
tf->uv[0][1]= tf->uv[2][1];
}
-
+
tf->uv[2][0]= tf->uv[1][0];
tf->uv[2][1]= tf->uv[1][1];
-
+
tf->uv[1][0]= u1;
tf->uv[1][1]= v1;
- } else {
+ } else {
tf->uv[0][0]= tf->uv[1][0];
tf->uv[0][1]= tf->uv[1][1];
-
+
tf->uv[1][0]= tf->uv[2][0];
tf->uv[1][1]= tf->uv[2][1];
-
+
if(efa->v4) {
tf->uv[2][0]= tf->uv[3][0];
tf->uv[2][1]= tf->uv[3][1];
-
+
tf->uv[3][0]= u1;
tf->uv[3][1]= v1;
}
@@ -6515,46 +7055,40 @@ static int mesh_rotate_uvs(bContext *C, wmOperator *op)
change = 1;
}
}
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- if(!change)
- return OPERATOR_CANCELLED;
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
+
+ if (change) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Rotate UV face");
+ }
}
-static int mesh_mirror_uvs(bContext *C, wmOperator *op)
+void mesh_mirror_uvs(void)
{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
+ EditMesh *em = G.editMesh;
EditFace *efa;
- short change = 0;
+ short change = 0, altaxis;
MTFace *tf;
float u1, v1;
- int axis= RNA_enum_get(op->ptr, "axis");
-
- if (!EM_texFaceCheck(em)) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
+
+ if (!EM_texFaceCheck()) {
+ error("mesh has no uv/image layers");
+ return;
}
-
+
+ altaxis = (G.qual == LR_SHIFTKEY);
+
for(efa=em->faces.first; efa; efa=efa->next) {
if (efa->f & SELECT) {
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if (axis == AXIS_Y) {
+ if (altaxis) {
u1= tf->uv[1][0];
v1= tf->uv[1][1];
if(efa->v4) {
-
+
tf->uv[1][0]= tf->uv[2][0];
tf->uv[1][1]= tf->uv[2][1];
-
+
tf->uv[2][0]= u1;
tf->uv[2][1]= v1;
@@ -6563,7 +7097,7 @@ static int mesh_mirror_uvs(bContext *C, wmOperator *op)
tf->uv[3][0]= tf->uv[0][0];
tf->uv[3][1]= tf->uv[0][1];
-
+
tf->uv[0][0]= u1;
tf->uv[0][1]= v1;
}
@@ -6573,15 +7107,15 @@ static int mesh_mirror_uvs(bContext *C, wmOperator *op)
tf->uv[2][0]= u1;
tf->uv[2][1]= v1;
}
-
+
} else {
u1= tf->uv[0][0];
v1= tf->uv[0][1];
if(efa->v4) {
-
+
tf->uv[0][0]= tf->uv[1][0];
tf->uv[0][1]= tf->uv[1][1];
-
+
tf->uv[1][0]= u1;
tf->uv[1][1]= v1;
@@ -6590,7 +7124,7 @@ static int mesh_mirror_uvs(bContext *C, wmOperator *op)
tf->uv[3][0]= tf->uv[2][0];
tf->uv[3][1]= tf->uv[2][1];
-
+
tf->uv[2][0]= u1;
tf->uv[2][1]= v1;
}
@@ -6604,40 +7138,33 @@ static int mesh_mirror_uvs(bContext *C, wmOperator *op)
change = 1;
}
}
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- if(!change)
- return OPERATOR_CANCELLED;
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
+
+ if (change) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Mirror UV face");
+ }
}
-static int mesh_rotate_colors(bContext *C, wmOperator *op)
+void mesh_rotate_colors(void)
{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
+ EditMesh *em = G.editMesh;
EditFace *efa;
- short change = 0;
+ short change = 0, ccw;
MCol tmpcol, *mcol;
- int dir= RNA_enum_get(op->ptr, "direction");
-
- if (!EM_vertColorCheck(em)) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers.");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
+ if (!EM_vertColorCheck()) {
+ error("mesh has no color layers");
+ return;
}
-
+
+ ccw = (G.qual == LR_SHIFTKEY);
+
for(efa=em->faces.first; efa; efa=efa->next) {
if (efa->f & SELECT) {
mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
tmpcol= mcol[0];
-
- if (dir == DIRECTION_CCW) {
+
+ if (ccw) {
if(efa->v4) {
mcol[0]= mcol[3];
mcol[3]= mcol[2];
@@ -6649,7 +7176,7 @@ static int mesh_rotate_colors(bContext *C, wmOperator *op)
} else {
mcol[0]= mcol[1];
mcol[1]= mcol[2];
-
+
if(efa->v4) {
mcol[2]= mcol[3];
mcol[3]= tmpcol;
@@ -6660,43 +7187,35 @@ static int mesh_rotate_colors(bContext *C, wmOperator *op)
change = 1;
}
}
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- if(!change)
- return OPERATOR_CANCELLED;
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
+
+ if (change) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Rotate Color face");
+ }
}
-
-static int mesh_mirror_colors(bContext *C, wmOperator *op)
+void mesh_mirror_colors(void)
{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
+ EditMesh *em = G.editMesh;
EditFace *efa;
- short change = 0;
+ short change = 0, altaxis;
MCol tmpcol, *mcol;
- int axis= RNA_enum_get(op->ptr, "axis");
-
- if (!EM_vertColorCheck(em)) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
+ if (!EM_vertColorCheck()) {
+ error("mesh has no color layers");
+ return;
}
-
+
+ altaxis = (G.qual == LR_SHIFTKEY);
+
for(efa=em->faces.first; efa; efa=efa->next) {
if (efa->f & SELECT) {
mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
- if (axis == AXIS_Y) {
+ if (altaxis) {
tmpcol= mcol[1];
mcol[1]= mcol[2];
mcol[2]= tmpcol;
-
+
if(efa->v4) {
tmpcol= mcol[0];
mcol[0]= mcol[3];
@@ -6706,7 +7225,7 @@ static int mesh_mirror_colors(bContext *C, wmOperator *op)
tmpcol= mcol[0];
mcol[0]= mcol[1];
mcol[1]= tmpcol;
-
+
if(efa->v4) {
tmpcol= mcol[2];
mcol[2]= mcol[3];
@@ -6716,863 +7235,10 @@ static int mesh_mirror_colors(bContext *C, wmOperator *op)
change = 1;
}
}
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- if(!change)
- return OPERATOR_CANCELLED;
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_uvs_rotate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Rotate UVs";
- ot->description= "Rotate selected UVs";
- ot->idname= "MESH_OT_uvs_rotate";
-
- /* api callbacks */
- ot->exec= mesh_rotate_uvs;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate UVs around.");
-}
-
-void MESH_OT_uvs_mirror(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Mirror UVs";
- ot->description= "Mirror selected UVs";
- ot->idname= "MESH_OT_uvs_mirror";
-
- /* api callbacks */
- ot->exec= mesh_mirror_uvs;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_enum(ot->srna, "axis", axis_items_xy, DIRECTION_CW, "Axis", "Axis to mirror UVs around.");
-}
-
-void MESH_OT_colors_rotate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Rotate Colors";
- ot->description= "Rotate UV/image color layer";
- ot->idname= "MESH_OT_colors_rotate";
-
- /* api callbacks */
- ot->exec= mesh_rotate_colors;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around.");
-}
-
-void MESH_OT_colors_mirror(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Mirror Colors";
- ot->description= "Mirror UV/image color layer";
- ot->idname= "MESH_OT_colors_mirror";
-
- /* api callbacks */
- ot->exec= mesh_mirror_colors;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_enum(ot->srna, "axis", axis_items_xy, DIRECTION_CW, "Axis", "Axis to mirror colors around.");
-}
-
-/********************** Subdivide Operator *************************/
-
-static int subdivide_exec(bContext *C, wmOperator *op)
-{
- ToolSettings *ts= CTX_data_tool_settings(C);
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
- int cuts= RNA_int_get(op->ptr,"number_cuts");
- float smooth= 0.292f*RNA_float_get(op->ptr, "smoothness");
- float fractal= RNA_float_get(op->ptr, "fractal")/100;
- int corner_cut_pattern= RNA_enum_get(op->ptr,"corner_cut_pattern");
- int flag= 0;
-
- if(smooth != 0.0f)
- flag |= B_SMOOTH;
- if(fractal != 0.0f)
- flag |= B_FRACTAL;
-
- esubdivideflag(obedit, em, 1, smooth, fractal, ts->editbutflag|flag, cuts, corner_cut_pattern, 0);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_subdivide(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Subdivide";
- ot->description= "Subdivide selected edges";
- ot->idname= "MESH_OT_subdivide";
-
- /* api callbacks */
- ot->exec= subdivide_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
- RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor.", 0.0f, 1.0f);
- RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f);
- RNA_def_enum(ot->srna, "corner_cut_pattern", corner_type_items, SUBDIV_CORNER_INNERVERT, "Corner Cut Pattern", "Topology pattern to use to fill a face after cutting across its corner");
-}
-
-/********************** Fill Operators *************************/
-
-/* note; the EM_selectmode_set() calls here illustrate how badly constructed it all is... from before the
-edge/face flags, with very mixed results.... */
-static void beautify_fill(EditMesh *em)
-{
- EditVert *v1, *v2, *v3, *v4;
- EditEdge *eed, *nexted;
- EditEdge dia1, dia2;
- EditFace *efa, *w;
- // void **efaar, **efaa;
- EVPTuple *efaar;
- EVPtr *efaa;
- float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2;
- int totedge, ok, notbeauty=8, onedone, vindex[4];
-
- /* - all selected edges with two faces
- * - find the faces: store them in edges (using datablock)
- * - per edge: - test convex
- * - test edge: flip?
- * - if true: remedge, addedge, all edges at the edge get new face pointers
- */
-
- EM_selectmode_set(em); // makes sure in selectmode 'face' the edges of selected faces are selected too
-
- totedge = count_selected_edges(em->edges.first);
- if(totedge==0) return;
-
- /* temp block with face pointers */
- efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "beautyfill");
-
- while (notbeauty) {
- notbeauty--;
-
- ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
-
- /* there we go */
- onedone= 0;
-
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
-
- /* f2 is set in collect_quadedges() */
- if(eed->f2==2 && eed->h==0) {
-
- efaa = (EVPtr *) eed->tmp.p;
-
- /* none of the faces should be treated before, nor be part of fgon */
- ok= 1;
- efa= efaa[0];
- if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
- if(efa->fgonf) ok= 0;
- efa= efaa[1];
- if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
- if(efa->fgonf) ok= 0;
-
- if(ok) {
- /* test convex */
- givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
- if(v1 && v2 && v3 && v4) {
- if( convex(v1->co, v2->co, v3->co, v4->co) ) {
-
- /* test edges */
- if( (v1) > (v3) ) {
- dia1.v1= v3;
- dia1.v2= v1;
- }
- else {
- dia1.v1= v1;
- dia1.v2= v3;
- }
-
- if( (v2) > (v4) ) {
- dia2.v1= v4;
- dia2.v2= v2;
- }
- else {
- dia2.v1= v2;
- dia2.v2= v4;
- }
-
- /* testing rule:
- * the area divided by the total edge lengths
- */
-
- len1= len_v3v3(v1->co, v2->co);
- len2= len_v3v3(v2->co, v3->co);
- len3= len_v3v3(v3->co, v4->co);
- len4= len_v3v3(v4->co, v1->co);
- len5= len_v3v3(v1->co, v3->co);
- len6= len_v3v3(v2->co, v4->co);
-
- opp1= area_tri_v3(v1->co, v2->co, v3->co);
- opp2= area_tri_v3(v1->co, v3->co, v4->co);
-
- fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5);
-
- opp1= area_tri_v3(v2->co, v3->co, v4->co);
- opp2= area_tri_v3(v2->co, v4->co, v1->co);
-
- fac2= opp1/(len2+len3+len6) + opp2/(len4+len1+len6);
-
- ok= 0;
- if(fac1 > fac2) {
- if(dia2.v1==eed->v1 && dia2.v2==eed->v2) {
- eed->f1= 1;
- efa= efaa[0];
- efa->f1= 1;
- efa= efaa[1];
- efa->f1= 1;
-
- w= EM_face_from_faces(em, efaa[0], efaa[1],
- vindex[0], vindex[1], 4+vindex[2], -1);
- w->f |= SELECT;
-
-
- w= EM_face_from_faces(em, efaa[0], efaa[1],
- vindex[0], 4+vindex[2], 4+vindex[3], -1);
- w->f |= SELECT;
-
- onedone= 1;
- }
- }
- else if(fac1 < fac2) {
- if(dia1.v1==eed->v1 && dia1.v2==eed->v2) {
- eed->f1= 1;
- efa= efaa[0];
- efa->f1= 1;
- efa= efaa[1];
- efa->f1= 1;
-
-
- w= EM_face_from_faces(em, efaa[0], efaa[1],
- vindex[1], 4+vindex[2], 4+vindex[3], -1);
- w->f |= SELECT;
-
-
- w= EM_face_from_faces(em, efaa[0], efaa[1],
- vindex[0], 4+vindex[1], 4+vindex[3], -1);
- w->f |= SELECT;
-
- onedone= 1;
- }
- }
- }
- }
- }
-
- }
- eed= nexted;
- }
-
- free_tagged_edges_faces(em, em->edges.first, em->faces.first);
-
- if(onedone==0) break;
-
- EM_selectmode_set(em); // new edges/faces were added
- }
-
- MEM_freeN(efaar);
-
- EM_select_flush(em);
-
-}
-
-/* Got this from scanfill.c. You will need to juggle around the
-* callbacks for the scanfill.c code a bit for this to work. */
-static void fill_mesh(EditMesh *em)
-{
- EditVert *eve,*v1;
- EditEdge *eed,*e1,*nexted;
- EditFace *efa,*nextvl, *efan;
- short ok;
-
- if(em==NULL) return;
- waitcursor(1);
-
- /* copy all selected vertices */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & SELECT) {
- v1= BLI_addfillvert(eve->co);
- eve->tmp.v= v1;
- v1->tmp.v= eve;
- v1->xs= 0; // used for counting edges
- }
- eve= eve->next;
- }
- /* copy all selected edges */
- eed= em->edges.first;
- while(eed) {
- if( (eed->v1->f & SELECT) && (eed->v2->f & SELECT) ) {
- e1= BLI_addfilledge(eed->v1->tmp.v, eed->v2->tmp.v);
- e1->v1->xs++;
- e1->v2->xs++;
- }
- eed= eed->next;
- }
- /* from all selected faces: remove vertices and edges to prevent doubles */
- /* all edges add values, faces subtract,
- then remove edges with vertices ->xs<2 */
- efa= em->faces.first;
- ok= 0;
- while(efa) {
- nextvl= efa->next;
- if( faceselectedAND(efa, 1) ) {
- efa->v1->tmp.v->xs--;
- efa->v2->tmp.v->xs--;
- efa->v3->tmp.v->xs--;
- if(efa->v4) efa->v4->tmp.v->xs--;
- ok= 1;
-
- }
- efa= nextvl;
- }
- if(ok) { /* there are faces selected */
- eed= filledgebase.first;
- while(eed) {
- nexted= eed->next;
- if(eed->v1->xs<2 || eed->v2->xs<2) {
- BLI_remlink(&filledgebase,eed);
- }
- eed= nexted;
- }
- }
-
- if(BLI_edgefill(em->mat_nr)) {
- efa= fillfacebase.first;
- while(efa) {
- /* normals default pointing up */
- efan= addfacelist(em, efa->v3->tmp.v, efa->v2->tmp.v,
- efa->v1->tmp.v, 0, NULL, NULL);
- if(efan) EM_select_face(efan, 1);
- efa= efa->next;
- }
- }
-
- BLI_end_edgefill();
- beautify_fill(em);
-
- WM_cursor_wait(0);
- EM_select_flush(em);
-
-}
-
-static int fill_mesh_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- fill_mesh(em);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-
-}
-
-void MESH_OT_fill(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Fill";
- ot->description= "Create a segment, edge or face";
- ot->idname= "MESH_OT_fill";
-
- /* api callbacks */
- ot->exec= fill_mesh_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static int beautify_fill_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- beautify_fill(em);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_beautify_fill(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Beautify Fill";
- ot->description= "Rearrange geometry on a selected surface to avoid skinny faces";
- ot->idname= "MESH_OT_beautify_fill";
-
- /* api callbacks */
- ot->exec= beautify_fill_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-/* ********************** SORT FACES ******************* */
-
-static void permutate(void *list, int num, int size, int *index)
-{
- void *buf;
- int len;
- int i;
-
- len = num * size;
-
- buf = MEM_mallocN(len, "permutate");
- memcpy(buf, list, len);
-
- for (i = 0; i < num; i++) {
- memcpy((char *)list + (i * size), (char *)buf + (index[i] * size), size);
- }
- MEM_freeN(buf);
-}
-
-/* sort faces on view axis */
-static float *face_sort_floats;
-static int float_sort(const void *v1, const void *v2)
-{
- float x1, x2;
-
- x1 = face_sort_floats[((int *) v1)[0]];
- x2 = face_sort_floats[((int *) v2)[0]];
-
- if( x1 > x2 ) return 1;
- else if( x1 < x2 ) return -1;
- return 0;
-}
-
-
-static int sort_faces_exec(bContext *C, wmOperator *op)
-{
- RegionView3D *rv3d= ED_view3d_context_rv3d(C);
- View3D *v3d= CTX_wm_view3d(C);
- Object *ob= CTX_data_edit_object(C);
- Scene *scene= CTX_data_scene(C);
- Mesh *me;
- CustomDataLayer *layer;
- int i, *index;
- int event;
- float reverse = 1;
- // XXX int ctrl= 0;
-
- if (!v3d) return OPERATOR_CANCELLED;
-
- /* This operator work in Object Mode, not in edit mode.
- * After talk with Campbell we agree that there is no point to port this to EditMesh right now.
- * so for now, we just exit_editmode and enter_editmode at the end of this function.
- */
- ED_object_exit_editmode(C, EM_FREEDATA);
-
- me= ob->data;
- if(me->totface==0) {
- ED_object_enter_editmode(C, 0);
- return OPERATOR_FINISHED;
- }
-
- event= RNA_enum_get(op->ptr, "type");
-
- // XXX
- //if(ctrl)
- // reverse = -1;
-
- /* create index list */
- index= (int *)MEM_mallocN(sizeof(int) * me->totface, "sort faces");
- for (i = 0; i < me->totface; i++) {
- index[i] = i;
- }
-
- face_sort_floats = (float *) MEM_mallocN(sizeof(float) * me->totface, "sort faces float");
-
- /* sort index list instead of faces itself
- * and apply this permutation to all face layers
- */
- if (event == 5) {
- /* Random */
- for(i=0; i<me->totface; i++) {
- face_sort_floats[i] = BLI_frand();
- }
- qsort(index, me->totface, sizeof(int), float_sort);
- } else {
- MFace *mf;
- float vec[3];
- float mat[4][4];
- float cur[3];
-
- if (event == 1)
- mul_m4_m4m4(mat, OBACT->obmat, rv3d->viewmat); /* apply the view matrix to the object matrix */
- else if (event == 2) { /* sort from cursor */
- if( v3d && v3d->localvd ) {
- VECCOPY(cur, v3d->cursor);
- } else {
- VECCOPY(cur, scene->cursor);
- }
- invert_m4_m4(mat, OBACT->obmat);
- mul_m4_v3(mat, cur);
- }
-
- mf= me->mface;
-
- for(i=0; i<me->totface; i++, mf++) {
- if (event==3) {
- face_sort_floats[i] = ((float)mf->mat_nr)*reverse;
- } else if (event==4) {
- /*selected first*/
- if (mf->flag & ME_FACE_SEL)
- face_sort_floats[i] = 0.0;
- else
- face_sort_floats[i] = reverse;
- } else {
- /* find the faces center */
- add_v3_v3v3(vec, (me->mvert+mf->v1)->co, (me->mvert+mf->v2)->co);
- if (mf->v4) {
- add_v3_v3(vec, (me->mvert+mf->v3)->co);
- add_v3_v3(vec, (me->mvert+mf->v4)->co);
- mul_v3_fl(vec, 0.25f);
- } else {
- add_v3_v3(vec, (me->mvert+mf->v3)->co);
- mul_v3_fl(vec, 1.0f/3.0f);
- } /* done */
-
- if (event == 1) { /* sort on view axis */
- mul_m4_v3(mat, vec);
- face_sort_floats[i] = vec[2] * reverse;
- } else if(event == 2) { /* distance from cursor*/
- face_sort_floats[i] = len_v3v3(cur, vec) * reverse; /* back to front */
- }
- }
- }
- qsort(index, me->totface, sizeof(int), float_sort);
- }
- MEM_freeN(face_sort_floats);
- for(i = 0; i < me->fdata.totlayer; i++) {
- layer = &me->fdata.layers[i];
- permutate(layer->data, me->totface, CustomData_sizeof(layer->type), index);
- }
-
- MEM_freeN(index);
- DAG_id_tag_update(ob->data, 0);
-
- /* Return to editmode. */
- ED_object_enter_editmode(C, 0);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_sort_faces(wmOperatorType *ot)
-{
- static EnumPropertyItem type_items[]= {
- { 1, "VIEW_AXIS", 0, "View Axis", "" },
- { 2, "CURSOR_DISTANCE", 0, "Cursor Distance", "" },
- { 3, "MATERIAL", 0, "Material", "" },
- { 4, "SELECTION", 0, "Selection", "" },
- { 5, "RANDOMIZE", 0, "Randomize", "" },
- { 0, NULL, 0, NULL, NULL }};
-
- /* identifiers */
- ot->name= "Sort Faces"; // XXX (Ctrl to reverse)%t|
- ot->description= "The faces of the active Mesh Object are sorted, based on the current view.";
- ot->idname= "MESH_OT_sort_faces";
-
- /* api callbacks */
- ot->invoke= WM_menu_invoke;
- ot->exec= sort_faces_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
-}
-
-/********************** Quad/Tri Operators *************************/
-
-static int quads_convert_to_tris_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- convert_to_triface(em,0);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_quads_convert_to_tris(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Quads to Tris";
- ot->description= "Convert selected quads to triangles";
- ot->idname= "MESH_OT_quads_convert_to_tris";
-
- /* api callbacks */
- ot->exec= quads_convert_to_tris_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static int tris_convert_to_quads_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- join_triangles(em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Tris to Quads";
- ot->description= "Convert selected triangles to quads";
- ot->idname= "MESH_OT_tris_convert_to_quads";
-
- /* api callbacks */
- ot->exec= tris_convert_to_quads_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static int edge_flip_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- edge_flip(em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_edge_flip(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Edge Flip";
- ot->description= "Flip selected edge or adjoining faces";
- ot->idname= "MESH_OT_edge_flip";
-
- /* api callbacks */
- ot->exec= edge_flip_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-/********************** Smooth/Solid Operators *************************/
-
-static void mesh_set_smooth_faces(EditMesh *em, short smooth)
-{
- EditFace *efa;
-
- if(em==NULL) return;
-
- for(efa= em->faces.first; efa; efa=efa->next) {
- if(efa->f & SELECT) {
- if(smooth) efa->flag |= ME_SMOOTH;
- else efa->flag &= ~ME_SMOOTH;
- }
+ if (change) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Mirror Color face");
}
}
-
-static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- mesh_set_smooth_faces(em, 1);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Shade Smooth";
- ot->description= "Display faces 'smooth' (using vertex normals)";
- ot->idname= "MESH_OT_faces_shade_smooth";
-
- /* api callbacks */
- ot->exec= mesh_faces_shade_smooth_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static int mesh_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- mesh_set_smooth_faces(em, 0);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_faces_shade_flat(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Shade Flat";
- ot->description= "Display faces 'flat'";
- ot->idname= "MESH_OT_faces_shade_flat";
-
- /* api callbacks */
- ot->exec= mesh_faces_shade_flat_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-/* TODO - some way to select on an arbitrary axis */
-static int select_axis_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- int axis= RNA_enum_get(op->ptr, "axis");
- int mode= RNA_enum_get(op->ptr, "mode"); /* -1==aligned, 0==neg, 1==pos*/
-
- EditSelection *ese = em->selected.last;
-
-
- if(ese==NULL)
- return OPERATOR_CANCELLED;
-
- if(ese->type==EDITVERT) {
- EditVert *ev;
- EditVert *act_vert= (EditVert*)ese->data;
- float value= act_vert->co[axis];
- float limit= CTX_data_tool_settings(C)->doublimit; // XXX
-
- if(mode==0) value -= limit;
- else if (mode==1) value += limit;
-
- for(ev=em->verts.first;ev;ev=ev->next) {
- if(!ev->h) {
- switch(mode) {
- case -1: /* aligned */
- if(fabs(ev->co[axis] - value) < limit)
- ev->f |= SELECT;
- break;
- case 0: /* neg */
- if(ev->co[axis] > value)
- ev->f |= SELECT;
- break;
- case 1: /* pos */
- if(ev->co[axis] < value)
- ev->f |= SELECT;
- break;
- }
- }
- }
- }
-
- EM_select_flush(em);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_axis(wmOperatorType *ot)
-{
- static EnumPropertyItem axis_mode_items[] = {
- {0, "POSITIVE", 0, "Positive Axis", ""},
- {1, "NEGATIVE", 0, "Negative Axis", ""},
- {-1, "ALIGNED", 0, "Aligned Axis", ""},
- {0, NULL, 0, NULL, NULL}};
-
- static EnumPropertyItem axis_items_xyz[] = {
- {0, "X_AXIS", 0, "X Axis", ""},
- {1, "Y_AXIS", 0, "Y Axis", ""},
- {2, "Z_AXIS", 0, "Z Axis", ""},
- {0, NULL, 0, NULL, NULL}};
-
- /* identifiers */
- ot->name= "Select Axis";
- ot->description= "Select all data in the mesh on a single axis";
- ot->idname= "MESH_OT_select_axis";
-
- /* api callbacks */
- ot->exec= select_axis_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting");
- RNA_def_enum(ot->srna, "axis", axis_items_xyz, 0, "Axis", "Select the axis to compare each vertex on");
-}
-
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
new file mode 100644
index 00000000000..6b4420d5eeb
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -0,0 +1,644 @@
+/**
+ * bmesh_construct.c August 2008
+ *
+ * BM construction functions.
+ *
+ * ***** 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.
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_customdata.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_array.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#define SELECT 1
+ #define BM_EDGEVERT (1<<14)
+
+/*prototypes*/
+static void bm_copy_loop_attributes(BMesh *source_mesh, BMesh *target_mesh,
+ BMLoop *source_loop, BMLoop *target_loop);
+#if 0
+
+/*
+ * BM_CONSTRUCT.C
+ *
+ * This file contains functions for making and destroying
+ * individual elements like verts, edges and faces.
+ *
+*/
+
+/*
+ * BMESH MAKE VERT
+ *
+ * Creates a new vertex and returns a pointer
+ * to it. If a pointer to an example vertex is
+ * passed in, it's custom data and properties
+ * will be copied to the new vertex.
+ *
+*/
+
+BMVert *BM_Make_Vert(BMesh *bm, float co[3], BMVert *example)
+{
+ BMVert *v = NULL;
+ v = bmesh_mv(bm, co);
+ if(example)
+ CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, example->head.data, &v->head.data);
+ return v;
+}
+
+/*
+ * BMESH MAKE EDGE
+ *
+ * Creates a new edge betweeen two vertices and returns a
+ * pointer to it. If 'nodouble' equals 1, then a check is
+ * is done to make sure that an edge between those two vertices
+ * does not already exist. If it does, that edge is returned instead
+ * of creating a new one.
+ *
+ * If a new edge is created, and a pointer to an example edge is
+ * provided, it's custom data and properties will be copied to the
+ * new edge.
+ *
+*/
+
+BMEdge *BM_Make_Edge(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge *example, int nodouble)
+{
+ BMEdge *e = NULL;
+
+ if(nodouble) /*test if edge already exists.*/
+ e = BM_Edge_Exist(v1, v2);
+
+ if(!e){
+ e = bmesh_me(bm, v1, v2);
+
+ if(example)
+ CustomData_bmesh_copy_data(&bm->edata, &bm->edata, example->head.data, &e->head.data);
+ }
+
+ return e;
+
+}
+#endif
+
+/*
+ * BMESH MAKE QUADTRIANGLE
+ *
+ * Creates a new quad or triangle from
+ * a list of 3 or 4 vertices. If nodouble
+ * equals 1, then a check is done to see
+ * if a face with these vertices already
+ * exists and returns it instead. If a pointer
+ * to an example face is provided, it's custom
+ * data and properties will be copied to the new
+ * face.
+ *
+ * Note that the winding of the face is determined
+ * by the order of the vertices in the vertex array
+ *
+*/
+
+BMFace *BM_Make_QuadTri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3,
+ BMVert *v4, BMFace *example, int nodouble)
+{
+ BMEdge *edar[4];
+ BMVert *vtar[4];
+
+ edar[0] = BM_Edge_Exist(v1, v2);
+ edar[1] = BM_Edge_Exist(v2, v3);
+ edar[2] = BM_Edge_Exist(v3, v4? v4 : v1);
+ if (v4) edar[3] = BM_Edge_Exist(v4, v1);
+ else edar[3] = NULL;
+
+ if (!edar[0]) edar[0] = BM_Make_Edge(bm, v1, v2, NULL, 0);
+ if (!edar[1]) edar[1] = BM_Make_Edge(bm, v2, v3, NULL, 0);
+ if (!edar[2]) edar[2] = BM_Make_Edge(bm, v3, v4?v4:v1, NULL, 0);
+ if (!edar[0] && v4) edar[0] = BM_Make_Edge(bm, v4, v1, NULL, 0);
+
+ vtar[0] = v1;
+ vtar[1] = v2;
+ vtar[2] = v3;
+ vtar[3] = v4;
+
+ return BM_Make_Quadtriangle(bm, vtar, edar, v4?4:3, example, nodouble);
+}
+
+/*remove the edge array bits from this. Its not really needed?*/
+BMFace *BM_Make_Quadtriangle(BMesh *bm, BMVert **verts, BMEdge **edges, int len, BMFace *example, int nodouble)
+{
+ BMEdge *edar[4];
+ BMFace *f = NULL;
+ int overlap = 0;
+
+ edar[0] = edar[1] = edar[2] = edar[3] = NULL;
+
+ if(edges){
+ edar[0] = edges[0];
+ edar[1] = edges[1];
+ edar[2] = edges[2];
+ if(len == 4) edar[3] = edges[3];
+ }else{
+ edar[0] = BM_Edge_Exist(verts[0],verts[1]);
+ edar[1] = BM_Edge_Exist(verts[1],verts[2]);
+ if(len == 4){
+ edar[2] = BM_Edge_Exist(verts[2],verts[3]);
+ edar[3] = BM_Edge_Exist(verts[3],verts[0]);
+
+ }else{
+ edar[2] = BM_Edge_Exist(verts[2],verts[0]);
+ }
+ }
+
+ if(nodouble){
+ /*check if face exists or overlaps*/
+ if(len == 4){
+ overlap = BM_Exist_Face_Overlaps(bm, verts, len, &f);
+ }else{
+ overlap = BM_Exist_Face_Overlaps(bm, verts, len, &f);
+ }
+ }
+
+ /*make new face*/
+ if((!f) && (!overlap)){
+ if(!edar[0]) edar[0] = BM_Make_Edge(bm, verts[0], verts[1], NULL, 0);
+ if(!edar[1]) edar[1] = BM_Make_Edge(bm, verts[1], verts[2], NULL, 0);
+ if(len == 4){
+ if(!edar[2]) edar[2] = BM_Make_Edge(bm, verts[2], verts[3], NULL, 0);
+ if(!edar[3]) edar[3] = BM_Make_Edge(bm, verts[3], verts[0], NULL, 0);
+ } else {
+ if(!edar[2]) edar[2] = BM_Make_Edge(bm, verts[2], verts[0], NULL, 0);
+ }
+
+ f = BM_Make_Face(bm, verts, edar, len);
+
+ if(example)
+ CustomData_bmesh_copy_data(&bm->pdata, &bm->pdata, example->head.data, &f->head.data);
+
+ }
+
+ return f;
+}
+
+
+/*copies face data from shared adjacent faces*/
+void BM_Face_CopyShared(BMesh *bm, BMFace *f) {
+ BMIter iter;
+ BMLoop *l, *l2;
+
+ if (!f) return;
+
+ l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f);
+ for (; l; l=BMIter_Step(&iter)) {
+ l2 = l->radial_next;
+
+ if (l2 && l2 != l) {
+ if (l2->v == l->v) {
+ bm_copy_loop_attributes(bm, bm, l2, l);
+ } else {
+ l2 = (BMLoop*) l2->next;
+ bm_copy_loop_attributes(bm, bm, l2, l);
+ }
+ }
+ }
+}
+
+/*
+ * BMESH MAKE NGON
+ *
+ * Attempts to make a new Ngon from a list of edges.
+ * If nodouble equals one, a check for overlaps or existing
+ *
+ * The edges are not required to be ordered, simply to to form
+ * a single closed loop as a whole
+*/
+#define VERT_BUF_SIZE 100
+BMFace *BM_Make_Ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, int nodouble)
+{
+ BMEdge **edges2 = NULL;
+ BLI_array_staticdeclare(edges2, VERT_BUF_SIZE);
+ BMVert **verts = NULL, *v;
+ BLI_array_staticdeclare(verts, VERT_BUF_SIZE);
+ BMFace *f = NULL;
+ BMEdge *e;
+ int overlap = 0, i, j, v1found, reverse;
+
+ /*this code is hideous, yeek. I'll have to think about ways of
+ cleaning it up. basically, it now combines the old BM_Make_Ngon
+ *and* the old bmesh_mf functions, so its kindof smashed together
+ - joeedh*/
+
+ if (!len || !v1 || !v2 || !edges || !bm)
+ return NULL;
+
+ /*put edges in correct order*/
+ for (i=0; i<len; i++) {
+ bmesh_api_setflag(edges[i], _FLAG_MF);
+ }
+
+ BLI_array_append(verts, edges[0]->v1);
+
+ v = edges[0]->v2;
+ e = edges[0];
+ do {
+ BMEdge *e2 = e;
+
+ BLI_array_append(verts, v);
+ BLI_array_append(edges2, e);
+
+ do {
+ e2 = bmesh_disk_nextedge(e2, v);
+ if (e2 != e && bmesh_api_getflag(e2, _FLAG_MF)) {
+ v = BM_OtherEdgeVert(e2, v);
+ break;
+ }
+ } while (e2 != e);
+
+ if (e2 == e)
+ goto err; /*the edges do not form a closed loop*/
+
+ e = e2;
+ } while (e != edges[0]);
+
+ if (BLI_array_count(edges2) != len)
+ goto err; /*we didn't use all edges in forming the boundary loop*/
+
+ /*ok, edges are in correct order, now ensure they are going
+ in the correct direction*/
+ v1found = reverse = 0;
+ for (i=0; i<len; i++) {
+ if (BM_Vert_In_Edge(edges2[i], v1)) {
+ /*see if v1 and v2 are in the same edge*/
+ if (BM_Vert_In_Edge(edges2[i], v2)) {
+ /*if v1 is shared by the *next* edge, then the winding
+ is incorrect*/
+ if (BM_Vert_In_Edge(edges2[(i+1)%len], v1)) {
+ reverse = 1;
+ break;
+ }
+ }
+
+ v1found = 1;
+ }
+
+ if (!v1found && BM_Vert_In_Edge(edges2[i], v2)) {
+ reverse = 1;
+ break;
+ }
+ }
+
+ if (reverse) {
+ for (i=0; i<len/2; i++) {
+ v = verts[i];
+ verts[i] = verts[len-i-1];
+ verts[len-i-1] = v;
+ }
+ }
+
+ for (i=0; i<len; i++) {
+ edges2[i] = BM_Edge_Exist(verts[i], verts[(i+1)%len]);
+ if (!edges2[i])
+ return NULL;
+ }
+
+ /*check if face already exists*/
+ if(nodouble)
+ overlap = BM_Face_Exists(bm, verts, len, &f);
+
+ /*create the face, if necassary*/
+ if (!f && !overlap)
+ f = BM_Make_Face(bm, verts, edges2, len);
+ else if (!overlap)
+ f = NULL;
+
+ /*clean up flags*/
+ for (i=0; i<len; i++) {
+ bmesh_api_clearflag(edges2[i], _FLAG_MF);
+ }
+
+ BLI_array_free(verts);
+ BLI_array_free(edges2);
+
+ return f;
+
+err:
+ for (i=0; i<len; i++) {
+ bmesh_api_clearflag(edges[i], _FLAG_MF);
+ }
+
+ BLI_array_free(verts);
+ BLI_array_free(edges2);
+
+ return NULL;
+}
+
+
+/*bmesh_make_face_from_face(BMesh *bm, BMFace *source, BMFace *target) */
+
+
+/*
+ * REMOVE TAGGED XXX
+ *
+ * Called by operators to remove elements that they have marked for
+ * removal.
+ *
+*/
+
+void BM_remove_tagged_faces(BMesh *bm, int flag)
+{
+ BMFace *f;
+ BMIter iter;
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if(BMO_TestFlag(bm, f, flag)) BM_Kill_Face(bm, f);
+ }
+}
+
+void BM_remove_tagged_edges(BMesh *bm, int flag)
+{
+ BMEdge *e;
+ BMIter iter;
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if(BMO_TestFlag(bm, e, flag)) BM_Kill_Edge(bm, e);
+ }
+}
+
+void BM_remove_tagged_verts(BMesh *bm, int flag)
+{
+ BMVert *v;
+ BMIter iter;
+
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(BMO_TestFlag(bm, v, flag)) BM_Kill_Vert(bm, v);
+ }
+}
+
+static void bm_copy_vert_attributes(BMesh *source_mesh, BMesh *target_mesh, BMVert *source_vertex, BMVert *target_vertex)
+{
+ CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata, source_vertex->head.data, &target_vertex->head.data);
+}
+
+static void bm_copy_edge_attributes(BMesh *source_mesh, BMesh *target_mesh, BMEdge *source_edge, BMEdge *target_edge)
+{
+ CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata, source_edge->head.data, &target_edge->head.data);
+}
+
+static void bm_copy_loop_attributes(BMesh *source_mesh, BMesh *target_mesh, BMLoop *source_loop, BMLoop *target_loop)
+{
+ CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata, source_loop->head.data, &target_loop->head.data);
+}
+
+static void bm_copy_face_attributes(BMesh *source_mesh, BMesh *target_mesh, BMFace *source_face, BMFace *target_face)
+{
+ CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata, source_face->head.data, &target_face->head.data);
+ target_face->mat_nr = source_face->mat_nr;
+}
+
+/*Todo: Special handling for hide flags?*/
+
+void BM_Copy_Attributes(BMesh *source_mesh, BMesh *target_mesh, void *source, void *target)
+{
+ BMHeader *sheader = source, *theader = target;
+
+ if(sheader->type != theader->type)
+ return;
+
+ /*First we copy select*/
+ if(BM_Selected(source_mesh, source)) BM_Select(target_mesh, target, 1);
+
+ /*Now we copy flags*/
+ theader->flag = sheader->flag;
+
+ /*Copy specific attributes*/
+ if(theader->type == BM_VERT)
+ bm_copy_vert_attributes(source_mesh, target_mesh, (BMVert*)source, (BMVert*)target);
+ else if(theader->type == BM_EDGE)
+ bm_copy_edge_attributes(source_mesh, target_mesh, (BMEdge*)source, (BMEdge*)target);
+ else if(theader->type == BM_LOOP)
+ bm_copy_loop_attributes(source_mesh, target_mesh, (BMLoop*)source, (BMLoop*)target);
+ else if(theader->type == BM_FACE)
+ bm_copy_face_attributes(source_mesh, target_mesh, (BMFace*)source, (BMFace*)target);
+}
+
+BMesh *BM_Copy_Mesh(BMesh *bmold)
+{
+ BMesh *bm;
+ BMVert *v, *v2, **vtable = NULL;
+ BLI_array_declare(vtable);
+ BMEdge *e, *e2, **edges = NULL, **etable = NULL;
+ BLI_array_declare(edges);
+ BLI_array_declare(etable);
+ BMLoop *l, *l2, **loops = NULL;
+ BLI_array_declare(loops);
+ BMFace *f, *f2, **ftable = NULL;
+ BLI_array_declare(ftable);
+ BMEditSelection *ese;
+ BMIter iter, liter;
+ int allocsize[4] = {512,512,2048,512}, numTex, numCol;
+ int i, j;
+
+ /*allocate a bmesh*/
+ bm = BM_Make_Mesh(allocsize);
+
+ CustomData_copy(&bmold->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bmold->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bmold->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bmold->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+ CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
+
+ /*needed later*/
+ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
+
+ v = BMIter_New(&iter, bmold, BM_VERTS_OF_MESH, NULL);
+ for (i=0; v; v=BMIter_Step(&iter), i++) {
+ v2 = BM_Make_Vert(bm, v->co, NULL);
+ BM_Copy_Attributes(bmold, bm, v, v2);
+ BLI_array_growone(vtable);
+ copy_v3_v3(v2->no, v->no);
+
+ vtable[BLI_array_count(vtable)-1] = v2;
+
+ BMINDEX_SET(v, i);
+ BMINDEX_SET(v2, i);
+ }
+
+ e = BMIter_New(&iter, bmold, BM_EDGES_OF_MESH, NULL);
+ for (i=0; e; e=BMIter_Step(&iter), i++) {
+ e2 = BM_Make_Edge(bm, vtable[BMINDEX_GET(e->v1)],
+ vtable[BMINDEX_GET(e->v2)], e, 0);
+
+ BM_Copy_Attributes(bmold, bm, e, e2);
+ BLI_array_growone(etable);
+ etable[BLI_array_count(etable)-1] = e2;
+
+ BMINDEX_SET(e, i);
+ BMINDEX_SET(e2, i);
+ }
+
+ f = BMIter_New(&iter, bmold, BM_FACES_OF_MESH, NULL);
+ for (i=0; f; f=BMIter_Step(&iter), i++) {
+ BLI_array_empty(loops);
+ BLI_array_empty(edges);
+ l = BMIter_New(&liter, bmold, BM_LOOPS_OF_FACE, f);
+ for (j=0; j<f->len; j++, l = BMIter_Step(&liter)) {
+ BLI_array_growone(loops);
+ BLI_array_growone(edges);
+ loops[j] = l;
+ edges[j] = etable[BMINDEX_GET(l->e)];
+ }
+
+ v = vtable[BMINDEX_GET(loops[0]->v)];
+ v2 = vtable[BMINDEX_GET(loops[1]->v)];
+
+ if (!bmesh_verts_in_edge(v, v2, edges[0])) {
+ v = vtable[BMINDEX_GET(loops[BLI_array_count(loops)-1]->v)];
+ v2 = vtable[BMINDEX_GET(loops[0]->v)];
+ }
+
+ f2 = BM_Make_Ngon(bm, v, v2, edges, f->len, 0);
+ if (!f2)
+ continue;
+
+ BMINDEX_SET(f, i);
+ BLI_array_growone(ftable);
+ ftable[i] = f2;
+
+ BM_Copy_Attributes(bmold, bm, f, f2);
+ copy_v3_v3(f2->no, f->no);
+
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f2);
+ for (j=0; j<f->len; j++, l = BMIter_Step(&liter)) {
+ BM_Copy_Attributes(bmold, bm, loops[j], l);
+ }
+
+ if (f == bmold->act_face) bm->act_face = f2;
+ }
+
+ /*copy over edit selection history*/
+ for (ese=bmold->selected.first; ese; ese=ese->next) {
+ void *ele;
+
+ if (ese->type == BM_VERT)
+ ele = vtable[BMINDEX_GET(ese->data)];
+ else if (ese->type == BM_EDGE)
+ ele = etable[BMINDEX_GET(ese->data)];
+ else if (ese->type == BM_FACE) {
+ ele = ftable[BMINDEX_GET(ese->data)];
+ }
+
+ BM_store_selection(bm, ele);
+ }
+
+ BLI_array_free(etable);
+ BLI_array_free(vtable);
+ BLI_array_free(ftable);
+
+ BLI_array_free(loops);
+ BLI_array_free(edges);
+
+ return bm;
+}
+
+/*
+ BM FLAGS TO ME FLAGS
+
+ Returns the flags stored in element,
+ which much be either a BMVert, BMEdge,
+ or BMFace, converted to mesh flags.
+*/
+
+int BMFlags_To_MEFlags(void *element) {
+ BMHeader *h = element;
+ int f = 0;
+
+ if (h->flag & BM_PINNED) f |= ME_PIN;
+ if (h->flag & BM_HIDDEN) f |= ME_HIDE;
+
+ if (h->type == BM_FACE) {
+ if (h->flag & BM_SELECT) f |= ME_FACE_SEL;
+ if (h->flag & BM_SMOOTH) f |= ME_SMOOTH;
+ } else if (h->type == BM_EDGE) {
+ if (h->flag & BM_SELECT) f |= BM_SELECT;
+ if (h->flag & BM_SEAM) f |= ME_SEAM;
+ if (h->flag & BM_SHARP) f |= ME_SHARP;
+ if (BM_Wire_Edge(NULL, element)) f |= ME_LOOSEEDGE;
+ f |= ME_EDGEDRAW;
+ } else if (h->type == BM_VERT) {
+ if (h->flag & BM_SELECT) f |= BM_SELECT;
+ }
+
+ return f;
+}
+
+/*
+ BM FLAGS TO ME FLAGS
+
+ Returns the flags stored in element,
+ which much be either a MVert, MEdge,
+ or MPoly, converted to mesh flags.
+ type must be either BM_VERT, BM_EDGE,
+ or BM_FACE.
+*/
+int MEFlags_To_BMFlags(int flag, int type) {
+ int f = 0;
+ if (flag & ME_PIN) f |= BM_PINNED;
+
+ if (type == BM_FACE) {
+ if (flag & ME_FACE_SEL) f |= BM_SELECT;
+ if (flag & ME_SMOOTH) f |= BM_SMOOTH;
+ if (flag & ME_HIDE) f |= BM_HIDDEN;
+ } else if (type == BM_EDGE) {
+ if (flag & SELECT) f |= BM_SELECT;
+ if (flag & ME_SEAM) f |= BM_SEAM;
+ if (flag & ME_SHARP) f |= BM_SHARP;
+ if (flag & ME_HIDE) f |= BM_HIDDEN;
+ } else if (type == BM_VERT) {
+ if (flag & SELECT) f |= BM_SELECT;
+ if (flag & ME_HIDE) f |= BM_HIDDEN;
+ }
+
+ return f;
+}
diff --git a/source/blender/bmesh/intern/bmesh_eulers.c b/source/blender/bmesh/intern/bmesh_eulers.c
new file mode 100644
index 00000000000..43b1ee76ffd
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_eulers.c
@@ -0,0 +1,1208 @@
+/*some of this may come back, such as split face or split edge, if necassary for speed*/
+
+#if 0
+/**
+ * bmesh_eulers.c jan 2007
+ *
+ * BM Euler construction API.
+ *
+ * $Id: bmesh_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** 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.
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_utildefines.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+
+/*********************************************************
+ * "Euler API" *
+ * *
+ * *
+ * Primitive construction operators for mesh tools. *
+ * *
+ **********************************************************/
+
+
+/*
+ The functions in this file represent the 'primitive' or 'atomic' operators that
+ mesh tools use to manipulate the topology of the structure.* The purpose of these
+ functions is to provide a trusted set of operators to manipulate the mesh topology
+ and which can also be combined together like building blocks to create more
+ sophisticated tools. It needs to be stressed that NO manipulation of an existing
+ mesh structure should be done outside of these functions.
+
+ In the BM system, each euler is named by an ancronym which describes what it actually does.
+ Furthermore each Euler has a logical inverse. An important design criteria of all Eulers is that
+ through a Euler's logical inverse you can 'undo' an operation. (Special note should
+ be taken of bmesh_loop_reverse, which is its own inverse).
+
+ bmesh_MF/KF: Make Face and Kill Face
+ bmesh_ME/KE: Make Edge and Kill Edge
+ bmesh_MV/KV: Make Vert and Kill Vert
+ bmesh_SEMV/JEKV: Split Edge, Make Vert and Join Edge, Kill Vert
+ bmesh_SFME/JFKE: Split Face, Make Edge and Join Face, Kill Edge
+ bmesh_loop_reverse: Reverse a Polygon's loop cycle. (used for flip normals for one)
+
+ Using a combination of these eleven eulers any non-manifold modelling operation can be achieved.
+ Each Euler operator has a detailed explanation of what is does in the comments preceding its
+ code.
+
+ *The term "Euler Operator" is actually a misnomer when referring to a non-manifold
+ data structure. Its use is in keeping with the convention established by others.
+
+ TODO:
+ -Make seperate 'debug levels' of validation
+ -Add in the UnglueFaceRegionMakeVert and GlueFaceRegionKillVert eulers.
+
+ NOTE:
+ -The functions in this file are notoriously difficult to debug and even understand sometimes.
+ better code comments would be nice....
+
+*/
+
+
+/*MAKE Eulers*/
+
+/**
+ * bmesh_MV
+ *
+ * MAKE VERT EULER:
+ *
+ * Makes a single loose vertex.
+ *
+ * Returns -
+ * A BMVert pointer.
+ */
+
+BMVert *bmesh_mv(BMesh *bm, float *vec){
+ BMVert *v = bmesh_addvertlist(bm, NULL);
+ VECCOPY(v->co,vec);
+ return v;
+}
+
+/**
+ * bmesh_ME
+ *
+ * MAKE EDGE EULER:
+ *
+ * Makes a single wire edge between two vertices.
+ * If the caller does not want there to be duplicate
+ * edges between the vertices, it is up to them to check
+ * for this condition beforehand.
+ *
+ * Returns -
+ * A BMEdge pointer.
+ */
+
+BMEdge *bmesh_me(BMesh *bm, BMVert *v1, BMVert *v2){
+ BMEdge *e=NULL;
+ BMNode *d1=NULL, *d2=NULL;
+ int valance1=0, valance2=0, edok;
+
+ /*edge must be between two distinct vertices...*/
+ if(v1 == v2) return NULL;
+
+ #ifndef bmesh_FASTEULER
+ /*count valance of v1*/
+ if(v1->e){
+ d1 = bmesh_disk_getpointer(v1->e,v1);
+ if(d1) valance1 = bmesh_cycle_length(d1);
+ else bmesh_error();
+ }
+ if(v2->e){
+ d2 = bmesh_disk_getpointer(v2->e,v2);
+ if(d2) valance2 = bmesh_cycle_length(d2);
+ else bmesh_error();
+ }
+ #endif
+
+ /*go ahead and add*/
+ e = bmesh_addedgelist(bm, v1, v2, NULL);
+ bmesh_disk_append_edge(e, e->v1);
+ bmesh_disk_append_edge(e, e->v2);
+
+ #ifndef bmesh_FASTEULER
+ /*verify disk cycle lengths*/
+ d1 = bmesh_disk_getpointer(e, e->v1);
+ edok = bmesh_cycle_validate(valance1+1, d1);
+ if(!edok) bmesh_error();
+ d2 = bmesh_disk_getpointer(e, e->v2);
+ edok = bmesh_cycle_validate(valance2+1, d2);
+ if(!edok) bmesh_error();
+
+ /*verify that edge actually made it into the cycle*/
+ edok = bmesh_disk_hasedge(v1, e);
+ if(!edok) bmesh_error();
+ edok = bmesh_disk_hasedge(v2, e);
+ if(!edok) bmesh_error();
+ #endif
+ return e;
+}
+
+
+
+/**
+ * bmesh_MF
+ *
+ * MAKE FACE EULER:
+ * Takes a list of edge pointers which form a closed loop and makes a face
+ * from them. The first edge in elist is considered to be the start of the
+ * polygon, and v1 and v2 are its vertices and determine the winding of the face
+ * Other than the first edge, no other assumptions are made about the order of edges
+ * in the elist array. To verify that it is a single closed loop and derive the correct
+ * order a simple series of verifications is done and all elements are visited.
+ *
+ * Returns -
+ * A BMFace pointer
+ */
+
+#define MF_CANDIDATE 1
+#define MF_VISITED 2
+#define MF_TAKEN 4
+
+BMFace *bmesh_mf(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **elist, int len)
+{
+ BMFace *f = NULL;
+ BMEdge *curedge;
+ BMVert *curvert, *tv, **vlist;
+ int i, j, done, cont, edok;
+
+ if(len < 2) return NULL;
+
+ /*make sure that v1 and v2 are in elist[0]*/
+ //if(bmesh_verts_in_edge(v1,v2,elist[0]) == 0)
+ // return NULL;
+
+ /*clear euler flags*/
+ for(i=0;i<len;i++) {
+ BMNode *diskbase;
+ BMEdge *curedge;
+ BMVert *v1;
+ int j;
+
+ for (j=0; j<2; j++) {
+ int a, len=0;
+
+ v1 = j ? elist[i]->v2 : elist[i]->v1;
+ diskbase = bmesh_disk_getpointer(v1->e, v1);
+ len = bmesh_cycle_length(diskbase);
+
+ for(a=0,curedge=v1->e;a<len;a++,curedge = bmesh_disk_nextedge(curedge,v1)){
+ curedge->head.eflag1 = curedge->head.eflag2 = 0;
+ }
+ }
+ }
+
+ for(i=0;i<len;i++){
+ elist[i]->head.eflag1 |= MF_CANDIDATE;
+
+ /*if elist[i] has a loop, count its radial length*/
+ if(elist[i]->loop) elist[i]->head.eflag2 = bmesh_cycle_length(&(elist[i]->l->radial));
+ else elist[i]->head.eflag2 = 0;
+ }
+
+ /* For each vertex in each edge, it must have exactly two MF_CANDIDATE edges attached to it
+ Note that this does not gauruntee that face is a single closed loop. At best it gauruntees
+ that elist contains a finite number of seperate closed loops.
+ */
+// for(i=0; i<len; i++){
+// edok = bmesh_disk_count_edgeflag(elist[i]->v1, MF_CANDIDATE, 0);
+// if(edok != 2) return NULL;
+// edok = bmesh_disk_count_edgeflag(elist[i]->v2, MF_CANDIDATE, 0);
+// if(edok != 2) return NULL;
+// }
+
+ /*set start edge, start vert and target vert for our loop traversal*/
+ curedge = elist[0];
+ tv = v1;
+ curvert = v2;
+
+ if(bm->vtarlen < len){
+ if (bm->vtar) MEM_freeN(bm->vtar);
+ bm->vtar = MEM_callocN(sizeof(BMVert *)* len, "BM Vert pointer array");
+ bm->vtarlen = len;
+ }
+ /*insert tv into vlist since its the first vertex in face*/
+
+ i=0;
+ vlist=bm->vtar;
+ vlist[i] = tv;
+
+ /* Basic procedure: Starting with curv we find the edge in it's disk cycle which hasn't
+ been visited yet. When we do, we put curv in a linked list and find the next MF_CANDIDATE
+ edge, loop until we find TV. We know TV is reachable because of test we did earlier.
+ */
+ done=0;
+ while(!done){
+ /*add curvert to vlist*/
+ /*insert some error cheking here for overflows*/
+ i++;
+ vlist[i] = curvert;
+
+ /*mark curedge as visited*/
+ curedge->head.eflag1 |= MF_VISITED;
+
+ /*find next edge and vert*/
+ curedge = bmesh_disk_next_edgeflag(curedge, curvert, MF_CANDIDATE, 0);
+ curvert = bmesh_edge_getothervert(curedge, curvert);
+ if(curvert == tv){
+ curedge->head.eflag1 |= MF_VISITED;
+ done=1;
+ }
+ }
+
+ /* Verify that all edges have been visited It's possible that we did reach tv
+ from sv, but that several unconnected loops were passed in via elist.
+ */
+ cont=1;
+// for(i=0; i<len; i++){
+// if((elist[i]->head.eflag1 & MF_VISITED) == 0) cont = 0;
+// }
+
+ /*if we get this far, its ok to allocate the face and add the loops*/
+ if(cont){
+ BMLoop *l;
+ BMEdge *e;
+ f = bmesh_addpolylist(bm, NULL);
+ f->len = len;
+ for(i=0;i<len;i++){
+ curvert = vlist[i];
+ l = bmesh_create_loop(bm,curvert,NULL,f,NULL);
+ if(!(f->loopbase)) f->lbase = l;
+ bmesh_cycle_append(f->lbase, l);
+ }
+
+ /*take care of edge pointers and radial cycle*/
+ for(i=0, l = f->loopbase; i<len; i++, l=((BMLoop*)(l->next))){
+ e = NULL;
+ if(l == f->loopbase) e = elist[0]; /*first edge*/
+
+ else{/*search elist for others*/
+ for(j=1; j<len; j++){
+ edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->next))->v, elist[j]);
+ if(edok){
+ e = elist[j];
+ break;
+ }
+ }
+ }
+ l->e = e; /*set pointer*/
+ bmesh_radial_append(e, l); /*append into radial*/
+ }
+
+ f->len = len;
+
+ /*Validation Loop cycle*/
+ edok = bmesh_cycle_validate(len, f->lbase);
+ if(!edok) bmesh_error();
+ for(i=0, l = f->loopbase; i<len; i++, l=((BMLoop*)(l->next))){
+ /*validate loop vert pointers*/
+ edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->next))->v, l->e);
+ if(!edok) bmesh_error();
+ /*validate the radial cycle of each edge*/
+ edok = bmesh_cycle_length(&(l->radial));
+ if(edok != (l->e->head.eflag2 + 1)) bmesh_error();
+ }
+ }
+
+ for(i=0;i<len;i++) elist[i]->head.eflag1=elist[i]->head.eflag2 = 0;
+ return f;
+}
+
+/* KILL Eulers */
+
+/**
+ * bmesh_KV
+ *
+ * KILL VERT EULER:
+ *
+ * Kills a single loose vertex.
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+ */
+
+int bmesh_kv(BMesh *bm, BMVert *v){
+ if(v->e == NULL){
+ if (BM_TestHFlag(v, BM_SELECT)) bm->totvertsel--;
+
+ BLI_remlink(&(bm->verts), &(v->head));
+ bmesh_free_vert(bm,v);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * bmesh_KE
+ *
+ * KILL EDGE EULER:
+ *
+ * Kills a wire edge.
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+ */
+
+int bmesh_ke(BMesh *bm, BMEdge *e){
+ int edok;
+
+ /*Make sure that no faces!*/
+ if(e->l == NULL){
+ bmesh_disk_remove_edge(e, e->v1);
+ bmesh_disk_remove_edge(e, e->v2);
+
+ /*verify that edge out of disk*/
+ edok = bmesh_disk_hasedge(e->v1, e);
+ if(edok) bmesh_error();
+ edok = bmesh_disk_hasedge(e->v2, e);
+ if(edok) bmesh_error();
+
+ /*remove and deallocate*/
+ if (BM_TestHFlag(e, BM_SELECT)) bm->totedgesel--;
+ BLI_remlink(&(bm->edges), &(e->head));
+ bmesh_free_edge(bm, e);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * bmesh_KF
+ *
+ * KILL FACE EULER:
+ *
+ * The logical inverse of bmesh_MF.
+ * Kills a face and removes each of its loops from the radial that it belongs to.
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+*/
+
+int bmesh_kf(BMesh *bm, BMFace *bply){
+ BMLoop *newbase,*oldbase, *curloop;
+ int i,len=0;
+
+ /*add validation to make sure that radial cycle is cleaned up ok*/
+ /*deal with radial cycle first*/
+ len = bmesh_cycle_length(bply->lbase);
+ for(i=0, curloop=bply->loopbase; i < len; i++, curloop = ((BMLoop*)(curloop->next)))
+ bmesh_radial_remove_loop(curloop, curloop->e);
+
+ /*now deallocate the editloops*/
+ for(i=0; i < len; i++){
+ newbase = ((BMLoop*)(bply->lbase->next));
+ oldbase = bply->lbase;
+ bmesh_cycle_remove(oldbase, oldbase);
+ bmesh_free_loop(bm, oldbase);
+ bply->loopbase = newbase;
+ }
+
+ if (BM_TestHFlag(bply, BM_SELECT)) bm->totfacesel--;
+ BLI_remlink(&(bm->polys), &(bply->head));
+ bmesh_free_poly(bm, bply);
+ return 1;
+}
+
+/*SPLIT Eulers*/
+
+/**
+ * bmesh_SEMV
+ *
+ * SPLIT EDGE MAKE VERT:
+ * Takes a given edge and splits it into two, creating a new vert.
+ *
+ *
+ * Before: OV---------TV
+ * After: OV----NV---TV
+ *
+ * Returns -
+ * BMVert pointer.
+ *
+*/
+
+BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **re){
+ BMVert *nv, *ov;
+ BMNode *diskbase;
+ BMEdge *ne;
+ int i, edok, valance1=0, valance2=0;
+
+ if(bmesh_vert_in_edge(e,tv) == 0) return NULL;
+ ov = bmesh_edge_getothervert(e,tv);
+ //v2 = tv;
+
+ /*count valance of v1*/
+ diskbase = bmesh_disk_getpointer(e, ov);
+ valance1 = bmesh_cycle_length(diskbase);
+ /*count valance of v2*/
+ diskbase = bmesh_disk_getpointer(e, tv);
+ valance2 = bmesh_cycle_length(diskbase);
+
+ nv = bmesh_addvertlist(bm, tv);
+ ne = bmesh_addedgelist(bm, nv, tv, e);
+
+ //e->v2 = nv;
+ /*remove e from v2's disk cycle*/
+ bmesh_disk_remove_edge(e, tv);
+ /*swap out tv for nv in e*/
+ bmesh_edge_swapverts(e, tv, nv);
+ /*add e to nv's disk cycle*/
+ bmesh_disk_append_edge(e, nv);
+ /*add ne to nv's disk cycle*/
+ bmesh_disk_append_edge(ne, nv);
+ /*add ne to tv's disk cycle*/
+ bmesh_disk_append_edge(ne, tv);
+ /*verify disk cycles*/
+ diskbase = bmesh_disk_getpointer(ov->e,ov);
+ edok = bmesh_cycle_validate(valance1, diskbase);
+ if(!edok) bmesh_error();
+ diskbase = bmesh_disk_getpointer(tv->e,tv);
+ edok = bmesh_cycle_validate(valance2, diskbase);
+ if(!edok) bmesh_error();
+ diskbase = bmesh_disk_getpointer(nv->e,nv);
+ edok = bmesh_cycle_validate(2, diskbase);
+ if(!edok) bmesh_error();
+
+ /*Split the radial cycle if present*/
+ if(e->l){
+ BMLoop *nl,*l;
+ BMNode *radEBase=NULL, *radNEBase=NULL;
+ int radlen = bmesh_cycle_length(&(e->l->radial));
+ /*Take the next loop. Remove it from radial. Split it. Append to appropriate radials.*/
+ while(e->l){
+ l=e->l;
+ l->f->len++;
+ bmesh_radial_remove_loop(l,e);
+
+ nl = bmesh_create_loop(bm,NULL,NULL,l->f,l);
+ nl->prev = (BMHeader*)l;
+ nl->next = (BMHeader*)(l->next);
+ nl->prev->next = (BMHeader*)nl;
+ nl->next->prev = (BMHeader*)nl;
+ nl->v = nv;
+
+ /*assign the correct edge to the correct loop*/
+ if(bmesh_verts_in_edge(nl->v, ((BMLoop*)(nl->next))->v, e)){
+ nl->e = e;
+ l->e = ne;
+
+ /*append l into ne's rad cycle*/
+ if(!radNEBase){
+ radNEBase = &(l->radial);
+ radNEBase->next = NULL;
+ radNEBase->prev = NULL;
+ }
+
+ if(!radEBase){
+ radEBase = &(nl->radial);
+ radEBase->next = NULL;
+ radEBase->prev = NULL;
+ }
+
+ bmesh_cycle_append(radEBase,&(nl->radial));
+ bmesh_cycle_append(radNEBase,&(l->radial));
+
+ }
+ else if(bmesh_verts_in_edge(nl->v,((BMLoop*)(nl->next))->v,ne)){
+ nl->e = ne;
+ l->e = e;
+
+ if(!radNEBase){
+ radNEBase = &(nl->radial);
+ radNEBase->next = NULL;
+ radNEBase->prev = NULL;
+ }
+ if(!radEBase){
+ radEBase = &(l->radial);
+ radEBase->next = NULL;
+ radEBase->prev = NULL;
+ }
+ bmesh_cycle_append(radEBase,&(l->radial));
+ bmesh_cycle_append(radNEBase,&(nl->radial));
+ }
+
+ }
+
+ e->l = radEBase->data;
+ ne->l = radNEBase->data;
+
+ /*verify length of radial cycle*/
+ edok = bmesh_cycle_validate(radlen,&(e->l->radial));
+ if(!edok) bmesh_error();
+ edok = bmesh_cycle_validate(radlen,&(ne->l->radial));
+ if(!edok) bmesh_error();
+
+ /*verify loop->v and loop->next->v pointers for e*/
+ for(i=0,l=e->l; i < radlen; i++, l = l->radial_next){
+ if(!(l->e == e)) bmesh_error();
+ if(!(l->radial.data == l)) bmesh_error();
+ if( ((BMLoop*)(l->prev))->e != ne && ((BMLoop*)(l->next))->e != ne) bmesh_error();
+ edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->next))->v, e);
+ if(!edok) bmesh_error();
+ if(l->v == ((BMLoop*)(l->next))->v) bmesh_error();
+ if(l->e == ((BMLoop*)(l->next))->e) bmesh_error();
+ /*verify loop cycle for kloop->f*/
+ edok = bmesh_cycle_validate(l->f->len, l->f->lbase);
+ if(!edok) bmesh_error();
+ }
+ /*verify loop->v and loop->next->v pointers for ne*/
+ for(i=0,l=ne->l; i < radlen; i++, l = l->radial_next){
+ if(!(l->e == ne)) bmesh_error();
+ if(!(l->radial.data == l)) bmesh_error();
+ if( ((BMLoop*)(l->prev))->e != e && ((BMLoop*)(l->next))->e != e) bmesh_error();
+ edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->next))->v, ne);
+ if(!edok) bmesh_error();
+ if(l->v == ((BMLoop*)(l->next))->v) bmesh_error();
+ if(l->e == ((BMLoop*)(l->next))->e) bmesh_error();
+ /*verify loop cycle for kloop->f. Redundant*/
+ edok = bmesh_cycle_validate(l->f->len, l->f->lbase);
+ if(!edok) bmesh_error();
+ }
+ }
+
+ if(re) *re = ne;
+ return nv;
+}
+
+/**
+ * bmesh_SFME
+ *
+ * SPLIT FACE MAKE EDGE:
+ *
+ * Takes as input two vertices in a single face. An edge is created which divides the original face
+ * into two distinct regions. One of the regions is assigned to the original face and it is closed off.
+ * The second region has a new face assigned to it.
+ *
+ * Examples:
+ *
+ * Before: After:
+ * ---------- ----------
+ * | | | |
+ * | | | f1 |
+ * v1 f1 v2 v1======v2
+ * | | | f2 |
+ * | | | |
+ * ---------- ----------
+ *
+ * Note that the input vertices can be part of the same edge. This will result in a two edged face.
+ * This is desirable for advanced construction tools and particularly essential for edge bevel. Because
+ * of this it is up to the caller to decide what to do with the extra edge.
+ *
+ * Note that the tesselator abuses eflag2 while using this euler! (don't ever ever do this....)
+ *
+ * Returns -
+ * A BMFace pointer
+ */
+BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **rl){
+
+ BMFace *f2;
+ BMLoop *v1loop = NULL, *v2loop = NULL, *curloop, *f1loop=NULL, *f2loop=NULL;
+ BMEdge *e;
+ int i, len, f1len, f2len;
+
+
+ /*verify that v1 and v2 are in face.*/
+ len = bmesh_cycle_length(f->lbase);
+ for(i = 0, curloop = f->loopbase; i < len; i++, curloop = ((BMLoop*)(curloop->next)) ){
+ if(curloop->v == v1) v1loop = curloop;
+ else if(curloop->v == v2) v2loop = curloop;
+ }
+
+ if(!v1loop || !v2loop) return NULL;
+
+ /*allocate new edge between v1 and v2*/
+ e = bmesh_addedgelist(bm, v1, v2,NULL);
+ bmesh_disk_append_edge(e, v1);
+ bmesh_disk_append_edge(e, v2);
+
+ f2 = bmesh_addpolylist(bm,f);
+ f1loop = bmesh_create_loop(bm,v2,e,f,v2loop);
+ f2loop = bmesh_create_loop(bm,v1,e,f2,v1loop);
+
+ f1loop->prev = v2loop->prev;
+ f2loop->prev = v1loop->prev;
+ v2loop->prev->next = (BMHeader*)f1loop;
+ v1loop->prev->next = (BMHeader*)f2loop;
+
+ f1loop->next = (BMHeader*)v1loop;
+ f2loop->next = (BMHeader*)v2loop;
+ v1loop->prev = (BMHeader*)f1loop;
+ v2loop->prev = (BMHeader*)f2loop;
+
+ f2->loopbase = f2loop;
+ f->loopbase = f1loop;
+
+ /*validate both loops*/
+ /*I dont know how many loops are supposed to be in each face at this point! FIXME!*/
+
+ /*go through all of f2's loops and make sure they point to it properly.*/
+ f2len = bmesh_cycle_length(f2->lbase);
+ for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->next)) ) curloop->f = f2;
+
+ /*link up the new loops into the new edges radial*/
+ bmesh_radial_append(e, f1loop);
+ bmesh_radial_append(e, f2loop);
+
+
+ f2->len = f2len;
+
+ f1len = bmesh_cycle_length(f->lbase);
+ f->len = f1len;
+
+ if(rl) *rl = f2loop;
+ return f2;
+}
+
+
+/**
+ * bmesh_JEKV
+ *
+ * JOIN EDGE KILL VERT:
+ * Takes a an edge and pointer to one of its vertices and collapses
+ * the edge on that vertex.
+ *
+ * Before: OE KE
+ * ------- -------
+ * | || |
+ * OV KV TV
+ *
+ *
+ * After: OE
+ * ---------------
+ * | |
+ * OV TV
+ *
+ *
+ * Restrictions:
+ * KV is a vertex that must have a valance of exactly two. Furthermore
+ * both edges in KV's disk cycle (OE and KE) must be unique (no double
+ * edges).
+ *
+ * It should also be noted that this euler has the possibility of creating
+ * faces with just 2 edges. It is up to the caller to decide what to do with
+ * these faces.
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+ */
+int bmesh_jekv(BMesh *bm, BMEdge *ke, BMVert *kv)
+{
+ BMEdge *oe;
+ BMVert *ov, *tv;
+ BMNode *diskbase;
+ BMLoop *killoop,*nextl;
+ int len,radlen=0, halt = 0, i, valance1, valance2,edok;
+
+ if(bmesh_vert_in_edge(ke,kv) == 0) return 0;
+ diskbase = bmesh_disk_getpointer(kv->e, kv);
+ len = bmesh_cycle_length(diskbase);
+
+ if(len == 2){
+ oe = bmesh_disk_nextedge(ke, kv);
+ tv = bmesh_edge_getothervert(ke, kv);
+ ov = bmesh_edge_getothervert(oe, kv);
+ halt = bmesh_verts_in_edge(kv, tv, oe); //check for double edges
+
+ if(halt) return 0;
+ else{
+
+ /*For verification later, count valance of ov and tv*/
+ diskbase = bmesh_disk_getpointer(ov->e, ov);
+ valance1 = bmesh_cycle_length(diskbase);
+ diskbase = bmesh_disk_getpointer(tv->e, tv);
+ valance2 = bmesh_cycle_length(diskbase);
+
+ /*remove oe from kv's disk cycle*/
+ bmesh_disk_remove_edge(oe,kv);
+ /*relink oe->kv to be oe->tv*/
+ bmesh_edge_swapverts(oe, kv, tv);
+ /*append oe to tv's disk cycle*/
+ bmesh_disk_append_edge(oe, tv);
+ /*remove ke from tv's disk cycle*/
+ bmesh_disk_remove_edge(ke, tv);
+
+
+
+ /*deal with radial cycle of ke*/
+ if(ke->l){
+ /*first step, fix the neighboring loops of all loops in ke's radial cycle*/
+ radlen = bmesh_cycle_length(&(ke->l->radial));
+ for(i=0,killoop = ke->l; i<radlen; i++, killoop = bmesh_radial_nextloop(killoop)){
+ /*relink loops and fix vertex pointer*/
+ killoop->next->prev = killoop->prev;
+ killoop->prev->next = killoop->next;
+ if( ((BMLoop*)(killoop->next))->v == kv) ((BMLoop*)(killoop->next))->v = tv;
+
+ /*fix len attribute of face*/
+ killoop->f->len--;
+ if(killoop->f->loopbase == killoop) killoop->f->lbase = ((BMLoop*)(killoop->next));
+ }
+ /*second step, remove all the hanging loops attached to ke*/
+ killoop = ke->l;
+ radlen = bmesh_cycle_length(&(ke->l->radial));
+ /*make sure we have enough room in bm->lpar*/
+ if(bm->lparlen < radlen){
+ MEM_freeN(bm->lpar);
+ bm->lpar = MEM_callocN(sizeof(BMLoop *)* radlen, "BM Loop pointer array");
+ bm->lparlen = bm->lparlen * radlen;
+ }
+ /*this should be wrapped into a bme_free_radial function to be used by bmesh_KF as well...*/
+ i=0;
+ while(i<radlen){
+ bm->lpar[i] = killoop;
+ killoop = killoop->radial_next;
+ i++;
+ }
+ i=0;
+ while(i<radlen){
+ bmesh_free_loop(bm,bm->lpar[i]);
+ i++;
+ }
+ /*Validate radial cycle of oe*/
+ edok = bmesh_cycle_validate(radlen,&(oe->l->radial));
+
+ }
+
+
+ /*Validate disk cycles*/
+ diskbase = bmesh_disk_getpointer(ov->e,ov);
+ edok = bmesh_cycle_validate(valance1, diskbase);
+ if(!edok) bmesh_error();
+ diskbase = bmesh_disk_getpointer(tv->e,tv);
+ edok = bmesh_cycle_validate(valance2, diskbase);
+ if(!edok) bmesh_error();
+
+ /*Validate loop cycle of all faces attached to oe*/
+ for(i=0,nextl = oe->l; i<radlen; i++, nextl = bmesh_radial_nextloop(nextl)){
+ edok = bmesh_cycle_validate(nextl->f->len,nextl->f->lbase);
+ if(!edok) bmesh_error();
+ }
+ /*deallocate edge*/
+ BLI_remlink(&(bm->edges), &(ke->head));
+ bmesh_free_edge(bm, ke);
+ /*deallocate vertex*/
+ BLI_remlink(&(bm->verts), &(kv->head));
+ bmesh_free_vert(bm, kv);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * bmesh_loop_reverse
+ *
+ * FLIP FACE EULER
+ *
+ * Changes the winding order of a face from CW to CCW or vice versa.
+ * This euler is a bit peculiar in compairson to others as it is its
+ * own inverse.
+ *
+ * TODO: reinsert validation code.
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+ */
+
+int bmesh_loop_reverse(BMesh *bm, BMFace *f){
+ BMLoop *l = f->loopbase, *curloop, *oldprev, *oldnext;
+ int i, j, edok, len = 0;
+
+ len = bmesh_cycle_length(l);
+ if(bm->edarlen < len){
+ MEM_freeN(bm->edar);
+ bm->edar = MEM_callocN(sizeof(BMEdge *)* len, "BM Edge pointer array");
+ bm->edarlen = len;
+ }
+
+ for(i=0, curloop = l; i< len; i++, curloop= ((BMLoop*)(curloop->next)) ){
+ curloop->e->head.eflag1 = 0;
+ curloop->e->head.eflag2 = bmesh_cycle_length(&curloop->radial);
+ bmesh_radial_remove_loop(curloop, curloop->e);
+ /*in case of border edges we HAVE to zero out curloop->radial Next/Prev*/
+ curloop->radial.next = curloop->radial.prev = NULL;
+ bm->edar[i] = curloop->e;
+ }
+
+ /*actually reverse the loop. This belongs in bmesh_cycle_reverse!*/
+ for(i=0, curloop = l; i < len; i++){
+ oldnext = ((BMLoop*)(curloop->next));
+ oldprev = ((BMLoop*)(curloop->prev));
+ curloop->next = (BMHeader*)oldprev;
+ curloop->prev = (BMHeader*)oldnext;
+ curloop = oldnext;
+ }
+
+ if(len == 2){ //two edged face
+ //do some verification here!
+ l->e = bm->edar[1];
+ ((BMLoop*)(l->next))->e = bm->edar[0];
+ }
+ else{
+ for(i=0, curloop = l; i < len; i++, curloop = ((BMLoop*)(curloop->next)) ){
+ edok = 0;
+ for(j=0; j < len; j++){
+ edok = bmesh_verts_in_edge(curloop->v, ((BMLoop*)(curloop->next))->v, bm->edar[j]);
+ if(edok){
+ curloop->e = bm->edar[j];
+ break;
+ }
+ }
+ }
+ }
+ /*rebuild radial*/
+ for(i=0, curloop = l; i < len; i++, curloop = ((BMLoop*)(curloop->next)) ) bmesh_radial_append(curloop->e, curloop);
+
+ /*validate radial*/
+ for(i=0, curloop = l; i < len; i++, curloop = ((BMLoop*)(curloop->next)) ){
+ edok = bmesh_cycle_validate(curloop->e->head.eflag2, &(curloop->radial));
+ if(!edok){
+ bmesh_error();
+ }
+ }
+ return 1;
+}
+
+/**
+ * bmesh_JFKE
+ *
+ * JOIN FACE KILL EDGE:
+ *
+ * Takes two faces joined by a single 2-manifold edge and fuses them togather.
+ * The edge shared by the faces must not be connected to any other edges which have
+ * Both faces in its radial cycle
+ *
+ * Examples:
+ *
+ * A B
+ * ---------- ----------
+ * | | | |
+ * | f1 | | f1 |
+ * v1========v2 = Ok! v1==V2==v3 == Wrong!
+ * | f2 | | f2 |
+ * | | | |
+ * ---------- ----------
+ *
+ * In the example A, faces f1 and f2 are joined by a single edge, and the euler can safely be used.
+ * In example B however, f1 and f2 are joined by multiple edges and will produce an error. The caller
+ * in this case should call bmesh_JEKV on the extra edges before attempting to fuse f1 and f2.
+ *
+ * Also note that the order of arguments decides whether or not certain per-face attributes are present
+ * in the resultant face. For instance vertex winding, material index, smooth flags, ect are inherited
+ * from f1, not f2.
+ *
+ * Returns -
+ * A BMFace pointer
+*/
+
+//disregarding f1loop and f2loop, if a vertex appears in a joined face more than once, we cancel
+
+BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
+{
+
+ BMLoop *curloop, *f1loop=NULL, *f2loop=NULL;
+ int loopok = 0, newlen = 0,i, f1len=0, f2len=0, radlen=0, edok, shared;
+
+ if(f1 == f2) return NULL; //can't join a face to itself
+ /*verify that e is in both f1 and f2*/
+ f1len = bmesh_cycle_length(f1->lbase);
+ f2len = bmesh_cycle_length(f2->lbase);
+ for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((BMLoop*)(curloop->next)) ){
+ if(curloop->e == e){
+ f1loop = curloop;
+ break;
+ }
+ }
+ for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->next)) ){
+ if(curloop->e==e){
+ f2loop = curloop;
+ break;
+ }
+ }
+ if(!(f1loop && f2loop)) return NULL;
+
+ /*validate that edge is 2-manifold edge*/
+ radlen = bmesh_cycle_length(&(f1loop->radial));
+ if(radlen != 2) return NULL;
+
+ /*validate direction of f2's loop cycle is compatible.*/
+ if(f1loop->v == f2loop->v) return NULL;
+
+ /*
+ validate that for each face, each vertex has another edge in its disk cycle that is
+ not e, and not shared.
+ */
+ if(bmesh_radial_find_face( ((BMLoop*)(f1loop->next))->e,f2)) return NULL;
+ if(bmesh_radial_find_face( ((BMLoop*)(f1loop->prev))->e,f2)) return NULL;
+ if(bmesh_radial_find_face( ((BMLoop*)(f2loop->next))->e,f1)) return NULL;
+ if(bmesh_radial_find_face( ((BMLoop*)(f2loop->prev))->e,f1)) return NULL;
+
+ /*validate only one shared edge*/
+ shared = BM_Face_Sharededges(f1,f2);
+ if(shared > 1) return NULL;
+
+ /*validate no internal joins*/
+ for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((BMLoop*)(curloop->next)) ) curloop->v->head.eflag1 = 0;
+ for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->next)) ) curloop->v->head.eflag1 = 0;
+
+ for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((BMLoop*)(curloop->next)) ){
+ if(curloop != f1loop)
+ curloop->v->head.eflag1++;
+ }
+ for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->next)) ){
+ if(curloop != f2loop)
+ curloop->v->head.eflag1++;
+ }
+
+ for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((BMLoop*)(curloop->next)) ){
+ if(curloop->v->head.eflag1 > 1)
+ return NULL;
+ }
+
+ for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->next)) ){
+ if(curloop->v->head.eflag1 > 1)
+ return NULL;
+ }
+
+ /*join the two loops*/
+ f1loop->prev->next = f2loop->next;
+ f2loop->next->prev = f1loop->prev;
+
+ f1loop->next->prev = f2loop->prev;
+ f2loop->prev->next = f1loop->next;
+
+ /*if f1loop was baseloop, give f1loop->next the base.*/
+ if(f1->loopbase == f1loop) f1->lbase = ((BMLoop*)(f1loop->next));
+
+ /*validate the new loop*/
+ loopok = bmesh_cycle_validate((f1len+f2len)-2, f1->lbase);
+ if(!loopok) bmesh_error();
+
+ /*make sure each loop points to the proper face*/
+ newlen = bmesh_cycle_length(f1->lbase);
+ for(i = 0, curloop = f1->loopbase; i < newlen; i++, curloop = ((BMLoop*)(curloop->next)) ) curloop->f = f1;
+
+ f1->len = newlen;
+
+ edok = bmesh_cycle_validate(f1->len, f1->lbase);
+ if(!edok) bmesh_error();
+
+ /*remove edge from the disk cycle of its two vertices.*/
+ bmesh_disk_remove_edge(f1loop->e, f1loop->e->v1);
+ bmesh_disk_remove_edge(f1loop->e, f1loop->e->v2);
+
+ /*deallocate edge and its two loops as well as f2*/
+ BLI_remlink(&(bm->edges), &(f1loop->e->head));
+ BLI_remlink(&(bm->polys), &(f2->head));
+ bmesh_free_edge(bm, f1loop->e);
+ bmesh_free_loop(bm, f1loop);
+ bmesh_free_loop(bm, f2loop);
+ bmesh_free_poly(bm, f2);
+ return f1;
+}
+
+/**
+* bmesh_URMV
+*
+* UNGLUE REGION MAKE VERT:
+*
+* Takes a locally manifold disk of face corners and 'unglues' it
+* creating a new vertex
+*
+**/
+
+#define URMV_VISIT 1
+#define URMV_VISIT2 2
+
+BMVert *bmesh_urmv(BMesh *bm, BMFace *sf, BMVert *sv)
+{
+ BMVert *nv = NULL;
+ BMLoop *l = NULL, *sl = NULL;
+ BMEdge *curedge = NULL;
+ int numloops = 0, numedges = 0, i, maxedges, maxloops;
+
+
+ /*Todo: Validation*/
+ /*validate radial cycle of all collected loops*/
+ /*validate the disk cycle of sv, and nv*/
+ /*validate the face length of all faces? overkill?*/
+ /*validate the l->e pointers of all affected faces, ie: l->v and l->next->v should be equivalent to l->e*/
+
+ /*verify that sv has edges*/
+ if(sv->e == NULL)
+ return NULL;
+
+ /*first verify no wire edges on sv*/
+ curedge = sv->e;
+ do{
+ if(curedge->l == NULL)
+ return NULL;
+ curedge = bmesh_disk_nextedge(curedge, sv);
+ }while(curedge != sv->e);
+
+ /*next verify that sv is in sf*/
+ l = sf->loopbase;
+ do{
+ if(l->v == sv){
+ sl = l;
+ break;
+ }
+ l = (BMLoop*)(l->next);
+ }while(l != sf->lbase);
+
+ if(sl == NULL)
+ return NULL;
+
+ /*clear euler flags*/
+ sv->head.eflag1 = 0;
+
+ curedge = sv->e;
+ do{
+ curedge->head.eflag1 = 0;
+ l = curedge->l;
+ do{
+ l->head.eflag1 = 0;
+ l->f->head.eflag1 = 0;
+ l = bmesh_radial_nextloop(l);
+ }while(l != curedge->l);
+ curedge = bmesh_disk_nextedge(curedge, sv);
+ }while(curedge != sv->e);
+
+ /*search through face disk and flag elements as we go.*/
+ /*Note, test this to make sure that it works correct on
+ non-manifold faces!
+ */
+ l = sl;
+ l->e->head.eflag1 |= URMV_VISIT;
+ l->f->head.eflag1 |= URMV_VISIT;
+ do{
+ if(l->v == sv)
+ l = bmesh_radial_nextloop((BMLoop*)(l->prev));
+ else
+ l = bmesh_radial_nextloop((BMLoop*)(l->next));
+ l->e->head.eflag1 |= URMV_VISIT;
+ l->f->head.eflag1 |= URMV_VISIT;
+ }while(l != sl && (bmesh_cycle_length(&(l->radial)) > 1) );
+
+ /*Verify that all visited edges are at least 1 or 2 manifold*/
+ curedge = sv->e;
+ do{
+ if(curedge->head.eflag1 && (bmesh_cycle_length(&(curedge->l->radial)) > 2) )
+ return NULL;
+ curedge = bmesh_disk_nextedge(curedge, sv);
+ }while(curedge != sv->e);
+
+ /*allocate temp storage - we overallocate here instead of trying to be clever*/
+ maxedges = 0;
+ maxloops = 0;
+ curedge = sv->e;
+ do{
+ if(curedge->l){
+ l = curedge->l;
+ do{
+ maxloops += l->f->len;
+ l = bmesh_radial_nextloop(l);
+ }while(l != curedge->l);
+ }
+ maxedges+= 1;
+ curedge = bmesh_disk_nextedge(curedge,sv);
+ }while(curedge != sv->e);
+
+ if(bm->edarlen < maxedges){
+ MEM_freeN(bm->edar);
+ bm->edar = MEM_callocN(sizeof(BMEdge *) * maxedges, "BM Edge pointer array");
+ bm->edarlen = maxedges;
+ }
+ if(bm->lparlen < maxloops){
+ MEM_freeN(bm->lpar);
+ bm->lpar = MEM_callocN(sizeof(BMLoop *) * maxloops, "BM Loop pointer array");
+ bm->lparlen = maxloops;
+ }
+
+ /*first get loops by looping around edges and loops around that edges faces*/
+ curedge = sv->e;
+ do{
+ if(curedge->l){
+ l = curedge->l;
+ do{
+ if( (l->head.eflag1 & URMV_VISIT) && (!(l->head.eflag1 & URMV_VISIT2)) ){
+ bm->lpar[numloops] = l;
+ l->head.eflag1 |= URMV_VISIT2;
+ numloops++;
+ }
+ l = bmesh_radial_nextloop(l);
+ }while(l != curedge->l);
+ }
+ curedge = bmesh_disk_nextedge(curedge, sv);
+ }while(curedge != sv->e);
+
+ /*now collect edges by looping around edges and looking at visited flags*/
+ curedge = sv->e;
+ do{
+ if(curedge->head.eflag1 & URMV_VISIT){
+ bm->edar[numedges] = curedge;
+ numedges++;
+ }
+ curedge = bmesh_disk_nextedge(curedge, sv);
+ }while(curedge != sv->e);
+
+ /*make new vertex*/
+ nv = bmesh_addvertlist(bm, sv);
+
+ /*go through and relink edges*/
+ for(i = 0; i < numedges; i++){
+ curedge = bm->edar[i];
+ /*remove curedge from sv*/
+ bmesh_disk_remove_edge(curedge, sv);
+ /*swap out sv for nv in curedge*/
+ bmesh_edge_swapverts(curedge, sv, nv);
+ /*add curedge to nv's disk cycle*/
+ bmesh_disk_append_edge(curedge, nv);
+ }
+
+ /*go through and relink loops*/
+ for(i = 0; i < numloops; i ++){
+ l = bm->lpar[i];
+ if(l->v == sv)
+ l->v = nv;
+ }
+ return nv;
+}
+#endif
diff --git a/source/blender/bmesh/intern/bmesh_filters.c b/source/blender/bmesh/intern/bmesh_filters.c
new file mode 100644
index 00000000000..c31139a8f93
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_filters.c
@@ -0,0 +1,5 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "bmesh.h"
+#include "bmesh_private.h"
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
new file mode 100644
index 00000000000..9dfe3c63be9
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -0,0 +1,297 @@
+/**
+ * BME_interp.c August 2008
+ *
+ * BM interpolation functions.
+ *
+ * ***** 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.
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_array.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+/*
+ * BME_INTERP.C
+ *
+ * Functions for interpolating data across the surface of a mesh.
+ *
+*/
+
+/**
+ * bmesh_data_interp_from_verts
+ *
+ * Interpolates per-vertex data from two sources to a target.
+ *
+ * Returns -
+ * Nothing
+ */
+void BM_Data_Interp_From_Verts(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, float fac)
+{
+ void *src[2];
+ float w[2];
+ if (v1->head.data && v2->head.data) {
+ src[0]= v1->head.data;
+ src[1]= v2->head.data;
+ w[0] = 1.0f-fac;
+ w[1] = fac;
+ CustomData_bmesh_interp(&bm->vdata, src, w, NULL, 2, v->head.data);
+ }
+}
+
+/*
+ BM Data Vert Average
+
+ Sets all the customdata (e.g. vert, loop) associated with a vert
+ to the average of the face regions surrounding it.
+*/
+
+//CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, vloop->head.data);
+
+void BM_Data_Vert_Average(BMesh *bm, BMFace *f)
+{
+ BMIter iter;
+}
+
+/**
+ * bmesh_data_facevert_edgeinterp
+ *
+ * Walks around the faces of an edge and interpolates the per-face-edge
+ * data between two sources to a target.
+ *
+ * Returns -
+ * Nothing
+*/
+
+void BM_Data_Facevert_Edgeinterp(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, BMEdge *e1, float fac){
+ void *src[2];
+ float w[2];
+ BMLoop *l=NULL, *v1loop = NULL, *vloop = NULL, *v2loop = NULL;
+
+ w[1] = 1.0f - fac;
+ w[0] = fac;
+
+ if(!e1->l) return;
+ l = e1->l;
+ do{
+ if(l->v == v1){
+ v1loop = l;
+ vloop = (BMLoop*)(v1loop->next);
+ v2loop = (BMLoop*)(vloop->next);
+ }else if(l->v == v){
+ v1loop = (BMLoop*)(l->next);
+ vloop = l;
+ v2loop = (BMLoop*)(l->prev);
+
+ }
+
+ src[0] = v1loop->head.data;
+ src[1] = v2loop->head.data;
+
+ CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, vloop->head.data);
+ l = l->radial_next;
+ }while(l!=e1->l);
+}
+
+void BM_loops_to_corners(BMesh *bm, Mesh *me, int findex,
+ BMFace *f, int numTex, int numCol)
+{
+ BMLoop *l;
+ BMIter iter;
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ int i, j;
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_get_n(&me->fdata, CD_MTFACE, findex, i);
+ texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
+
+ texface->tpage = texpoly->tpage;
+ texface->flag = texpoly->flag;
+ texface->transp = texpoly->transp;
+ texface->mode = texpoly->mode;
+ texface->tile = texpoly->tile;
+ texface->unwrap = texpoly->unwrap;
+
+ j = 0;
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
+ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
+ texface->uv[j][0] = mloopuv->uv[0];
+ texface->uv[j][1] = mloopuv->uv[1];
+
+ j++;
+ }
+
+ }
+
+ for(i=0; i < numCol; i++){
+ mcol = CustomData_get_n(&me->fdata, CD_MCOL, findex, i);
+
+ j = 0;
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
+ mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
+ mcol[j].r = mloopcol->r;
+ mcol[j].g = mloopcol->g;
+ mcol[j].b = mloopcol->b;
+ mcol[j].a = mloopcol->a;
+
+ j++;
+ }
+ }
+}
+
+//static void bmesh_data_interp_from_face(BME_Mesh *bm, BMFace *source, BMFace *target)
+//{
+//
+//}
+/*insert BM_data_interp_from_face here for mean value coordinates...*/
+
+
+static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
+{
+ BMIter iter;
+ BLI_mempool *oldpool = olddata->pool;
+ void *block;
+
+ CustomData_bmesh_init_pool(data, data==&bm->ldata ? 2048 : 512);
+
+ if (data == &bm->vdata) {
+ BMVert *eve;
+
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ block = NULL;
+ CustomData_bmesh_set_default(data, &block);
+ CustomData_bmesh_copy_data(olddata, data, eve->head.data, &block);
+ CustomData_bmesh_free_block(olddata, &eve->head.data);
+ eve->head.data= block;
+ }
+ }
+ else if (data == &bm->edata) {
+ BMEdge *eed;
+
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ block = NULL;
+ CustomData_bmesh_set_default(data, &block);
+ CustomData_bmesh_copy_data(olddata, data, eed->head.data, &block);
+ CustomData_bmesh_free_block(olddata, &eed->head.data);
+ eed->head.data= block;
+ }
+ }
+ else if (data == &bm->pdata || data == &bm->ldata) {
+ BMIter liter;
+ BMFace *efa;
+ BMLoop *l;
+
+ BM_ITER(efa, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (data == &bm->pdata) {
+ block = NULL;
+ CustomData_bmesh_set_default(data, &block);
+ CustomData_bmesh_copy_data(olddata, data, efa->head.data, &block);
+ CustomData_bmesh_free_block(olddata, &efa->head.data);
+ efa->head.data= block;
+ }
+
+ if (data == &bm->ldata) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) {
+ block = NULL;
+ CustomData_bmesh_set_default(data, &block);
+ CustomData_bmesh_copy_data(olddata, data, l->head.data, &block);
+ CustomData_bmesh_free_block(olddata, &l->head.data);
+ l->head.data= block;
+ }
+ }
+ }
+ }
+}
+
+
+void BM_add_data_layer(BMesh *bm, CustomData *data, int type)
+{
+ CustomData olddata;
+
+ olddata= *data;
+ olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
+ CustomData_add_layer(data, type, CD_DEFAULT, NULL, 0);
+
+ update_data_blocks(bm, &olddata, data);
+ if (olddata.layers) MEM_freeN(olddata.layers);
+}
+
+void BM_add_data_layer_named(BMesh *bm, CustomData *data, int type, char *name)
+{
+ CustomData olddata;
+
+ olddata= *data;
+ olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
+ CustomData_add_layer_named(data, type, CD_DEFAULT, NULL, 0, name);
+
+ update_data_blocks(bm, &olddata, data);
+ if (olddata.layers) MEM_freeN(olddata.layers);
+}
+
+void BM_free_data_layer(BMesh *bm, CustomData *data, int type)
+{
+ CustomData olddata;
+
+ olddata= *data;
+ olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
+ CustomData_free_layer_active(data, type, 0);
+
+ update_data_blocks(bm, &olddata, data);
+ if (olddata.layers) MEM_freeN(olddata.layers);
+}
+
+float BM_GetCDf(CustomData *cd, void *element, int type)
+{
+ if (CustomData_has_layer(cd, type)) {
+ float *f = CustomData_bmesh_get(cd, ((BMHeader*)element)->data, type);
+ return *f;
+ }
+
+ return 0.0;
+}
+
+void BM_SetCDf(CustomData *cd, void *element, int type, float val)
+{
+ if (CustomData_has_layer(cd, type)) {
+ float *f = CustomData_bmesh_get(cd, ((BMHeader*)element)->data, type);
+ *f = val;
+ }
+
+ return;
+}
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
new file mode 100644
index 00000000000..1f737ac9fe9
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -0,0 +1,466 @@
+#include <string.h>
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+
+void *BMIter_AtIndex(struct BMesh *bm, int type, void *data, int index)
+{
+ BMIter iter;
+ void *val;
+ int i;
+
+ /*sanity check*/
+ if (index < 0) return NULL;
+
+ val=BMIter_New(&iter, bm, type, data);
+
+ i = 0;
+ while (i < index) {
+ val=BMIter_Step(&iter);
+ i++;
+ }
+
+ return val;
+}
+
+/*
+ * BMESH ITERATOR STEP
+ *
+ * Calls an iterators step fucntion to return
+ * the next element.
+*/
+
+void *BMIter_Step(BMIter *iter)
+{
+ return iter->step(iter);
+}
+
+/*
+ * INIT ITERATOR
+ *
+ * Clears the internal state of an iterator
+ * For begin() callbacks.
+ *
+*/
+
+static void init_iterator(BMIter *iter)
+{
+ iter->firstvert = iter->nextvert = NULL;
+ iter->firstedge = iter->nextedge = NULL;
+ iter->firstloop = iter->nextloop = NULL;
+ iter->firstpoly = iter->nextpoly = NULL;
+ iter->ldata = NULL;
+}
+
+/*
+ * Notes on iterator implementation:
+ *
+ * Iterators keep track of the next element
+ * in a sequence. When a step() callback is
+ * invoked the current value of 'next' is stored
+ * to be returned later and the next variable is
+ * incremented.
+ *
+ * When the end of a sequence is
+ * reached, next should always equal NULL
+ *
+*/
+
+/*
+ * VERT OF MESH CALLBACKS
+ *
+*/
+
+static void vert_of_mesh_begin(BMIter *iter)
+{
+ BLI_mempool_iternew(iter->bm->vpool, &iter->pooliter);
+}
+
+static void *vert_of_mesh_step(BMIter *iter)
+{
+ return BLI_mempool_iterstep(&iter->pooliter);
+
+}
+
+static void edge_of_mesh_begin(BMIter *iter)
+{
+ BLI_mempool_iternew(iter->bm->epool, &iter->pooliter);
+}
+
+static void *edge_of_mesh_step(BMIter *iter)
+{
+ return BLI_mempool_iterstep(&iter->pooliter);
+
+}
+
+static void face_of_mesh_begin(BMIter *iter)
+{
+ BLI_mempool_iternew(iter->bm->fpool, &iter->pooliter);
+}
+
+static void *face_of_mesh_step(BMIter *iter)
+{
+ return BLI_mempool_iterstep(&iter->pooliter);
+
+}
+
+/*
+ * EDGE OF VERT CALLBACKS
+ *
+*/
+
+static void edge_of_vert_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ if(iter->vdata->e){
+ iter->firstedge = iter->vdata->e;
+ iter->nextedge = iter->vdata->e;
+ }
+}
+
+static void *edge_of_vert_step(BMIter *iter)
+{
+ BMEdge *current = iter->nextedge;
+
+ if(iter->nextedge)
+ iter->nextedge = bmesh_disk_nextedge(iter->nextedge, iter->vdata);
+
+ if(iter->nextedge == iter->firstedge) iter->nextedge = NULL;
+
+ return current;
+}
+
+/*
+ * FACE OF VERT CALLBACKS
+ *
+*/
+
+static void face_of_vert_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ iter->count = 0;
+ if(iter->vdata->e)
+ iter->count = bmesh_disk_count_facevert(iter->vdata);
+ if(iter->count){
+ iter->firstedge = bmesh_disk_find_first_faceedge(iter->vdata->e, iter->vdata);
+ iter->nextedge = iter->firstedge;
+ iter->firstloop = bmesh_radial_find_first_facevert(iter->firstedge->l, iter->vdata);
+ iter->nextloop = iter->firstloop;
+ }
+}
+static void *face_of_vert_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if(iter->count && iter->nextloop) {
+ iter->count--;
+ iter->nextloop = bmesh_radial_find_next_facevert(iter->nextloop, iter->vdata);
+ if(iter->nextloop == iter->firstloop){
+ iter->nextedge = bmesh_disk_find_next_faceedge(iter->nextedge, iter->vdata);
+ iter->firstloop = bmesh_radial_find_first_facevert(iter->nextedge->l, iter->vdata);
+ iter->nextloop = iter->firstloop;
+ }
+ }
+
+ if(!iter->count) iter->nextloop = NULL;
+
+
+ if(current) return current->f;
+ return NULL;
+}
+
+
+/*
+ * LOOP OF VERT CALLBACKS
+ *
+*/
+
+static void loop_of_vert_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ iter->count = 0;
+ if(iter->vdata->e)
+ iter->count = bmesh_disk_count_facevert(iter->vdata);
+ if(iter->count){
+ iter->firstedge = bmesh_disk_find_first_faceedge(iter->vdata->e, iter->vdata);
+ iter->nextedge = iter->firstedge;
+ iter->firstloop = bmesh_radial_find_first_facevert(iter->firstedge->l, iter->vdata);
+ iter->nextloop = iter->firstloop;
+ }
+}
+static void *loop_of_vert_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if(iter->count){
+ iter->count--;
+ iter->nextloop = bmesh_radial_find_next_facevert(iter->nextloop, iter->vdata);
+ if(iter->nextloop == iter->firstloop){
+ iter->nextedge = bmesh_disk_find_next_faceedge(iter->nextedge, iter->vdata);
+ iter->firstloop = bmesh_radial_find_first_facevert(iter->nextedge->l, iter->vdata);
+ iter->nextloop = iter->firstloop;
+ }
+ }
+
+ if(!iter->count) iter->nextloop = NULL;
+
+
+ if(current) return current;
+ return NULL;
+}
+
+
+static void loops_of_edge_begin(BMIter *iter)
+{
+ BMLoop *l;
+
+ l = iter->edata->l;
+ if (!l)
+ return;
+
+ /*note sure why this sets ldata. . .*/
+ init_iterator(iter);
+
+ iter->firstloop = iter->nextloop = l;
+}
+
+static void *loops_of_edge_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if(iter->nextloop)
+ iter->nextloop = bmesh_radial_nextloop(iter->nextloop);
+
+ if(iter->nextloop == iter->firstloop)
+ iter->nextloop = NULL;
+
+ if(current) return current;
+ return NULL;
+}
+
+static void loops_of_loop_begin(BMIter *iter)
+{
+ BMLoop *l;
+
+ l = iter->ldata;
+
+ /*note sure why this sets ldata. . .*/
+ init_iterator(iter);
+
+ iter->firstloop = l;
+ iter->nextloop = bmesh_radial_nextloop(iter->firstloop);
+}
+
+static void *loops_of_loop_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if(iter->nextloop) iter->nextloop = bmesh_radial_nextloop(iter->nextloop);
+
+ if(iter->nextloop == iter->firstloop) iter->nextloop = NULL;
+ if(current) return current;
+ return NULL;
+}
+
+/*
+ * FACE OF EDGE CALLBACKS
+ *
+*/
+
+static void face_of_edge_begin(BMIter *iter)
+{
+ init_iterator(iter);
+
+ if(iter->edata->l){
+ iter->firstloop = iter->edata->l;
+ iter->nextloop = iter->edata->l;
+ }
+}
+
+static void *face_of_edge_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if(iter->nextloop) iter->nextloop = bmesh_radial_nextloop(iter->nextloop);
+
+ if(iter->nextloop == iter->firstloop) iter->nextloop = NULL;
+ if(current) return current->f;
+ return NULL;
+}
+
+/*
+ * VERT OF FACE CALLBACKS
+ *
+*/
+
+static void vert_of_face_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ iter->firstloop = iter->nextloop = ((BMLoopList*)iter->pdata->loops.first)->first;
+}
+
+static void *vert_of_face_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if(iter->nextloop) iter->nextloop = ((BMLoop*)(iter->nextloop->next));
+ if(iter->nextloop == iter->firstloop) iter->nextloop = NULL;
+
+ if(current) return current->v;
+ return NULL;
+}
+
+/*
+ * EDGE OF FACE CALLBACKS
+ *
+*/
+
+static void edge_of_face_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ iter->firstloop = iter->nextloop = ((BMLoopList*)iter->pdata->loops.first)->first;
+}
+
+static void *edge_of_face_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if(iter->nextloop) iter->nextloop = ((BMLoop*)(iter->nextloop->next));
+ if(iter->nextloop == iter->firstloop) iter->nextloop = NULL;
+
+ if(current) return current->e;
+ return NULL;
+}
+
+/*
+ * LOOP OF FACE CALLBACKS
+ *
+*/
+
+static void loop_of_face_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ iter->firstloop = iter->nextloop = bm_firstfaceloop(iter->pdata);
+}
+
+static void *loop_of_face_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if(iter->nextloop) iter->nextloop = ((BMLoop*)(iter->nextloop->next));
+ if(iter->nextloop == iter->firstloop) iter->nextloop = NULL;
+
+ return current;
+}
+
+/*
+ * BMESH ITERATOR INIT
+ *
+ * Takes a bmesh iterator structure and fills
+ * it with the appropriate function pointers based
+ * upon its type and then calls BMeshIter_step()
+ * to return the first element of the iterator.
+ *
+*/
+void *BMIter_New(BMIter *iter, BMesh *bm, int type, void *data)
+{
+ int argtype;
+ iter->type = type;
+ iter->bm = bm;
+
+ switch(type){
+ case BM_VERTS_OF_MESH:
+ iter->begin = vert_of_mesh_begin;
+ iter->step = vert_of_mesh_step;
+ iter->bm = bm;
+ break;
+ case BM_EDGES_OF_MESH:
+ iter->begin = edge_of_mesh_begin;
+ iter->step = edge_of_mesh_step;
+ iter->bm = bm;
+ break;
+ case BM_FACES_OF_MESH:
+ iter->begin = face_of_mesh_begin;
+ iter->step = face_of_mesh_step;
+ iter->bm = bm;
+ break;
+ case BM_EDGES_OF_VERT:
+ if (!data)
+ return NULL;
+
+ iter->begin = edge_of_vert_begin;
+ iter->step = edge_of_vert_step;
+ iter->vdata = data;
+ break;
+ case BM_FACES_OF_VERT:
+ if (!data)
+ return NULL;
+
+ iter->begin = face_of_vert_begin;
+ iter->step = face_of_vert_step;
+ iter->vdata = data;
+ break;
+ case BM_LOOPS_OF_VERT:
+ if (!data)
+ return NULL;
+
+ iter->begin = loop_of_vert_begin;
+ iter->step = loop_of_vert_step;
+ iter->vdata = data;
+ break;
+ case BM_FACES_OF_EDGE:
+ if (!data)
+ return NULL;
+
+ iter->begin = face_of_edge_begin;
+ iter->step = face_of_edge_step;
+ iter->edata = data;
+ break;
+ case BM_VERTS_OF_FACE:
+ if (!data)
+ return NULL;
+
+ iter->begin = vert_of_face_begin;
+ iter->step = vert_of_face_step;
+ iter->pdata = data;
+ break;
+ case BM_EDGES_OF_FACE:
+ if (!data)
+ return NULL;
+
+ iter->begin = edge_of_face_begin;
+ iter->step = edge_of_face_step;
+ iter->pdata = data;
+ break;
+ case BM_LOOPS_OF_FACE:
+ if (!data)
+ return NULL;
+
+ iter->begin = loop_of_face_begin;
+ iter->step = loop_of_face_step;
+ iter->pdata = data;
+ break;
+ case BM_LOOPS_OF_LOOP:
+ if (!data)
+ return NULL;
+
+ iter->begin = loops_of_loop_begin;
+ iter->step = loops_of_loop_step;
+ iter->ldata = data;
+ break;
+ case BM_LOOPS_OF_EDGE:
+ if (!data)
+ return NULL;
+
+ iter->begin = loops_of_edge_begin;
+ iter->step = loops_of_edge_step;
+ iter->edata = data;
+ break;
+ default:
+ break;
+ }
+
+ iter->begin(iter);
+ return BMIter_Step(iter);
+}
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
new file mode 100644
index 00000000000..463cd635696
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -0,0 +1,709 @@
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_array.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include <string.h>
+
+/*
+ * BM_MARK.C
+ *
+ * Selection routines for bmesh structures.
+ * This is actually all old code ripped from
+ * editmesh_lib.c and slightly modified to work
+ * for bmesh's. This also means that it has some
+ * of the same problems.... something that
+ * that should be addressed eventually.
+ *
+*/
+
+
+/*
+ * BMESH SELECTMODE FLUSH
+ *
+ * Makes sure to flush selections
+ * 'upwards' (ie: all verts of an edge
+ * selects the edge and so on). This
+ * should only be called by system and not
+ * tool authors.
+ *
+*/
+
+static void recount_totsels(BMesh *bm)
+{
+ BMIter iter;
+ BMHeader *ele;
+ int types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
+ int *tots[3];
+ int i;
+
+ /*recount tot*sel variables*/
+ bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
+ tots[0] = &bm->totvertsel;
+ tots[1] = &bm->totedgesel;
+ tots[2] = &bm->totfacesel;
+
+ for (i=0; i<3; i++) {
+ ele = BMIter_New(&iter, bm, types[i], NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(ele, BM_SELECT)) *tots[i] += 1;
+ }
+ }
+}
+
+void BM_SelectMode_Flush(BMesh *bm)
+{
+ BMEdge *e;
+ BMLoop *l;
+ BMFace *f;
+
+ BMIter edges;
+ BMIter faces;
+
+ int totsel;
+
+ if(bm->selectmode & SCE_SELECT_VERTEX) {
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges)) {
+ if(BM_TestHFlag(e->v1, BM_SELECT) && BM_TestHFlag(e->v2, BM_SELECT)) BM_SetHFlag(e, BM_SELECT);
+ else BM_ClearHFlag(e, BM_SELECT);
+ }
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)) {
+ totsel = 0;
+ l=(BMLoop*) bm_firstfaceloop(f);
+ do{
+ if(BM_TestHFlag(l->v, BM_SELECT))
+ totsel++;
+ l = ((BMLoop*)(l->next));
+ } while(l != bm_firstfaceloop(f));
+
+ if(totsel == f->len)
+ BM_SetHFlag(f, BM_SELECT);
+ else
+ BM_ClearHFlag(f, BM_SELECT);
+ }
+ }
+ else if(bm->selectmode & SCE_SELECT_EDGE) {
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)) {
+ totsel = 0;
+ l=(BMLoop*) bm_firstfaceloop(f);
+ do{
+ if(bmesh_test_sysflag(&(l->e->head), BM_SELECT))
+ totsel++;
+ l = ((BMLoop*)(l->next));
+ }while(l!=bm_firstfaceloop(f));
+
+ if(totsel == f->len)
+ BM_SetHFlag(f, BM_SELECT);
+ else
+ BM_ClearHFlag(f, BM_SELECT);
+ }
+ }
+
+ recount_totsels(bm);
+}
+
+/*
+ * BMESH SELECT VERT
+ *
+ * Changes selection state of a single vertex
+ * in a mesh
+ *
+*/
+
+void BM_Select_Vert(BMesh *bm, BMVert *v, int select)
+{
+ BMIter iter;
+ BMEdge *e;
+
+ if(select) {
+ if (!BM_TestHFlag(v, BM_SELECT)) bm->totvertsel += 1;
+ BM_SetHFlag(v, BM_SELECT);
+ } else {
+ if (BM_TestHFlag(v, BM_SELECT)) bm->totvertsel -= 1;
+ BM_ClearHFlag(v, BM_SELECT);
+ }
+}
+
+/*
+ * BMESH SELECT EDGE
+ *
+ * Changes selection state of a single edge
+ * in a mesh. Note that this may not be
+ * 100 percent reliable.
+ *
+*/
+
+void BM_Select_Edge(BMesh *bm, BMEdge *e, int select)
+{
+ int candesel;
+ int testiso = 1;
+
+ /*I might move this logic to editors/mesh/bmesh_select.c, where it'd be invoked
+ by the selection tools. in that case, we'd still retain the checks
+ for if an edge's verts can be deselected.*/
+
+ /*ensure vert selections are valid, only if not in a multiselect
+ mode that shares SCE_SELECT_VERT*/
+ switch (bm->selectmode) {
+ case SCE_SELECT_VERTEX:
+ case SCE_SELECT_EDGE:
+ case SCE_SELECT_FACE:
+ case SCE_SELECT_EDGE|SCE_SELECT_FACE:
+ testiso = 1;
+ break;
+ default:
+ testiso = 0;
+ break;
+ }
+
+ if (testiso && !select) {
+ BMIter eiter;
+ BMEdge *e2;
+ int i;
+
+ for (i=0; i<2; i++) {
+ candesel = 1;
+ e2 = BMIter_New(&eiter, bm, BM_EDGES_OF_VERT, !i?e->v1:e->v2);
+ for (; e2; e2=BMIter_Step(&eiter)) {
+ if (e2 == e) continue;
+ if (BM_TestHFlag(e2, BM_SELECT)) {
+ candesel = 0;
+ break;
+ }
+ }
+
+ if (candesel) BM_Select_Vert(bm, !i?e->v1:e->v2, 0);
+ }
+ }
+
+ if(select) {
+ if (!BM_TestHFlag(e, BM_SELECT)) bm->totedgesel += 1;
+
+ BM_SetHFlag(&(e->head), BM_SELECT);
+ BM_Select(bm, e->v1, 1);
+ BM_Select(bm, e->v2, 1);
+ }
+ else{
+ if (BM_TestHFlag(e, BM_SELECT)) bm->totedgesel -= 1;
+
+ BM_ClearHFlag(&(e->head), BM_SELECT);
+ }
+}
+
+/*
+ *
+ * BMESH SELECT FACE
+ *
+ * Changes selection state of a single
+ * face in a mesh. This (might) suffer
+ * from same problems as edge select
+ * code...
+ *
+*/
+
+void BM_Select_Face(BMesh *bm, BMFace *f, int select)
+{
+ BMLoop *l;
+
+ if(select){
+ if (!BM_TestHFlag(f, BM_SELECT)) bm->totfacesel += 1;
+
+ BM_SetHFlag(&(f->head), BM_SELECT);
+ l=(BMLoop*) bm_firstfaceloop(f);
+ do{
+ BM_Select_Vert(bm, l->v, 1);
+ BM_Select_Edge(bm, l->e, 1);
+ l = ((BMLoop*)(l->next));
+ }while(l != bm_firstfaceloop(f));
+ }
+ else{
+ BMIter liter, fiter, eiter;
+ BMFace *f2;
+ BMLoop *l;
+ BMEdge *e;
+
+ if (BM_TestHFlag(f, BM_SELECT)) bm->totfacesel -= 1;
+ BM_ClearHFlag(&(f->head), BM_SELECT);
+
+ /*flush down to edges*/
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ BM_ITER(f2, &fiter, bm, BM_FACES_OF_EDGE, l->e) {
+ if (BM_TestHFlag(f2, BM_SELECT))
+ break;
+ }
+
+ if (!f2) {
+ BM_Select(bm, l->e, 0);
+ }
+ }
+
+ /*flush down to verts*/
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, l->v) {
+ if (BM_TestHFlag(e, BM_SELECT))
+ break;
+ }
+
+ if (!e) {
+ BM_Select(bm, l->v, 0);
+ }
+ }
+ }
+}
+
+/*
+ * BMESH SELECTMODE SET
+ *
+ * Sets the selection mode for the bmesh
+ *
+*/
+
+void BM_Selectmode_Set(BMesh *bm, int selectmode)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ bm->selectmode = selectmode;
+
+ if(bm->selectmode & SCE_SELECT_VERTEX) {
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges))
+ BM_ClearHFlag(e, 0);
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces))
+ BM_ClearHFlag(f, 0);
+ BM_SelectMode_Flush(bm);
+ }
+ else if(bm->selectmode & SCE_SELECT_EDGE) {
+ for(v= BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm ); v; v= BMIter_Step(&verts))
+ BM_ClearHFlag(v, 0);
+ for(e= BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges)){
+ if(BM_TestHFlag(&(e->head), BM_SELECT))
+ BM_Select_Edge(bm, e, 1);
+ }
+ BM_SelectMode_Flush(bm);
+ }
+ else if(bm->selectmode & SCE_SELECT_FACE) {
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges))
+ BM_ClearHFlag(e, 0);
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)){
+ if(BM_TestHFlag(&(f->head), BM_SELECT))
+ BM_Select_Face(bm, f, 1);
+ }
+ BM_SelectMode_Flush(bm);
+ }
+}
+
+
+int BM_CountFlag(struct BMesh *bm, int type, int flag, int respecthide)
+{
+ BMHeader *head;
+ BMIter iter;
+ int tot = 0;
+
+ if (type & BM_VERT) {
+ for (head = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); head; head=BMIter_Step(&iter)) {
+ if (respecthide && BM_TestHFlag(head, BM_HIDDEN)) continue;
+ if (head->flag & flag) tot++;
+ }
+ }
+ if (type & BM_EDGE) {
+ for (head = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); head; head=BMIter_Step(&iter)) {
+ if (respecthide && BM_TestHFlag(head, BM_HIDDEN)) continue;
+ if (head->flag & flag) tot++;
+ }
+ }
+ if (type & BM_FACE) {
+ for (head = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); head; head=BMIter_Step(&iter)) {
+ if (respecthide && BM_TestHFlag(head, BM_HIDDEN)) continue;
+ if (head->flag & flag) tot++;
+ }
+ }
+
+ return tot;
+}
+
+/*note: by design, this will not touch the editselection history stuff*/
+void BM_Select(struct BMesh *bm, void *element, int select)
+{
+ BMHeader *head = element;
+
+ if(head->type == BM_VERT) BM_Select_Vert(bm, (BMVert*)element, select);
+ else if(head->type == BM_EDGE) BM_Select_Edge(bm, (BMEdge*)element, select);
+ else if(head->type == BM_FACE) BM_Select_Face(bm, (BMFace*)element, select);
+}
+
+int BM_Selected(BMesh *bm, void *element)
+{
+ BMHeader *head = element;
+ return BM_TestHFlag(head, BM_SELECT);
+}
+
+
+/* generic way to get data from an EditSelection type
+These functions were written to be used by the Modifier widget when in Rotate about active mode,
+but can be used anywhere.
+EM_editselection_center
+EM_editselection_normal
+EM_editselection_plane
+*/
+void BM_editselection_center(BMesh *em, float *center, BMEditSelection *ese)
+{
+ if (ese->type==BM_VERT) {
+ BMVert *eve= ese->data;
+ copy_v3_v3(center, eve->co);
+ } else if (ese->type==BM_EDGE) {
+ BMEdge *eed= ese->data;
+ add_v3_v3v3(center, eed->v1->co, eed->v2->co);
+ mul_v3_fl(center, 0.5);
+ } else if (ese->type==BM_FACE) {
+ BMFace *efa= ese->data;
+ BM_Compute_Face_Center(em, efa, center);
+ }
+}
+
+void BM_editselection_normal(float *normal, BMEditSelection *ese)
+{
+ if (ese->type==BM_VERT) {
+ BMVert *eve= ese->data;
+ copy_v3_v3(normal, eve->no);
+ } else if (ese->type==BM_EDGE) {
+ BMEdge *eed= ese->data;
+ float plane[3]; /* need a plane to correct the normal */
+ float vec[3]; /* temp vec storage */
+
+ add_v3_v3v3(normal, eed->v1->no, eed->v2->no);
+ sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
+
+ /* the 2 vertex normals will be close but not at rightangles to the edge
+ for rotate about edge we want them to be at right angles, so we need to
+ do some extra colculation to correct the vert normals,
+ we need the plane for this */
+ cross_v3_v3v3(vec, normal, plane);
+ cross_v3_v3v3(normal, plane, vec);
+ normalize_v3(normal);
+
+ } else if (ese->type==BM_FACE) {
+ BMFace *efa= ese->data;
+ copy_v3_v3(normal, efa->no);
+ }
+}
+
+/* Calculate a plane that is rightangles to the edge/vert/faces normal
+also make the plane run allong an axis that is related to the geometry,
+because this is used for the manipulators Y axis.*/
+void BM_editselection_plane(BMesh *em, float *plane, BMEditSelection *ese)
+{
+ if (ese->type==BM_VERT) {
+ BMVert *eve= ese->data;
+ float vec[3]={0,0,0};
+
+ if (ese->prev) { /*use previously selected data to make a usefull vertex plane */
+ BM_editselection_center(em, vec, ese->prev);
+ sub_v3_v3v3(plane, vec, eve->co);
+ } else {
+ /* make a fake plane thats at rightangles to the normal
+ we cant make a crossvec from a vec thats the same as the vec
+ unlikely but possible, so make sure if the normal is (0,0,1)
+ that vec isnt the same or in the same direction even.*/
+ if (eve->no[0]<0.5) vec[0]=1;
+ else if (eve->no[1]<0.5) vec[1]=1;
+ else vec[2]=1;
+ cross_v3_v3v3(plane, eve->no, vec);
+ }
+ } else if (ese->type==BM_EDGE) {
+ BMEdge *eed= ese->data;
+
+ /*the plane is simple, it runs allong the edge
+ however selecting different edges can swap the direction of the y axis.
+ this makes it less likely for the y axis of the manipulator
+ (running along the edge).. to flip less often.
+ at least its more pradictable */
+ if (eed->v2->co[1] > eed->v1->co[1]) /*check which to do first */
+ sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
+ else
+ sub_v3_v3v3(plane, eed->v1->co, eed->v2->co);
+
+ } else if (ese->type==BM_FACE) {
+ BMFace *efa= ese->data;
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+
+ /*for now, use face normal*/
+
+ /* make a fake plane thats at rightangles to the normal
+ we cant make a crossvec from a vec thats the same as the vec
+ unlikely but possible, so make sure if the normal is (0,0,1)
+ that vec isnt the same or in the same direction even.*/
+ if (efa->no[0]<0.5) vec[0]=1.0f;
+ else if (efa->no[1]<0.5) vec[1]=1.0f;
+ else vec[2]=1.0f;
+ cross_v3_v3v3(plane, efa->no, vec);
+#if 0 //BMESH_TODO
+
+ if (efa->v4) { /*if its a quad- set the plane along the 2 longest edges.*/
+ float vecA[3], vecB[3];
+ sub_v3_v3v3(vecA, efa->v4->co, efa->v3->co);
+ sub_v3_v3v3(vecB, efa->v1->co, efa->v2->co);
+ add_v3_v3v3(plane, vecA, vecB);
+
+ sub_v3_v3v3(vecA, efa->v1->co, efa->v4->co);
+ sub_v3_v3v3(vecB, efa->v2->co, efa->v3->co);
+ add_v3_v3v3(vec, vecA, vecB);
+ /*use the biggest edge length*/
+ if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
+ copy_v3_v3(plane, vec);
+ } else {
+ /*start with v1-2 */
+ sub_v3_v3v3(plane, efa->v1->co, efa->v2->co);
+
+ /*test the edge between v2-3, use if longer */
+ sub_v3_v3v3(vec, efa->v2->co, efa->v3->co);
+ if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
+ copy_v3_v3(plane, vec);
+
+ /*test the edge between v1-3, use if longer */
+ sub_v3_v3v3(vec, efa->v3->co, efa->v1->co);
+ if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
+ copy_v3_v3(plane, vec);
+ }
+#endif
+ }
+ normalize_v3(plane);
+}
+
+static int BM_check_selection(BMesh *em, void *data)
+{
+ BMEditSelection *ese;
+
+ for(ese = em->selected.first; ese; ese = ese->next){
+ if(ese->data == data) return 1;
+ }
+
+ return 0;
+}
+
+void BM_remove_selection(BMesh *em, void *data)
+{
+ BMEditSelection *ese;
+ for(ese=em->selected.first; ese; ese = ese->next){
+ if(ese->data == data){
+ BLI_freelinkN(&(em->selected),ese);
+ break;
+ }
+ }
+}
+
+void BM_clear_selection_history(BMesh *em)
+{
+ BLI_freelistN(&em->selected);
+ em->selected.first = em->selected.last = NULL;
+}
+
+void BM_store_selection(BMesh *em, void *data)
+{
+ BMEditSelection *ese;
+ if(!BM_check_selection(em, data)){
+ ese = (BMEditSelection*) MEM_callocN( sizeof(BMEditSelection), "BMEdit Selection");
+ ese->type = ((BMHeader*)data)->type;
+ ese->data = data;
+ BLI_addtail(&(em->selected),ese);
+ }
+}
+
+void BM_validate_selections(BMesh *em)
+{
+ BMEditSelection *ese, *nextese;
+
+ ese = em->selected.first;
+
+ while(ese){
+ nextese = ese->next;
+ if (!BM_TestHFlag(ese->data, BM_SELECT)) BLI_freelinkN(&(em->selected), ese);
+ ese = nextese;
+ }
+}
+
+void BM_clear_flag_all(BMesh *bm, int flag)
+{
+ BMIter iter;
+ BMHeader *ele;
+ int i, type;
+
+ if (flag & BM_SELECT)
+ BM_clear_selection_history(bm);
+
+ for (i=0; i<3; i++) {
+ switch (i) {
+ case 0:
+ type = BM_VERTS_OF_MESH;
+ break;
+ case 1:
+ type = BM_EDGES_OF_MESH;
+ break;
+ case 2:
+ type = BM_FACES_OF_MESH;
+ break;
+ }
+
+ ele = BMIter_New(&iter, bm, type, NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ if (flag & BM_SELECT) BM_Select(bm, ele, 0);
+ BM_ClearHFlag(ele, flag);
+ }
+ }
+}
+
+
+/***************** Pinning **************/
+
+#define SETPIN(ele) pin ? BM_SetHFlag(ele, BM_PINNED) : BM_ClearHFlag(ele, BM_PINNED);
+
+
+void BM_Pin_Vert(BMesh *bm, BMVert *v, int pin)
+{
+ SETPIN(v);
+}
+
+void BM_Pin_Edge(BMesh *bm, BMEdge *e, int pin)
+{
+ SETPIN(e->v1);
+ SETPIN(e->v2);
+}
+
+void BM_Pin_Face(BMesh *bm, BMFace *f, int pin)
+{
+ BMIter vfiter;
+ BMVert *vf;
+
+ BM_ITER(vf, &vfiter, bm, BM_VERTS_OF_FACE, f) {
+ SETPIN(vf);
+ }
+}
+
+void BM_Pin(BMesh *bm, void *element, int pin)
+{
+ BMHeader *h = element;
+
+ switch (h->type) {
+ case BM_VERT:
+ BM_Pin_Vert(bm, element, pin);
+ break;
+ case BM_EDGE:
+ BM_Pin_Edge(bm, element, pin);
+ break;
+ case BM_FACE:
+ BM_Pin_Face(bm, element, pin);
+ break;
+ }
+}
+
+
+
+/***************** Mesh Hiding stuff *************/
+
+#define SETHIDE(ele) hide ? BM_SetHFlag(ele, BM_HIDDEN) : BM_ClearHFlag(ele, BM_HIDDEN);
+
+static void vert_flush_hide(BMesh *bm, BMVert *v) {
+ BMIter iter;
+ BMEdge *e;
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
+ if (!BM_TestHFlag(e, BM_HIDDEN))
+ return;
+ }
+
+ BM_SetHFlag(v, BM_HIDDEN);
+}
+
+static void edge_flush_hide(BMesh *bm, BMEdge *e) {
+ BMIter iter;
+ BMFace *f;
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_EDGE, e) {
+ if (!BM_TestHFlag(f, BM_HIDDEN))
+ return;
+ }
+
+ BM_SetHFlag(e, BM_HIDDEN);
+}
+
+void BM_Hide_Vert(BMesh *bm, BMVert *v, int hide)
+{
+ /*vert hiding: vert + surrounding edges and faces*/
+ BMIter iter, fiter;
+ BMEdge *e;
+ BMFace *f;
+
+ SETHIDE(v);
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
+ SETHIDE(e);
+
+ BM_ITER(f, &fiter, bm, BM_FACES_OF_EDGE, e) {
+ SETHIDE(f);
+ }
+ }
+}
+
+void BM_Hide_Edge(BMesh *bm, BMEdge *e, int hide)
+{
+ BMIter iter;
+ BMFace *f;
+ BMVert *v;
+
+ /*edge hiding: faces around the edge*/
+ BM_ITER(f, &iter, bm, BM_FACES_OF_EDGE, e) {
+ SETHIDE(f);
+ }
+
+ SETHIDE(e);
+
+ /*hide vertices if necassary*/
+ vert_flush_hide(bm, e->v1);
+ vert_flush_hide(bm, e->v2);
+}
+
+void BM_Hide_Face(BMesh *bm, BMFace *f, int hide)
+{
+ BMIter iter;
+ BMLoop *l;
+
+ /**/
+ SETHIDE(f);
+
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
+ edge_flush_hide(bm, l->e);
+ }
+
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
+ vert_flush_hide(bm, l->v);
+ }
+}
+
+void BM_Hide(BMesh *bm, void *element, int hide)
+{
+ BMHeader *h = element;
+
+ switch (h->type) {
+ case BM_VERT:
+ BM_Hide_Vert(bm, element, hide);
+ break;
+ case BM_EDGE:
+ BM_Hide_Edge(bm, element, hide);
+ break;
+ case BM_FACE:
+ BM_Hide_Face(bm, element, hide);
+ break;
+ }
+}
+
+
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
new file mode 100644
index 00000000000..22e68f30ae1
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -0,0 +1,302 @@
+/**
+ * BME_mesh.c jan 2007
+ *
+ * BM mesh level functions.
+ *
+ * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** 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.
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+#include "DNA_listBase.h"
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BKE_utildefines.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+void BME_error(void);
+
+/*bmesh_error stub*/
+void bmesh_error(void)
+{
+ printf("BM modelling error!");
+}
+
+/*
+ * BMESH SET SYSFLAG
+ *
+ * Sets a bitflag for a given element.
+ *
+*/
+
+void bmesh_set_sysflag(BMHeader *head, int flag)
+{
+ head->flag |= flag;
+}
+
+/*
+ * BMESH CLEAR SYSFLAG
+ *
+ * Clears a bitflag for a given element.
+ *
+*/
+
+void bmesh_clear_sysflag(BMHeader *head, int flag)
+{
+ head->flag &= ~flag;
+}
+
+
+/*
+ * BMESH TEST SYSFLAG
+ *
+ * Tests whether a bitflag is set for a given element.
+ *
+*/
+
+int bmesh_test_sysflag(BMHeader *head, int flag)
+{
+ if(head->flag & flag)
+ return 1;
+ return 0;
+}
+
+/*
+ * BMESH MAKE MESH
+ *
+ * Allocates a new BMesh structure.
+ * Returns -
+ * Pointer to a BM
+ *
+*/
+
+BMesh *BM_Make_Mesh(int allocsize[4])
+{
+ /*allocate the structure*/
+ BMesh *bm = MEM_callocN(sizeof(BMesh),"BM");
+ int vsize, esize, lsize, fsize, lstsize;
+ int baselevel = LAYER_ADJ;
+
+ if (baselevel == LAYER_BASE) {
+ vsize = sizeof(BMBaseVert);
+ esize = sizeof(BMBaseEdge);
+ lsize = sizeof(BMBaseLoop);
+ fsize = sizeof(BMBaseFace);
+ lstsize = sizeof(BMBaseLoopList);
+ } else {
+ vsize = sizeof(BMVert);
+ esize = sizeof(BMEdge);
+ lsize = sizeof(BMLoop);
+ fsize = sizeof(BMFace);
+ lstsize = sizeof(BMLoopList);
+ }
+
+ bm->baselevel = baselevel;
+
+/*allocate the memory pools for the mesh elements*/
+ bm->vpool = BLI_mempool_create(vsize, allocsize[0], allocsize[0], 0, 1);
+ bm->epool = BLI_mempool_create(esize, allocsize[1], allocsize[1], 0, 1);
+ bm->lpool = BLI_mempool_create(lsize, allocsize[2], allocsize[2], 0, 0);
+ bm->looplistpool = BLI_mempool_create(lstsize, allocsize[3], allocsize[3], 0, 0);
+ bm->fpool = BLI_mempool_create(fsize, allocsize[3], allocsize[3], 0, 1);
+
+ /*allocate one flag pool that we dont get rid of.*/
+ bm->toolflagpool = BLI_mempool_create(sizeof(BMFlagLayer), 512, 512, 0, 0);
+ bm->stackdepth = 1;
+ bm->totflags = 1;
+
+ return bm;
+}
+
+/*
+ * BMESH FREE MESH
+ *
+ * Frees a BMesh structure.
+*/
+
+void BM_Free_Mesh_Data(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMLoop *l;
+ BMFace *f;
+
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+ BMIter loops;
+
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm ); v; v = BMIter_Step(&verts)) CustomData_bmesh_free_block( &(bm->vdata), &(v->head.data) );
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e = BMIter_Step(&edges)) CustomData_bmesh_free_block( &(bm->edata), &(e->head.data) );
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f = BMIter_Step(&faces)){
+ CustomData_bmesh_free_block( &(bm->pdata), &(f->head.data) );
+ for(l = BMIter_New(&loops, bm, BM_LOOPS_OF_FACE, f ); l; l = BMIter_Step(&loops)) CustomData_bmesh_free_block( &(bm->ldata), &(l->head.data) );
+ }
+
+ /*Free custom data pools, This should probably go in CustomData_free?*/
+ if(bm->vdata.totlayer) BLI_mempool_destroy(bm->vdata.pool);
+ if(bm->edata.totlayer) BLI_mempool_destroy(bm->edata.pool);
+ if(bm->ldata.totlayer) BLI_mempool_destroy(bm->ldata.pool);
+ if(bm->pdata.totlayer) BLI_mempool_destroy(bm->pdata.pool);
+
+ /*free custom data*/
+ CustomData_free(&bm->vdata,0);
+ CustomData_free(&bm->edata,0);
+ CustomData_free(&bm->ldata,0);
+ CustomData_free(&bm->pdata,0);
+
+ /*destroy element pools*/
+ BLI_mempool_destroy(bm->vpool);
+ BLI_mempool_destroy(bm->epool);
+ BLI_mempool_destroy(bm->lpool);
+ BLI_mempool_destroy(bm->fpool);
+
+ if (bm->svpool)
+ BLI_mempool_destroy(bm->svpool);
+ if (bm->sepool)
+ BLI_mempool_destroy(bm->sepool);
+ if (bm->slpool)
+ BLI_mempool_destroy(bm->slpool);
+ if (bm->sfpool)
+ BLI_mempool_destroy(bm->sfpool);
+
+ /*destroy flag pool*/
+ BLI_mempool_destroy(bm->toolflagpool);
+ BLI_mempool_destroy(bm->looplistpool);
+
+ BLI_freelistN(&bm->selected);
+
+ BMO_ClearStack(bm);
+}
+
+void BM_Free_Mesh(BMesh *bm)
+{
+ BM_Free_Mesh_Data(bm);
+ MEM_freeN(bm);
+}
+
+/*
+ * BMESH COMPUTE NORMALS
+ *
+ * Updates the normals of a mesh.
+ * Note that this can only be called
+ *
+*/
+
+void BM_Compute_Normals(BMesh *bm)
+{
+ BMVert *v;
+ BMFace *f;
+ BMLoop *l;
+ BMIter verts;
+ BMIter faces;
+ BMIter loops;
+ unsigned int maxlength = 0, i;
+ float (*projectverts)[3];
+
+ /*first, find out the largest face in mesh*/
+ BM_ITER(f, &faces, bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_TestHFlag(f, BM_HIDDEN))
+ continue;
+
+ if(f->len > maxlength) maxlength = f->len;
+ }
+
+ /*make sure we actually have something to do*/
+ if(maxlength < 3) return;
+
+ /*allocate projectverts array*/
+ projectverts = MEM_callocN(sizeof(float) * maxlength * 3, "BM normal computation array");
+
+ /*calculate all face normals*/
+ BM_ITER(f, &faces, bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_TestHFlag(f, BM_HIDDEN))
+ continue;
+ if (f->head.flag & BM_NONORMCALC)
+ continue;
+
+ bmesh_update_face_normal(bm, f, projectverts);
+ }
+
+ /*Zero out vertex normals*/
+ BM_ITER(v, &verts, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(v, BM_HIDDEN))
+ continue;
+
+ v->no[0] = v->no[1] = v->no[2] = 0.0;
+ }
+
+ /*add face normals to vertices*/
+ i = 0;
+ BM_ITER(f, &faces, bm, BM_FACES_OF_MESH, NULL) {
+ i += 1;
+
+ if (BM_TestHFlag(f, BM_HIDDEN))
+ continue;
+
+ for(l = BMIter_New(&loops, bm, BM_LOOPS_OF_FACE, f ); l; l = BMIter_Step(&loops))
+ add_v3_v3v3(l->v->no, l->v->no, f->no);
+ }
+
+ /*average the vertex normals*/
+ BM_ITER(v, &verts, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(v, BM_HIDDEN))
+ continue;
+
+ if (normalize_v3(v->no)==0.0) {
+ copy_v3_v3(v->no, v->co);
+ normalize_v3(v->no);
+ }
+ }
+
+ MEM_freeN(projectverts);
+}
+
+/*
+ * BMESH BEGIN/END EDIT
+ *
+ * Functions for setting up a mesh for editing and cleaning up after
+ * the editing operations are done. These are called by the tools/operator
+ * API for each time a tool is executed.
+ *
+ * Returns -
+ * Nothing
+ *
+*/
+
+void bmesh_begin_edit(BMesh *bm){
+}
+
+void bmesh_end_edit(BMesh *bm, int flag){
+ /*compute normals, clear temp flags and flush selections*/
+ BM_Compute_Normals(bm);
+ BM_SelectMode_Flush(bm);
+}
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
new file mode 100644
index 00000000000..5c662614117
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -0,0 +1,569 @@
+#include <limits.h>
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "BKE_utildefines.h"
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+#include "BLI_ghash.h"
+#include "BLI_math.h"
+#include "BLI_array.h"
+#include "BLI_utildefines.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * BME_MODS.C
+ *
+ * This file contains functions for locally modifying
+ * the topology of existing mesh data. (split, join, flip ect).
+ *
+*/
+
+/**
+ * bmesh_dissolve_disk
+ *
+ * Turns the face region surrounding a manifold vertex into
+ * A single polygon.
+ *
+ *
+ * Example:
+ *
+ * |=========| |=========|
+ * | \ / | | |
+ * Before: | V | After: | |
+ * | / \ | | |
+ * |=========| |=========|
+ *
+ *
+ */
+#if 1
+int BM_Dissolve_Vert(BMesh *bm, BMVert *v) {
+ BMIter iter;
+ BMEdge *e;
+ int len=0;
+
+ if (!v) return 0;
+
+ e = BMIter_New(&iter, bm, BM_EDGES_OF_VERT, v);
+ for (; e; e=BMIter_Step(&iter)) {
+ len++;
+ }
+
+ if (len == 1) {
+ BM_Kill_Edge(bm, v->e);
+ BM_Kill_Vert(bm, v);
+ return 1;
+ }
+
+ if(BM_Nonmanifold_Vert(bm, v)) {
+ if (!v->e) BM_Kill_Vert(bm, v);
+ else if (!v->e->l) {
+ BM_Kill_Edge(bm, v->e);
+ BM_Kill_Vert(bm, v);
+ } else return 0;
+
+ return 1;
+ }
+
+ return BM_Dissolve_Disk(bm, v);
+}
+
+int BM_Dissolve_Disk(BMesh *bm, BMVert *v) {
+ BMFace *f, *f2;
+ BMEdge *e, *keepedge=NULL, *baseedge=NULL;
+ BMLoop *loop;
+ int done, len;
+
+ if(BM_Nonmanifold_Vert(bm, v)) {
+ return 0;
+ }
+
+ if(v->e){
+ /*v->e we keep, what else?*/
+ e = v->e;
+ len = 0;
+ do{
+ e = bmesh_disk_nextedge(e,v);
+ if(!(BM_Edge_Share_Faces(e, v->e))){
+ keepedge = e;
+ baseedge = v->e;
+ break;
+ }
+ len++;
+ }while(e != v->e);
+ }
+
+ /*this code for handling 2 and 3-valence verts
+ may be totally bad.*/
+ if (keepedge == NULL && len == 3) {
+ /*handle specific case for three-valence. solve it by
+ increasing valence to four. this may be hackish. . .*/
+ loop = e->l;
+ if (loop->v == v) loop = (BMLoop*) loop->next;
+ if (!BM_Split_Face(bm, loop->f, v, loop->v, NULL, NULL))
+ return 0;
+
+ BM_Dissolve_Disk(bm, v);
+ return 1;
+ } else if (keepedge == NULL && len == 2) {
+ /*handle two-valence*/
+ f = v->e->l->f;
+ f2 = ((BMLoop*)v->e->l->radial_next)->f;
+
+ /*collapse the vertex*/
+ BM_Collapse_Vert(bm, v->e, v, 1.0);
+
+ if (f != f2 && !BM_Join_TwoFaces(bm, f, f2, NULL))
+ return 0;
+
+ return 1;
+ }
+
+ if(keepedge){
+ done = 0;
+ while(!done){
+ done = 1;
+ e = v->e;
+ do{
+ f = NULL;
+ len = bmesh_radial_length(e->l);
+ if(len == 2 && (e!=baseedge) && (e!=keepedge)) {
+ f = BM_Join_TwoFaces(bm, e->l->f, ((BMLoop*)(e->l->radial_next))->f, e);
+ /*return if couldn't join faces in manifold
+ conditions.*/
+ //!disabled for testing why bad things happen
+ if (!f) return 0;
+ }
+
+ if(f){
+ done = 0;
+ break;
+ }
+ e = bmesh_disk_nextedge(e, v);
+ }while(e != v->e);
+ }
+
+ /*get remaining two faces*/
+ f = v->e->l->f;
+ f2 = ((BMLoop*)v->e->l->radial_next)->f;
+
+ /*collapse the vertex*/
+ BM_Collapse_Vert(bm, baseedge, v, 1.0);
+
+ if (f != f2) {
+ /*join two remaining faces*/
+ if (!BM_Join_TwoFaces(bm, f, f2, NULL)) return 0;
+ }
+ }
+
+ return 1;
+}
+#else
+void BM_Dissolve_Disk(BMesh *bm, BMVert *v){
+ BMFace *f;
+ BMEdge *e;
+ BMIter iter;
+ int done, len;
+
+ if(v->e){
+ done = 0;
+ while(!done){
+ done = 1;
+
+ /*loop the edges looking for an edge to dissolve*/
+ for (e=BMIter_New(&iter, bm, BM_EDGES_OF_VERT, v); e;
+ e = BMIter_Step(&iter)) {
+ f = NULL;
+ len = bmesh_cycle_length(&(e->l->radial));
+ if(len == 2){
+ f = BM_Join_TwoFaces(bm,e->l->f,((BMLoop*)
+ (e->l->radial_next))->f,
+ e);
+ }
+ if(f){
+ done = 0;
+ break;
+ }
+ };
+ }
+ BM_Collapse_Vert(bm, v->e, v, 1.0);
+ }
+}
+#endif
+
+/**
+ * bmesh_join_faces
+ *
+ * joins two adjacenct faces togather.
+ *
+ * Returns -
+ * BMFace pointer
+ */
+
+BMFace *BM_Join_TwoFaces(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e) {
+
+ BMLoop *l1, *l2;
+ BMEdge *jed=NULL;
+ BMFace *faces[2] = {f1, f2};
+
+ jed = e;
+ if(!jed){
+ /*search for an edge that has both these faces in its radial cycle*/
+ l1 = bm_firstfaceloop(f1);
+ do{
+ if( ((BMLoop*)l1->radial_next)->f == f2 ){
+ jed = l1->e;
+ break;
+ }
+ l1 = ((BMLoop*)(l1->next));
+ }while(l1!=bm_firstfaceloop(f1));
+ }
+
+ if (!jed) {
+ bmesh_error();
+ return NULL;
+ }
+
+ l1 = jed->l;
+
+ if (!l1) {
+ bmesh_error();
+ return NULL;
+ }
+
+ l2 = l1->radial_next;
+ if (l1->v == l2->v) {
+ bmesh_loop_reverse(bm, f2);
+ }
+
+ f1 = BM_Join_Faces(bm, faces, 2);
+
+ return f1;
+}
+
+/*connects two verts together, automatically (if very naively) finding the
+ face they both share (if there is one) and splittling it. use this at your
+ own risk, as it doesn't handle the many complex cases it should (like zero-area faces,
+ multiple faces, etc).
+
+ this is really only meant for cases where you don't know before hand the face
+ the two verts belong to for splitting (e.g. the subdivision operator).
+*/
+
+BMEdge *BM_Connect_Verts(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf) {
+ BMIter iter, iter2;
+ BMVert *v;
+ BMLoop *nl;
+ BMFace *face;
+
+ /*this isn't the best thing in the world. it doesn't handle cases where there's
+ multiple faces yet. that might require a convexity test to figure out which
+ face is "best," and who knows what for non-manifold conditions.*/
+ for (face = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v1); face; face=BMIter_Step(&iter)) {
+ for (v=BMIter_New(&iter2, bm, BM_VERTS_OF_FACE, face); v; v=BMIter_Step(&iter2)) {
+ if (v == v2) {
+ face = BM_Split_Face(bm, face, v1, v2, &nl, NULL);
+
+ if (nf) *nf = face;
+ return nl->e;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * BM_split_face
+ *
+ * Splits a single face into two.
+ *
+ * Returns -
+ * BMFace pointer
+ */
+
+BMFace *BM_Split_Face(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **nl, BMEdge *example)
+{
+ BMFace *nf;
+ nf = bmesh_sfme(bm,f,v1,v2,nl, NULL);
+
+ if (nf) {
+ BM_Copy_Attributes(bm, bm, f, nf);
+ copy_v3_v3(nf->no, f->no);
+ }
+
+ return nf;
+}
+
+/**
+ * bmesh_collapse_vert
+ *
+ * Collapses a vertex that has only two manifold edges
+ * onto a vertex it shares an edge with. Fac defines
+ * the amount of interpolation for Custom Data.
+ *
+ * Note that this is not a general edge collapse function. For
+ * that see BM_manifold_edge_collapse
+ *
+ * TODO:
+ * Insert error checking for KV valance.
+ *
+ * Returns -
+ * Nothing
+ */
+
+void BM_Collapse_Vert(BMesh *bm, BMEdge *ke, BMVert *kv, float fac){
+ BMFace **faces = NULL, *f;
+ BLI_array_staticdeclare(faces, 8);
+ BMIter iter;
+ BMLoop *l=NULL, *kvloop=NULL, *tvloop=NULL;
+ BMVert *tv = bmesh_edge_getothervert(ke,kv);
+ void *src[2];
+ float w[2];
+
+ w[0] = 1.0f - fac;
+ w[1] = fac;
+
+ if(ke->l){
+ l = ke->l;
+ do{
+ if(l->v == tv && ((BMLoop*)(l->next))->v == kv){
+ tvloop = l;
+ kvloop = ((BMLoop*)(l->next));
+
+ src[0] = kvloop->head.data;
+ src[1] = tvloop->head.data;
+ CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, kvloop->head.data);
+ }
+ l=l->radial_next;
+ }while(l!=ke->l);
+ }
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_VERT, kv) {
+ BLI_array_append(faces, f);
+ }
+
+ BM_Data_Interp_From_Verts(bm, kv, tv, kv, fac);
+
+ //bmesh_jekv(bm,ke,kv);
+ if (faces && BLI_array_count(faces) > 1) {
+ BMFace *f2;
+ BMEdge *e2;
+ BMVert *tv2;
+
+ /*ok, no faces, means we have a wire edge*/
+ e2 = bmesh_disk_nextedge(ke, kv);
+ tv2 = BM_OtherEdgeVert(e2, kv);
+
+ f2 = BM_Join_Faces(bm, faces, BLI_array_count(faces));
+ BM_Split_Face(bm, f2, tv, tv2, NULL, NULL);
+ } else if (faces && BLI_array_count(faces) == 1) {
+ BMLoop **loops = NULL;
+ BMEdge *e;
+ BMVert **verts = NULL;
+ BMEdge **edges = NULL;
+ BMFace *f2;
+ BLI_array_staticdeclare(verts, 64);
+ BLI_array_staticdeclare(edges, 64);
+ BLI_array_staticdeclare(loops, 64);
+ int i;
+
+ /*create new face excluding kv*/
+ f = *faces;
+ l = bm_firstfaceloop(f);
+ i = 0;
+ do {
+ if (l->v != kv) {
+ BLI_array_append(verts, l->v);
+
+ if (l->e != ke && !BM_Vert_In_Edge(l->e, kv)) {
+ BLI_array_append(edges, l->e);
+ } else {
+ BMVert *v2;
+
+ if (BM_Vert_In_Edge(l->next->e, kv))
+ v2 = BM_OtherEdgeVert(l->next->e, kv);
+ else
+ v2 = BM_OtherEdgeVert(l->prev->e, kv);
+
+ e = BM_Make_Edge(bm, BM_OtherEdgeVert(l->e, kv), v2, l->e, 1);
+ BLI_array_append(edges, e);
+ }
+
+ BLI_array_append(loops, l);
+ i++;
+ }
+
+ l = l->next;
+ } while (l != bm_firstfaceloop(f));
+
+ f2 = BM_Make_Face(bm, verts, edges, BLI_array_count(verts));
+ l = bm_firstfaceloop(f2);
+ i = 0;
+ do {
+ BM_Copy_Attributes(bm, bm, loops[i], l);
+ i++;
+ l = l->next;
+ } while (l != bm_firstfaceloop(f2));
+
+ BM_Copy_Attributes(bm, bm, f, f2);
+ BM_Kill_Face(bm, f);
+ BM_Kill_Vert(bm, kv);
+ } else {
+ BMVert *tv2;
+ BMEdge *e2, *ne;
+
+ /*ok, no faces, means we have a wire edge*/
+ e2 = bmesh_disk_nextedge(ke, kv);
+ tv2 = BM_OtherEdgeVert(e2, kv);
+
+ ne = BM_Make_Edge(bm, tv, tv2, ke, 0);
+
+ BM_Kill_Edge(bm, ke);
+ BM_Kill_Edge(bm, e2);
+ BM_Kill_Vert(bm, kv);
+ }
+
+ BLI_array_free(faces);
+}
+
+/**
+ * BM_split_edge
+ *
+ * Splits an edge. v should be one of the vertices in e and
+ * defines the direction of the splitting operation for interpolation
+ * purposes.
+ *
+ * Returns -
+ * the new vert
+ */
+
+BMVert *BM_Split_Edge(BMesh *bm, BMVert *v, BMEdge *e, BMEdge **ne, float percent) {
+ BMVert *nv, *v2;
+
+ v2 = bmesh_edge_getothervert(e,v);
+ nv = bmesh_semv(bm,v,e,ne);
+ if (nv == NULL) return NULL;
+
+ sub_v3_v3v3(nv->co,v2->co,v->co);
+ VECADDFAC(nv->co,v->co,nv->co,percent);
+
+ if (ne) {
+ (*ne)->head.flag = e->head.flag;
+ BM_Copy_Attributes(bm, bm, e, *ne);
+ }
+
+ /*v->nv->v2*/
+ BM_Data_Facevert_Edgeinterp(bm,v2, v, nv, e, percent);
+ BM_Data_Interp_From_Verts(bm, v2, v, nv, percent);
+ return nv;
+}
+
+BMVert *BM_Split_Edge_Multi(BMesh *bm, BMEdge *e, int numcuts)
+{
+ int i;
+ float percent;
+ BMVert *nv = NULL;
+
+ for(i=0; i < numcuts; i++){
+ percent = 1.0f / (float)(numcuts + 1 - i);
+ nv = BM_Split_Edge(bm, e->v2, e, NULL, percent);
+ }
+ return nv;
+}
+
+int BM_Validate_Face(BMesh *bm, BMFace *face, FILE *err)
+{
+ BMIter iter;
+ BLI_array_declare(verts);
+ BMVert **verts = NULL;
+ BMLoop *l;
+ int ret = 1, i, j;
+
+ if (face->len == 2) {
+ fprintf(err, "warning: found two-edged face. face ptr: %p\n", face);
+ fflush(err);
+ }
+
+ for (l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, face);l;l=BMIter_Step(&iter)) {
+ BLI_array_growone(verts);
+ verts[BLI_array_count(verts)-1] = l->v;
+
+ if (l->e->v1 == l->e->v2) {
+ fprintf(err, "Found bmesh edge with identical verts!\n");
+ fprintf(err, " edge ptr: %p, vert: %p\n", l->e, l->e->v1);
+ fflush(err);
+ ret = 0;
+ }
+ }
+
+ for (i=0; i<BLI_array_count(verts); i++) {
+ for (j=0; j<BLI_array_count(verts); j++) {
+ if (j == i) continue;
+ if (verts[i] == verts[j]) {
+ fprintf(err, "Found duplicate verts in bmesh face!\n");
+ fprintf(err, " face ptr: %p, vert: %p\n", face, verts[i]);
+ fflush(err);
+ ret = 0;
+ }
+ }
+ }
+
+ BLI_array_free(verts);
+ return ret;
+}
+
+/*
+ BM Rotate Edge
+
+ Spins an edge topologically, either counter-clockwise or clockwise.
+ If ccw is true, the edge is spun counter-clockwise, otherwise it is
+ spun clockwise.
+
+ Returns the spun edge. Note that this works by dissolving the edge
+ then re-creating it, so the returned edge won't have the same pointer
+ address as the original one.
+
+ Returns NULL on error (e.g., if the edge isn't surrounded by exactly
+ two faces).
+*/
+BMEdge *BM_Rotate_Edge(BMesh *bm, BMEdge *e, int ccw)
+{
+ BMVert *v1, *v2;
+ BMLoop *l, *l1, *l2, *nl;
+ BMFace *f;
+ BMIter liter;
+
+ v1 = e->v1;
+ v2 = e->v2;
+
+ if (BM_Edge_FaceCount(e) != 2)
+ return NULL;
+
+ f = BM_Join_TwoFaces(bm, e->l->f, ((BMLoop*)e->l->radial_next)->f, e);
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ if (l->v == v1)
+ l1 = l;
+ else if (l->v == v2)
+ l2 = l;
+ }
+
+ if (ccw) {
+ l1 = (BMLoop*) l1->prev;
+ l2 = (BMLoop*) l2->prev;
+ } else {
+ l1 = (BMLoop*) l1->next;
+ l2 = (BMLoop*) l2->next;
+ }
+
+ if (!BM_Split_Face(bm, f, l1->v, l2->v, &nl, NULL))
+ return NULL;
+
+ return nl->e;
+}
diff --git a/source/blender/bmesh/intern/bmesh_newcore.c b/source/blender/bmesh/intern/bmesh_newcore.c
new file mode 100644
index 00000000000..37518457dbf
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_newcore.c
@@ -0,0 +1,1222 @@
+#include <limits.h>
+
+#include "BLI_math_vector.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_listbase.h"
+#include "BLI_mempool.h"
+#include "BLI_ghash.h"
+#include "BLI_array.h"
+
+#include "DNA_listBase.h"
+
+#include "bmesh_class.h"
+
+#include "bmesh_iterators.h"
+#include "bmesh_private.h"
+
+/*note: first three layers, base through adjacency, do *not* use the
+ LayerType system for speed/memory cache efficiency and whatnot*/
+
+static void inherit_vert(BMesh *bm, BMBaseVert *v)
+{
+ int i;
+
+ for (i=0; i<bm->totlayer; i++) {
+ void *ldata = BMSC_GETSELF(bm, v, bm->layers+i);
+ bm->layers[i].type->new_vert(bm, v, ldata);
+ }
+
+ if (bm->baselevel >= LAYER_ADJ) {
+ /*not sure anything is needed here either, verts generally come first before all else*/
+ }
+}
+
+static void inherit_edge(BMesh *bm, BMBaseEdge *ebase)
+{
+ int i;
+
+ if (bm->baselevel >= LAYER_ADJ) {
+ BMEdge *e = (BMEdge*)ebase;
+
+ bmesh_disk_append_edge(e, e->v1);
+ bmesh_disk_append_edge(e, e->v2);
+ }
+
+ for (i=0; i<bm->totlayer; i++) {
+ void *ldata = BMSC_GETSELF(bm, ebase, bm->layers+i);
+ bm->layers[i].type->new_edge(bm, ebase, ldata);
+ }
+}
+
+static void inherit_loop(BMesh *bm, BMBaseLoop *l, BMBaseFace *f)
+{
+ int i;
+
+ for (i=0; i<bm->totlayer; i++) {
+ void *self;
+
+ if (!bm->layers[i].type->new_loop) continue;
+
+ self = BMSC_GETSELF(bm, l, &bm->layers[i]);
+ bm->layers[i].type->new_loop(bm, (BMBaseLoop*)l, self, (BMBaseFace*)f);
+ }
+}
+
+/*
+static void inherit_face(BMesh *bm, BMBaseFace *basef)
+{
+ int i;
+
+ for (i=0; i<bm->totlayer; i++) {
+ void *fdata = BMSC_GETSELF(bm, basef, bm->layers+i);
+ bm->layers[i].type->new_face(bm, basef, fdata);
+ }
+}
+*/
+
+void BM_SubClass(BMesh *bm, BMLayerType *type)
+{
+}
+
+BMVert *BM_Make_Vert(BMesh *bm, float co[3], struct BMVert *example) {
+ BMBaseVert *v = BLI_mempool_calloc(bm->vpool);
+
+ bm->totvert += 1;
+
+ v->head.type = BM_VERT;
+ if (bm->svpool)
+ v->head.layerdata = BLI_mempool_calloc(bm->svpool);
+
+ if (co) copy_v3_v3(v->co, co);
+
+ if (bm->baselevel >= LAYER_TOOL) {
+ BMBaseVert *tv = (BMBaseVert*)v;
+
+ /*allocate flags*/
+ tv->head.flags = BLI_mempool_calloc(bm->toolflagpool);
+ }
+
+ CustomData_bmesh_set_default(&bm->vdata, &v->head.data);
+
+ inherit_vert(bm, v);
+
+ if (example)
+ BM_Copy_Attributes(bm, bm, (BMVert*)example, (BMVert*)v);
+
+ CHECK_ELEMENT(bm, v);
+
+ return (BMVert*) v;
+}
+
+/**
+ * BMESH EDGE EXIST
+ *
+ * Finds out if two vertices already have an edge
+ * connecting them. Note that multiple edges may
+ * exist between any two vertices, and therefore
+ * This function only returns the first one found.
+ *
+ * Returns -
+ * BMEdge pointer
+ */
+BMEdge *BM_Edge_Exist(BMVert *v1, BMVert *v2)
+{
+ BMIter iter;
+ BMEdge *e;
+
+ BM_ITER(e, &iter, NULL, BM_EDGES_OF_VERT, v1) {
+ if (e->v1 == v2 || e->v2 == v2)
+ return e;
+ }
+
+ return NULL;
+}
+
+BMEdge *BM_Make_Edge(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge *example, int nodouble) {
+ BMBaseEdge *e;
+
+ if (nodouble && (e=(BMBaseEdge*)BM_Edge_Exist(v1, v2)))
+ return (BMEdge*)e;
+
+ e = BLI_mempool_calloc(bm->epool);
+ bm->totedge += 1;
+ e->head.type = BM_EDGE;
+ if (bm->sepool)
+ e->head.layerdata = BLI_mempool_calloc(bm->sepool);
+
+ if (bm->baselevel >= LAYER_TOOL) {
+ BMBaseEdge *te = (BMBaseEdge*)e;
+
+ /*allocate flags*/
+ te->head.flags = BLI_mempool_calloc(bm->toolflagpool);
+ }
+
+ e->v1 = (BMBaseVert*) v1;
+ e->v2 = (BMBaseVert*) v2;
+
+ CustomData_bmesh_set_default(&bm->edata, &e->head.data);
+
+ inherit_edge(bm, e);
+
+ if (example)
+ BM_Copy_Attributes(bm, bm, (BMEdge*)example, (BMEdge*)e);
+
+ CHECK_ELEMENT(bm, e);
+
+ return (BMEdge*) e;
+}
+
+static BMLoop *bmesh_create_loop(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f, BMLoop *example){
+ BMLoop *l=NULL;
+ int i;
+
+ l = BLI_mempool_calloc(bm->lpool);
+ l->next = l->prev = NULL;
+ l->v = v;
+ l->e = e;
+ if (bm->baselevel >= LAYER_ADJ) {
+ l->f = f;
+ l->radial_next = l->radial_prev = NULL;
+ }
+ l->head.data = NULL;
+ l->head.type = BM_LOOP;
+
+ bm->totloop++;
+
+ if (bm->slpool)
+ l->head.layerdata = BLI_mempool_calloc(bm->slpool);
+
+ inherit_loop(bm, l, f);
+
+ if(example)
+ CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, example->head.data, &l->head.data);
+ else
+ CustomData_bmesh_set_default(&bm->ldata, &l->head.data);
+
+ return l;
+}
+
+BMLoop *BM_Add_FaceBoundary(BMesh *bm, BMFace *f, BMVert *startv, BMEdge *starte) {
+ BMBaseLoopList *lst = BLI_mempool_calloc(bm->looplistpool);
+ BMLoop *l = (BMLoop*)bmesh_create_loop(bm, startv, starte, (BMBaseFace*)f, NULL);
+ int i;
+
+ bmesh_radial_append(starte, l);
+
+ lst->first = lst->last = (BMBaseLoop*)l;
+ BLI_addtail(&f->loops, lst);
+
+ if (bm->baselevel >= LAYER_ADJ)
+ l->f = f;
+
+ for (i=0; i<bm->totlayer; i++) {
+ void *self = BMSC_GETSELF(bm, l, (&bm->layers[i]));
+
+ bm->layers[i].type->new_loop(bm, (BMBaseLoop*)l, self, (BMBaseFace*)f);
+ }
+
+ return l;
+}
+
+BMFace *BM_Make_Face(BMesh *bm, BMVert **verts, BMEdge **edges, int len) {
+ BMBaseFace *f;
+ BMBaseLoop *l, *startl, *lastl;
+ int i;
+
+ if (len == 0) {
+ /*just return NULL for now*/
+ return NULL;
+ }
+
+ f = BLI_mempool_calloc(bm->fpool);
+ bm->totface += 1;
+ f->head.type = BM_FACE;
+
+ if (bm->sfpool)
+ f->head.layerdata = BLI_mempool_calloc(bm->sfpool);
+
+ startl = lastl = (BMBaseLoop*) BM_Add_FaceBoundary(bm, (BMFace*)f, verts[0], edges[0]);
+
+ startl->v = (BMBaseVert*) verts[0];
+ startl->e = (BMBaseEdge*) edges[0];
+ for (i=1; i<len; i++) {
+ l = bmesh_create_loop(bm, verts[i], edges[i], f, edges[i]->l);
+
+ if (bm->baselevel >= LAYER_ADJ) {
+ BMLoop *bl = (BMLoop*)l;
+ bl->f = (BMFace*) f;
+ bmesh_radial_append(edges[i], bl);
+ }
+
+ l->prev = lastl;
+ lastl->next = l;
+ lastl = l;
+ }
+
+ if (bm->baselevel >= LAYER_TOOL) {
+ BMBaseFace *tf = (BMBaseFace*) f;
+
+ /*allocate flags*/
+ tf->head.flags = BLI_mempool_calloc(bm->toolflagpool);
+ }
+
+ CustomData_bmesh_set_default(&bm->pdata, &f->head.data);
+
+ startl->prev = lastl;
+ lastl->next = startl;
+
+ f->len = len;
+ f->totbounds = 0;
+
+ for (i=0; i<bm->totlayer; i++) {
+ void *self;
+
+ if (!bm->layers[i].type->new_face) continue;
+
+ self = BMSC_GETSELF(bm, f, &bm->layers[i]);
+ bm->layers[i].type->new_face(bm, f, self);
+ }
+
+ CHECK_ELEMENT(bm, f);
+
+ return (BMFace*) f;
+}
+
+int bmesh_check_element(BMesh *bm, void *element, int type) {
+ BMHeader *head = element;
+ int err = 0;
+
+ if (!element)
+ return 1;
+
+ if (head->type != type)
+ return 2;
+
+ switch (type) {
+ case BM_VERT: {
+ BMVert *v = element;
+ if (v->e && v->e->head.type != BM_EDGE) {
+ err |= 4;
+ }
+ break;
+ }
+ case BM_EDGE: {
+ BMEdge *e = element;
+ if (e->l && e->l->head.type != BM_LOOP)
+ err |= 8;
+ if (e->l && e->l->f->head.type != BM_FACE)
+ err |= 16;
+ if (e->dlink1.prev == NULL || e->dlink2.prev == NULL || e->dlink1.next == NULL || e->dlink2.next == NULL)
+ err |= 32;
+ if (e->l && (e->l->radial_next == NULL || e->l->radial_prev == NULL))
+ err |= 64;
+ if (e->l && e->l->f->len <= 0)
+ err |= 128;
+ break;
+ }
+ case BM_LOOP: {
+ BMLoop *l = element, *l2;
+ int i;
+
+ if (l->f->head.type != BM_FACE)
+ err |= 256;
+ if (l->e->head.type != BM_EDGE)
+ err |= 512;
+ if (l->v->head.type != BM_VERT)
+ err |= 1024;
+ if (!BM_Vert_In_Edge(l->e, l->v)) {
+ printf("eek!! fatal bmesh error! evil!\n");
+ err |= 2048;
+ }
+
+ if (l->radial_next == NULL || l->radial_prev == NULL)
+ err |= (1<<12);
+ if (l->f->len <= 0)
+ err |= (1<<13);
+
+ /*validate boundary loop--invalid for hole loops, of course,
+ but we won't be allowing those for a while yet*/
+ l2 = l;
+ i = 0;
+ do {
+ if (i >= 9999999)
+ break;
+
+ i++;
+ l2 = l2->next;
+ } while (l2 != l);
+
+ if (i != l->f->len || l2 != l)
+ err |= (1<<14);
+
+ if (!bmesh_radial_validate(bmesh_radial_length(l), l))
+ err |= (1<<15);
+
+ break;
+ }
+ case BM_FACE: {
+ BMFace *f = element;
+ BMLoop *l;
+ int len=0;
+
+ if (!f->loops.first)
+ err |= (1<<16);
+ l = bm_firstfaceloop(f);
+ do {
+ if (l->f != f) {
+ printf("yeek!! loop inside one face points to another!\n");
+ err |= (1<<17);
+ }
+
+ if (!l->e)
+ err |= (1<<18);
+ if (!l->v)
+ err |= (1<<19);
+ if (!BM_Vert_In_Edge(l->e, l->v) || !BM_Vert_In_Edge(l->e, l->next->v)) {
+ err |= (1<<20);
+ }
+
+ if (!bmesh_radial_validate(bmesh_radial_length(l), l))
+ err |= (1<<21);
+
+ if (!bmesh_disk_count(l->v) || !bmesh_disk_count(l->next->v))
+ err |= (1<<22);
+
+ len++;
+ l = l->next;
+ } while (l != bm_firstfaceloop(f));
+
+ if (len != f->len)
+ err |= (1<<23);
+ }
+ }
+
+ if (err) {
+ bmesh_error();
+ }
+
+ return err;
+}
+
+void bmesh_kill_loop(BMesh *bm, BMLoop *l) {
+ int i;
+
+ for (i=0; i<bm->totlayer; i++) {
+ bm->layers[i].type->free_loop(bm, (BMBaseLoop*)l);
+ }
+
+ bm->totloop--;
+ if (l->head.data)
+ CustomData_bmesh_free_block(&bm->ldata, &l->head.data);
+
+ if (bm->baselevel >= LAYER_TOOL && l->head.flags) {
+ BLI_mempool_free(bm->toolflagpool, l->head.flags);
+ }
+
+ BLI_mempool_free(bm->lpool, l);
+}
+
+void BM_Kill_Face(BMesh *bm, BMFace *f) {
+ BMBaseLoopList *ls, *lsnext;
+ int i;
+
+ CHECK_ELEMENT(bm, f);
+
+ for (i=0; i<bm->totlayer; i++) {
+ bm->layers[i].type->free_face(bm, (BMBaseFace*)f);
+ }
+
+ for (ls=f->loops.first; ls; ls=lsnext) {
+ BMBaseLoop *l, *lnext;
+
+ lsnext = ls->next;
+ l = ls->first;
+ do {
+ lnext = l->next;
+
+ if (bm->baselevel >= LAYER_ADJ)
+ bmesh_radial_remove_loop((BMLoop*)l, l->e);
+ bmesh_kill_loop(bm, (BMLoop*)l);
+
+ l = lnext;
+ } while (l != ls->first);
+
+ BLI_mempool_free(bm->looplistpool, ls);
+ }
+
+ bm->totface--;
+ BM_remove_selection(bm, f);
+ if (f->head.data)
+ CustomData_bmesh_free_block(&bm->pdata, &f->head.data);
+
+ if (bm->baselevel >= LAYER_TOOL) {
+ BLI_mempool_free(bm->toolflagpool, f->head.flags);
+ }
+
+ BLI_mempool_free(bm->fpool, f);
+}
+
+void BM_Kill_Edge(BMesh *bm, BMEdge *e) {
+ int i;
+
+ for (i=0; i<bm->totlayer; i++) {
+ bm->layers[i].type->free_edge(bm, (BMBaseEdge*)e);
+ }
+
+ if (bm->baselevel >= LAYER_ADJ) {
+ bmesh_disk_remove_edge(e, e->v1);
+ bmesh_disk_remove_edge(e, e->v2);
+
+ if (e->l) {
+ BMLoop *l = e->l, *lnext, *startl=e->l;
+
+ do {
+ lnext = l->radial_next;
+ BM_Kill_Face(bm, l->f);
+
+ if (l == lnext)
+ break;
+ l = lnext;
+ } while (l != startl);
+ }
+ }
+
+ bm->totedge--;
+ BM_remove_selection(bm, e);
+ if (e->head.data)
+ CustomData_bmesh_free_block(&bm->edata, &e->head.data);
+
+ if (bm->baselevel >= LAYER_TOOL) {
+ BLI_mempool_free(bm->toolflagpool, e->head.flags);
+ }
+
+ BLI_mempool_free(bm->epool, e);
+}
+
+void BM_Kill_Vert(BMesh *bm, BMVert *v) {
+ int i;
+
+ for (i=0; i<bm->totlayer; i++) {
+ bm->layers[i].type->free_vert(bm, (BMBaseVert*)v);
+ }
+
+ if (bm->baselevel >= LAYER_ADJ) {
+ if (v->e) {
+ BMEdge *e, *nexte;
+
+ e = v->e;
+ while (v->e) {
+ nexte=bmesh_disk_nextedge(e, v);
+
+ BM_Kill_Edge(bm, (BMEdge*)e);
+ e = nexte;
+ }
+ }
+ }
+
+ bm->totvert--;
+ BM_remove_selection(bm, v);
+ if (v->head.data)
+ CustomData_bmesh_free_block(&bm->vdata, &v->head.data);
+
+ if (bm->baselevel >= LAYER_TOOL) {
+ BLI_mempool_free(bm->toolflagpool, v->head.flags);
+ }
+
+ BLI_mempool_free(bm->vpool, v);
+}
+
+/********** private disk and radial cycle functions ************/
+
+/**
+ * bmesh_loop_reverse
+ *
+ * FLIP FACE EULER
+ *
+ * Changes the winding order of a face from CW to CCW or vice versa.
+ * This euler is a bit peculiar in compairson to others as it is its
+ * own inverse.
+ *
+ * TODO: reinsert validation code.
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+ */
+
+int bmesh_loop_length(BMLoop *l)
+{
+ BMLoop *ol = l;
+ int i = 0;
+
+ do {
+ l = l->next;
+ i++;
+ } while (l != ol);
+
+ return i;
+}
+
+int bmesh_loop_reverse_loop(BMesh *bm, BMFace *f, BMLoopList *lst){
+ BMLoop *l = lst->first, *curloop, *oldprev, *oldnext;
+ BMEdge *staticedar[64], **edar;
+ int i, j, edok, len = 0;
+
+ len = bmesh_loop_length(l);
+ if(len >= 64){
+ edar = MEM_callocN(sizeof(BMEdge *)* len, "BM Edge pointer array");
+ } else {
+ edar = staticedar;
+ }
+
+ for(i=0, curloop = l; i< len; i++, curloop= ((BMLoop*)(curloop->next)) ){
+ curloop->e->head.eflag1 = 0;
+ curloop->e->head.eflag2 = bmesh_radial_length(curloop);
+ bmesh_radial_remove_loop(curloop, curloop->e);
+ /*in case of border edges we HAVE to zero out curloop->radial Next/Prev*/
+ curloop->radial_next = curloop->radial_prev = NULL;
+ edar[i] = curloop->e;
+ }
+
+ /*actually reverse the loop.*/
+ for(i=0, curloop = l; i < len; i++){
+ oldnext = ((BMLoop*)(curloop->next));
+ oldprev = ((BMLoop*)(curloop->prev));
+ curloop->next = (BMLoop*)oldprev;
+ curloop->prev = (BMLoop*)oldnext;
+ curloop = oldnext;
+ }
+
+ if(len == 2){ //two edged face
+ //do some verification here!
+ l->e = edar[1];
+ ((BMLoop*)(l->next))->e = edar[0];
+ }
+ else{
+ for(i=0, curloop = l; i < len; i++, curloop = ((BMLoop*)(curloop->next)) ){
+ edok = 0;
+ for(j=0; j < len; j++){
+ edok = bmesh_verts_in_edge(curloop->v, ((BMLoop*)(curloop->next))->v, edar[j]);
+ if(edok){
+ curloop->e = edar[j];
+ break;
+ }
+ }
+ }
+ }
+ /*rebuild radial*/
+ for(i=0, curloop = l; i < len; i++, curloop = curloop->next)
+ bmesh_radial_append(curloop->e, curloop);
+
+ /*validate radial*/
+ for(i=0, curloop = l; i < len; i++, curloop = curloop->next) {
+ CHECK_ELEMENT(bm, curloop);
+ CHECK_ELEMENT(bm, curloop->e);
+ CHECK_ELEMENT(bm, curloop->v);
+ CHECK_ELEMENT(bm, curloop->f);
+ }
+
+ if (edar != staticedar)
+ MEM_freeN(edar);
+
+ CHECK_ELEMENT(bm, f);
+
+ return 1;
+}
+
+int bmesh_loop_reverse(BMesh *bm, BMFace *f)
+{
+ return bmesh_loop_reverse_loop(bm, f, f->loops.first);
+}
+
+void bmesh_systag_elements(BMesh *bm, void *veles, int tot, int flag)
+{
+ BMHeader **eles = veles;
+ int i;
+
+ for (i=0; i<tot; i++) {
+ bmesh_api_setflag(eles[i], flag);
+ }
+}
+
+void bmesh_clear_systag_elements(BMesh *bm, void *veles, int tot, int flag)
+{
+ BMHeader **eles = veles;
+ int i;
+
+ for (i=0; i<tot; i++) {
+ bmesh_api_clearflag(eles[i], flag);
+ }
+}
+
+#define FACE_MARK (1<<10)
+
+static int count_flagged_radial(BMLoop *l, int flag)
+{
+ BMLoop *l2 = l;
+ int i = 0, c=0;
+
+ do {
+ if (!l2) {
+ bmesh_error();
+ return 0;
+ }
+
+ i += bmesh_api_getflag(l2->f, flag) ? 1 : 0;
+ l2 = bmesh_radial_nextloop(l2);
+ if (c >= 800000) {
+ bmesh_error();
+ return 0;
+ }
+ c++;
+ } while (l2 != l);
+
+ return i;
+}
+
+static int count_flagged_disk(BMVert *v, int flag)
+{
+ BMEdge *e = v->e;
+ int i=0;
+
+ if (!e)
+ return 0;
+
+ do {
+ i += bmesh_api_getflag(e, flag) ? 1 : 0;
+ e = bmesh_disk_nextedge(e, v);
+ } while (e != v->e);
+
+ return i;
+}
+
+static int disk_is_flagged(BMVert *v, int flag)
+{
+ BMEdge *e = v->e;
+
+ if (!e)
+ return 0;
+
+ do {
+ BMLoop *l = e->l;
+
+ if (!l) {
+ return 0;
+ }
+
+ if (bmesh_radial_length(l) == 1)
+ return 0;
+
+ do {
+ if (!bmesh_api_getflag(l->f, flag))
+ return 0;
+
+ l = l->radial_next;
+ } while (l != e->l);
+
+ e = bmesh_disk_nextedge(e, v);
+ } while (e != v->e);
+
+ return 1;
+}
+
+/* Midlevel Topology Manipulation Functions */
+
+/*joins a collected group of faces into one. only restriction on
+ the input data is that the faces must be connected to each other.*/
+BMFace *BM_Join_Faces(BMesh *bm, BMFace **faces, int totface)
+{
+ BMFace *f, *newf;
+ BMLoopList *lst;
+ BMLoop *l;
+ BMEdge **edges = NULL;
+ BMEdge **deledges = NULL;
+ BMVert **delverts = NULL;
+ BLI_array_staticdeclare(edges, 64);
+ BLI_array_staticdeclare(deledges, 64);
+ BLI_array_staticdeclare(delverts, 64);
+ BMVert *v1=NULL, *v2=NULL;
+ ListBase holes = {NULL, NULL};
+ char *err = NULL;
+ int i, tote=0;
+
+ if (!totface) {
+ bmesh_error();
+ return NULL;
+ }
+
+ if (totface == 1)
+ return faces[0];
+
+ bmesh_systag_elements(bm, faces, totface, _FLAG_JF);
+
+ for (i=0; i<totface; i++) {
+ f = faces[i];
+ l = bm_firstfaceloop(f);
+ do {
+ int rlen = count_flagged_radial(l, _FLAG_JF);
+
+ if (rlen > 2) {
+ err = "Input faces do not form a contiguous manifold region";
+ goto error;
+ } else if (rlen == 1) {
+ BLI_array_append(edges, l->e);
+
+ if (!v1) {
+ v1 = l->v;
+ v2 = BM_OtherEdgeVert(l->e, l->v);
+ }
+ tote++;
+ } else if (rlen == 2) {
+ int d1, d2;
+
+ d1 = disk_is_flagged(l->e->v1, _FLAG_JF);
+ d2 = disk_is_flagged(l->e->v2, _FLAG_JF);
+
+ if (!d1 && !d2 && !bmesh_api_getflag(l->e, _FLAG_JF)) {
+ BLI_array_append(deledges, l->e);
+ bmesh_api_setflag(l->e, _FLAG_JF);
+ } else {
+ if (d1 && !bmesh_api_getflag(l->e->v1, _FLAG_JF)) {
+ BLI_array_append(delverts, l->e->v1);
+ bmesh_api_setflag(l->e->v1, _FLAG_JF);
+ }
+
+ if (d2 && !bmesh_api_getflag(l->e->v2, _FLAG_JF)) {
+ BLI_array_append(delverts, l->e->v2);
+ bmesh_api_setflag(l->e->v2, _FLAG_JF);
+ }
+ }
+ }
+
+ l = l->next;
+ } while (l != bm_firstfaceloop(f));
+
+ for (lst=f->loops.first; lst; lst=lst->next) {
+ if (lst == f->loops.first) continue;
+
+ BLI_remlink(&f->loops, lst);
+ BLI_addtail(&holes, lst);
+ }
+ }
+
+ /*create region face*/
+ newf = BM_Make_Ngon(bm, v1, v2, edges, tote, 0);
+ if (!newf) {
+ err = "Invalid boundary region to join faces";
+ goto error;
+ }
+
+ for (i=0; i<bm->totlayer; i++) {
+ BMFace *faces2[2] = {newf, NULL};
+
+ if (bm->layers[i].type->faces_from_faces)
+ bm->layers[i].type->faces_from_faces(bm, faces, totface, faces2, 1);
+ }
+
+ /*copy over loop data*/
+ l = bm_firstfaceloop(newf);
+ do {
+ BMLoop *l2 = l->radial_next;
+
+ do {
+ if (bmesh_api_getflag(l2->f, _FLAG_JF))
+ break;
+ l2 = l2->radial_next;
+ } while (l2 != l);
+
+ if (l2 != l) {
+ /*I think this is correct?*/
+ if (l2->v != l->v) {
+ l2 = l2->next;
+ }
+
+ BM_Copy_Attributes(bm, bm, l2, l);
+ }
+
+ l = l->next;
+ } while (l != bm_firstfaceloop(newf));
+
+ BM_Copy_Attributes(bm, bm, faces[0], newf);
+
+ /*add holes*/
+ BLI_movelisttolist(&newf->loops, &holes);
+
+ /*update loop face pointers*/
+ for (lst=newf->loops.first; lst; lst=lst->next) {
+ l = lst->first;
+ do {
+ l->f = newf;
+ l = l->next;
+ } while (l != lst->first);
+ }
+
+ bmesh_clear_systag_elements(bm, faces, totface, _FLAG_JF);
+ bmesh_api_clearflag(newf, _FLAG_JF);
+
+ /*delete old geometry*/
+ for (i=0; i<BLI_array_count(deledges); i++) {
+ BM_Kill_Edge(bm, deledges[i]);
+ }
+
+ for (i=0; i<BLI_array_count(delverts); i++) {
+ BM_Kill_Vert(bm, delverts[i]);
+ }
+
+ BLI_array_free(edges);
+ BLI_array_free(deledges);
+ BLI_array_free(delverts);
+
+ CHECK_ELEMENT(bm, newf);
+ return newf;
+error:
+ bmesh_clear_systag_elements(bm, faces, totface, _FLAG_JF);
+ BLI_array_free(edges);
+ BLI_array_free(deledges);
+ BLI_array_free(delverts);
+
+ if (err) {
+ BMO_RaiseError(bm, bm->currentop, BMERR_DISSOLVEFACES_FAILED, err);
+ }
+ return NULL;
+}
+
+static BMFace *bmesh_addpolylist(BMesh *bm, BMFace *example) {
+ BMBaseFace *f;
+ BMBaseLoopList *lst;
+
+ f = BLI_mempool_calloc(bm->fpool);
+ lst = BLI_mempool_calloc(bm->looplistpool);
+
+ f->head.type = BM_FACE;
+ BLI_addtail(&f->loops, lst);
+ bm->totface++;
+
+ if (bm->baselevel >= LAYER_TOOL) {
+ BMBaseFace *tf = (BMBaseFace*)f;
+
+ /*allocate flags*/
+ tf->head.flags = BLI_mempool_calloc(bm->toolflagpool);
+ }
+
+ if (bm->sfpool)
+ f->head.layerdata = BLI_mempool_calloc(f->head.layerdata);
+
+ CustomData_bmesh_set_default(&bm->pdata, &f->head.data);
+
+ f->len = 0;
+ f->totbounds = 1;
+
+ /*okkaay not sure what to do here
+ for (i=0; i<bm->totlayer; i++) {
+ void *self;
+
+ if (!bm->layers[i].type->new_face) continue;
+
+ self = BMSC_GETSELF(bm, f, &bm->layers[i]);
+ bm->layers[i].type->new_face(bm, f, self);
+ }
+ */
+
+ return (BMFace*) f;
+}
+
+/**
+ * bmesh_SFME
+ *
+ * SPLIT FACE MAKE EDGE:
+ *
+ * Takes as input two vertices in a single face. An edge is created which divides the original face
+ * into two distinct regions. One of the regions is assigned to the original face and it is closed off.
+ * The second region has a new face assigned to it.
+ *
+ * Examples:
+ *
+ * Before: After:
+ * ---------- ----------
+ * | | | |
+ * | | | f1 |
+ * v1 f1 v2 v1======v2
+ * | | | f2 |
+ * | | | |
+ * ---------- ----------
+ *
+ * Note that the input vertices can be part of the same edge. This will
+ * result in a two edged face. This is desirable for advanced construction
+ * tools and particularly essential for edge bevel. Because of this it is
+ * up to the caller to decide what to do with the extra edge.
+ *
+ * If holes is NULL, then both faces will lose
+ * all holes from the original face. Also, you cannot split between
+ * a hole vert and a boundary vert; that case is handled by higher-
+ * level wrapping functions (when holes are fully implemented, anyway).
+ *
+ * Note that holes represents which holes goes to the new face, and of
+ * course this requires removing them from the exitsing face first, since
+ * you cannot have linked list links inside multiple lists.
+ *
+ * Returns -
+ * A BMFace pointer
+ */
+BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2,
+ BMLoop **rl, ListBase *holes)
+{
+
+ BMFace *f2;
+ BMLoop *v1loop = NULL, *v2loop = NULL, *curloop, *f1loop=NULL, *f2loop=NULL;
+ BMEdge *e;
+ BMLoopList *lst, *lst2;
+ int i, len, f1len, f2len;
+
+ /*verify that v1 and v2 are in face.*/
+ len = f->len;
+ for(i = 0, curloop = bm_firstfaceloop(f); i < len; i++, curloop = curloop->next) {
+ if(curloop->v == v1) v1loop = curloop;
+ else if(curloop->v == v2) v2loop = curloop;
+ }
+
+ if(!v1loop || !v2loop) return NULL;
+
+ /*allocate new edge between v1 and v2*/
+ e = BM_Make_Edge(bm, v1, v2, NULL, 0);
+
+ f2 = bmesh_addpolylist(bm,f);
+ f1loop = bmesh_create_loop(bm,v2,e,f,v2loop);
+ f2loop = bmesh_create_loop(bm,v1,e,f2,v1loop);
+
+ f1loop->prev = v2loop->prev;
+ f2loop->prev = v1loop->prev;
+ v2loop->prev->next = f1loop;
+ v1loop->prev->next = f2loop;
+
+ f1loop->next = v1loop;
+ f2loop->next = v2loop;
+ v1loop->prev = f1loop;
+ v2loop->prev = f2loop;
+
+ lst = f->loops.first;
+ lst2 = f2->loops.first;
+
+ lst2->first = lst2->last = f2loop;
+ lst->first = lst->last = f1loop;
+
+ /*validate both loops*/
+ /*I dont know how many loops are supposed to be in each face at this point! FIXME!*/
+
+ /*go through all of f2's loops and make sure they point to it properly.*/
+ curloop = lst2->first;
+ f2len = 0;
+ do {
+ curloop->f = f2;
+
+ curloop = curloop->next;
+ f2len++;
+ } while (curloop != lst2->first);
+
+ /*link up the new loops into the new edges radial*/
+ bmesh_radial_append(e, f1loop);
+ bmesh_radial_append(e, f2loop);
+
+ f2->len = f2len;
+
+ f1len = 0;
+ curloop = lst->first;
+ do {
+ f1len++;
+ curloop = curloop->next;
+ } while (curloop != lst->first);
+
+ f->len = f1len;
+
+ if(rl) *rl = f2loop;
+
+ if (holes) {
+ BLI_movelisttolist(&f2->loops, holes);
+ } else {
+ /*this code is not significant until holes actually work ;) */
+ //printf("warning: call to split face euler without holes argument; holes will be tossed.\n");
+ for (lst=f->loops.last; lst != f->loops.first; lst=lst2) {
+ lst2 = lst->prev;
+ BLI_mempool_free(bm->looplistpool, lst);
+ }
+ }
+
+ CHECK_ELEMENT(bm, e);
+ CHECK_ELEMENT(bm, f);
+ CHECK_ELEMENT(bm, f2);
+
+ return f2;
+}
+
+/**
+ * bmesh_SEMV
+ *
+ * SPLIT EDGE MAKE VERT:
+ * Takes a given edge and splits it into two, creating a new vert.
+ *
+ *
+ * Before: OV---------TV
+ * After: OV----NV---TV
+ *
+ * Returns -
+ * BMVert pointer.
+ *
+*/
+
+BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **re){
+ BMLoop *nextl;
+ BMEdge *ne;
+ BMVert *nv, *ov;
+ int i, edok, valance1=0, valance2=0;
+
+ if(bmesh_vert_in_edge(e,tv) == 0) return NULL;
+ ov = bmesh_edge_getothervert(e,tv);
+
+ /*count valance of v1*/
+ valance1 = bmesh_disk_count(ov);
+
+ /*count valance of v2*/
+ valance2 = bmesh_disk_count(tv);
+
+ nv = BM_Make_Vert(bm, tv->co, tv);
+ ne = BM_Make_Edge(bm, nv, tv, e, 0);
+
+ bmesh_disk_remove_edge(ne, tv);
+ bmesh_disk_remove_edge(ne, nv);
+
+ /*remove e from v2's disk cycle*/
+ bmesh_disk_remove_edge(e, tv);
+
+ /*swap out tv for nv in e*/
+ bmesh_edge_swapverts(e, tv, nv);
+
+ /*add e to nv's disk cycle*/
+ bmesh_disk_append_edge(e, nv);
+
+ /*add ne to nv's disk cycle*/
+ bmesh_disk_append_edge(ne, nv);
+
+ /*add ne to tv's disk cycle*/
+ bmesh_disk_append_edge(ne, tv);
+
+ /*verify disk cycles*/
+ edok = bmesh_disk_validate(valance1, ov->e, ov);
+ if(!edok) bmesh_error();
+ edok = bmesh_disk_validate(valance2, tv->e, tv);
+ if(!edok) bmesh_error();
+ edok = bmesh_disk_validate(2, nv->e, nv);
+ if(!edok) bmesh_error();
+
+ /*Split the radial cycle if present*/
+ nextl = e->l;
+ e->l = NULL;
+ if(nextl) {
+ BMLoop *nl, *l;
+ int radlen = bmesh_radial_length(nextl);
+ int first1=0, first2=0;
+
+ /*Take the next loop. Remove it from radial. Split it. Append to appropriate radials.*/
+ while(nextl) {
+ l=nextl;
+ l->f->len++;
+ nextl = nextl!=nextl->radial_next ? nextl->radial_next : NULL;
+ bmesh_radial_remove_loop(l, NULL);
+
+ nl = bmesh_create_loop(bm,NULL,NULL,l->f,l);
+ nl->prev = l;
+ nl->next = (l->next);
+ nl->prev->next = nl;
+ nl->next->prev = nl;
+ nl->v = nv;
+
+ /*assign the correct edge to the correct loop*/
+ if(bmesh_verts_in_edge(nl->v, nl->next->v, e)) {
+ nl->e = e;
+ l->e = ne;
+
+ /*append l into ne's rad cycle*/
+ if(!first1) {
+ first1 = 1;
+ l->radial_next = l->radial_prev = NULL;
+ }
+
+ if(!first2) {
+ first2 = 1;
+ l->radial_next = l->radial_prev = NULL;
+ }
+
+ bmesh_radial_append(nl->e, nl);
+ bmesh_radial_append(l->e, l);
+ }
+ else if(bmesh_verts_in_edge(nl->v,((BMLoop*)(nl->next))->v,ne)){
+ nl->e = ne;
+ l->e = e;
+
+ /*append l into ne's rad cycle*/
+ if(!first1) {
+ first1 = 1;
+ l->radial_next = l->radial_prev = NULL;
+ }
+
+ if(!first2) {
+ first2 = 1;
+ l->radial_next = l->radial_prev = NULL;
+ }
+
+ bmesh_radial_append(nl->e, nl);
+ bmesh_radial_append(l->e, l);
+ }
+
+ }
+
+ /*verify length of radial cycle*/
+ edok = bmesh_radial_validate(radlen, e->l);
+ if(!edok) bmesh_error();
+ edok = bmesh_radial_validate(radlen, ne->l);
+ if(!edok) bmesh_error();
+
+ /*verify loop->v and loop->next->v pointers for e*/
+ for(i=0,l=e->l; i < radlen; i++, l = l->radial_next){
+ if(!(l->e == e)) bmesh_error();
+ //if(!(l->radial_next == l)) bmesh_error();
+ if( ((BMLoop*)(l->prev))->e != ne && ((BMLoop*)(l->next))->e != ne) bmesh_error();
+ edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->next))->v, e);
+ if(!edok) bmesh_error();
+ if(l->v == ((BMLoop*)(l->next))->v) bmesh_error();
+ if(l->e == ((BMLoop*)(l->next))->e) bmesh_error();
+
+ /*verify loop cycle for kloop->f*/
+ CHECK_ELEMENT(bm, l);
+ CHECK_ELEMENT(bm, l->v);
+ CHECK_ELEMENT(bm, l->e);
+ CHECK_ELEMENT(bm, l->f);
+ }
+ /*verify loop->v and loop->next->v pointers for ne*/
+ for(i=0,l=ne->l; i < radlen; i++, l = l->radial_next){
+ if(!(l->e == ne)) bmesh_error();
+ //if(!(l->radial_next == l)) bmesh_error();
+ if( ((BMLoop*)(l->prev))->e != e && ((BMLoop*)(l->next))->e != e) bmesh_error();
+ edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->next))->v, ne);
+ if(!edok) bmesh_error();
+ if(l->v == ((BMLoop*)(l->next))->v) bmesh_error();
+ if(l->e == ((BMLoop*)(l->next))->e) bmesh_error();
+
+ CHECK_ELEMENT(bm, l);
+ CHECK_ELEMENT(bm, l->v);
+ CHECK_ELEMENT(bm, l->e);
+ CHECK_ELEMENT(bm, l->f);
+ }
+ }
+
+ CHECK_ELEMENT(bm, ne);
+ CHECK_ELEMENT(bm, nv);
+ CHECK_ELEMENT(bm, e);
+ CHECK_ELEMENT(bm, tv);
+
+ if(re) *re = ne;
+ return nv;
+}
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
new file mode 100644
index 00000000000..957a97b61fa
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -0,0 +1,1002 @@
+#include "bmesh.h"
+#include "bmesh_private.h"
+#include <stdio.h>
+
+/*
+This file defines (and documents) all bmesh operators (bmops).
+
+Do not rename any operator or slot names! otherwise you must go
+through the code and find all references to them!
+
+A word on slot names:
+
+For geometry input slots, the following are valid names:
+* verts
+* edges
+* faces
+* edgefacein
+* vertfacein
+* vertedgein
+* vertfacein
+* geom
+
+The basic rules are, for single-type geometry slots, use the plural of the
+type name (e.g. edges). for double-type slots, use the two type names plus
+"in" (e.g. edgefacein). for three-type slots, use geom.
+
+for output slots, for single-type geometry slots, use the type name plus "out",
+(e.g. vertout), for double-type slots, use the two type names plus "out",
+(e.g. vertfaceout), for three-type slots, use geom. note that you can also
+use more esohteric names (e.g. skirtout) do long as the comment next to the
+slot definition tells you what types of elements are in it.
+
+*/
+
+/*
+ok, I'm going to write a little docgen script. so all
+bmop comments must conform to the following template/rules:
+
+template (py quotes used because nested comments don't work
+on all C compilers):
+
+"""
+Region Extend.
+
+paragraph1, Extends bleh bleh bleh.
+Bleh Bleh bleh.
+
+Another paragraph.
+
+Another paragraph.
+"""
+
+so the first line is the "title" of the bmop.
+subsequent line blocks seperated by blank lines
+are paragraphs. individual descriptions of slots
+would be extracted from comments
+next to them, e.g.
+
+{BMOP_OPSLOT_ELEMENT_BUF, "geomout"}, //output slot, boundary region
+
+the doc generator would automatically detect the presence of "output slot"
+and flag the slot as an output. the same happens for "input slot". also
+note that "edges", "faces", "verts", "loops", and "geometry" are valid
+substitutions for "slot".
+
+note that slots default to being input slots.
+*/
+
+/*
+ Vertex Smooth
+
+ Smoothes vertices by using a basic vertex averaging scheme.
+*/
+BMOpDefine def_vertexsmooth = {
+ "vertexsmooth",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"}, //input vertices
+ {BMOP_OPSLOT_INT, "mirror_clip_x"}, //set vertices close to the x axis before the operation to 0
+ {BMOP_OPSLOT_INT, "mirror_clip_y"}, //set vertices close to the y axis before the operation to 0
+ {BMOP_OPSLOT_INT, "mirror_clip_z"}, //set vertices close to the z axis before the operation to 0
+ {BMOP_OPSLOT_FLT, "clipdist"}, //clipping threshod for the above three slots
+ {0} /*null-terminating sentinel*/,
+ },
+ bmesh_vertexsmooth_exec,
+ 0
+};
+
+/*
+ Right-Hand Faces
+
+ Computes an "outside" normal for the specified input faces.
+*/
+
+BMOpDefine def_righthandfaces = {
+ "righthandfaces",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "faces"},
+ {0} /*null-terminating sentinel*/,
+ },
+ bmesh_righthandfaces_exec,
+ 0
+};
+
+/*
+ Region Extend
+
+ used to implement the select more/less tools.
+ this puts some geometry surrounding regions of
+ geometry in geom into geomout.
+
+ if usefaces is 0 then geomout spits out verts and edges,
+ otherwise it spits out faces.
+ */
+BMOpDefine def_regionextend = {
+ "regionextend",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "geom"}, //input geometry
+ {BMOP_OPSLOT_ELEMENT_BUF, "geomout"}, //output slot, computed boundary geometry.
+ {BMOP_OPSLOT_INT, "constrict"}, //find boundary inside the regions, not outside.
+ {BMOP_OPSLOT_INT, "usefaces"}, //extend from faces instead of edges
+ {0} /*null-terminating sentinel*/,
+ },
+ bmesh_regionextend_exec,
+ 0
+};
+
+/*
+ Edge Rotate
+
+ Rotates edges topologically. Also known as "spin edge" to some people.
+ Simple example: [/] becomes [|] then [\].
+*/
+BMOpDefine def_edgerotate = {
+ "edgerotate",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, //input edges
+ {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"}, //newly spun edges
+ {BMOP_OPSLOT_INT, "ccw"}, //rotate edge counter-clockwise if true, othewise clockwise
+ {0} /*null-terminating sentinel*/,
+ },
+ bmesh_edgerotate_exec,
+ 0
+};
+
+/*
+ Reverse Faces
+
+ Reverses the winding (vertex order) of faces. This has the effect of
+ flipping the normal.
+*/
+BMOpDefine def_reversefaces = {
+ "reversefaces",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "faces"}, //input faces
+ {0} /*null-terminating sentinel*/,
+ },
+ bmesh_reversefaces_exec,
+ 0
+};
+
+/*
+ Edge Bisect
+
+ Splits input edges (but doesn't do anything else).
+ This creates a 2-valence vert.
+*/
+BMOpDefine def_edgebisect = {
+ "edgebisect",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, //input edges
+ {BMOP_OPSLOT_INT, "numcuts"}, //number of cuts
+ {BMOP_OPSLOT_ELEMENT_BUF, "outsplit"}, //newly created vertices and edges
+ {0} /*null-terminating sentinel*/,
+ },
+ esplit_exec,
+ 0
+};
+
+/*
+ Mirror
+
+ Mirrors geometry along an axis. The resulting geometry is welded on using
+ mergedist. Pairs of original/mirrored vertices are welded using the mergedist
+ parameter (which defines the minimum distance for welding to happen).
+*/
+
+BMOpDefine def_mirror = {
+ "mirror",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "geom"}, //input geometry
+ {BMOP_OPSLOT_MAT, "mat"}, //matrix defining the mirror transformation
+ {BMOP_OPSLOT_FLT, "mergedist"}, //maximum distance for merging. does no merging if 0.
+ {BMOP_OPSLOT_ELEMENT_BUF, "newout"}, //output geometry, mirrored
+ {BMOP_OPSLOT_INT, "axis"}, //the axis to use, 0, 1, or 2 for x, y, z
+ {BMOP_OPSLOT_INT, "mirror_u"}, //mirror UVs across the u axis
+ {BMOP_OPSLOT_INT, "mirror_v"}, //mirror UVs across the v axis
+ {0, /*null-terminating sentinel*/}},
+ bmesh_mirror_exec,
+ 0,
+};
+
+/*
+ Find Doubles
+
+ Takes input verts and find vertices they should weld to. Outputs a
+ mapping slot suitable for use with the weld verts bmop.
+*/
+BMOpDefine def_finddoubles = {
+ "finddoubles",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"}, //input vertices
+ {BMOP_OPSLOT_ELEMENT_BUF, "keepverts"}, //list of verts to keep
+ {BMOP_OPSLOT_FLT, "dist"}, //minimum distance
+ {BMOP_OPSLOT_MAPPING, "targetmapout"},
+ {0, /*null-terminating sentinel*/}},
+ bmesh_finddoubles_exec,
+ 0,
+};
+
+/*
+ Remove Doubles
+
+ Finds groups of vertices closer then dist and merges them together,
+ using the weld verts bmop.
+*/
+BMOpDefine def_removedoubles = {
+ "removedoubles",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"}, //input verts
+ {BMOP_OPSLOT_FLT, "dist"}, //minimum distance
+ {0, /*null-terminating sentinel*/}},
+ bmesh_removedoubles_exec,
+ 0,
+};
+
+/*
+ Auto Merge
+
+ Finds groups of vertices closer then dist and merges them together,
+ using the weld verts bmop. The merges must go from a vert not in
+ verts to one in verts.
+*/
+BMOpDefine def_automerge = {
+ "automerge",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"}, //input verts
+ {BMOP_OPSLOT_FLT, "dist"}, //minimum distance
+ {0, /*null-terminating sentinel*/}},
+ bmesh_automerge_exec,
+ 0,
+};
+
+/*
+ Collapse Connected
+
+ Collapses connected vertices
+*/
+BMOpDefine def_collapse = {
+ "collapse",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, /*input edges*/
+ {0, /*null-terminating sentinel*/}},
+ bmesh_collapse_exec,
+ 0,
+};
+
+
+/*
+ Facedata point Merge
+
+ Merge uv/vcols at a specific vertex.
+*/
+BMOpDefine def_pointmerge_facedata = {
+ "pointmerge_facedata",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"}, /*input vertices*/
+ {BMOP_OPSLOT_ELEMENT_BUF, "snapv"}, /*snap vertex*/
+ {0, /*null-terminating sentinel*/}},
+ bmesh_pointmerge_facedata_exec,
+ 0,
+};
+
+/*
+ Average Vertices Facevert Data
+
+ Merge uv/vcols associated with the input vertices at
+ the bounding box center. (I know, it's not averaging but
+ the vert_snap_to_bb_center is just too long).
+*/
+BMOpDefine def_vert_average_facedata = {
+ "vert_average_facedata",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"}, /*input vertices*/
+ {0, /*null-terminating sentinel*/}},
+ bmesh_vert_average_facedata_exec,
+ 0,
+};
+
+/*
+ Point Merge
+
+ Merge verts together at a point.
+*/
+BMOpDefine def_pointmerge = {
+ "pointmerge",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"}, /*input vertices*/
+ {BMOP_OPSLOT_VEC, "mergeco"},
+ {0, /*null-terminating sentinel*/}},
+ bmesh_pointmerge_exec,
+ 0,
+};
+
+/*
+ Collapse Connected UVs
+
+ Collapses connected UV vertices.
+*/
+BMOpDefine def_collapse_uvs = {
+ "collapse_uvs",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, /*input edges*/
+ {0, /*null-terminating sentinel*/}},
+ bmesh_collapsecon_exec,
+ 0,
+};
+
+/*
+ Weld Verts
+
+ Welds verts together (kindof like remove doubles, merge, etc, all of which
+ use or will use this bmop). You pass in mappings from vertices to the vertices
+ they weld with.
+*/
+BMOpDefine def_weldverts = {
+ "weldverts",
+ {{BMOP_OPSLOT_MAPPING, "targetmap"}, /*maps welded vertices to verts they should weld to.*/
+ {0, /*null-terminating sentinel*/}},
+ bmesh_weldverts_exec,
+ 0,
+};
+
+/*
+ Make Vertex
+
+ Creates a single vertex; this bmop was necassary
+ for click-create-vertex.
+*/
+BMOpDefine def_makevert = {
+ "makevert",
+ {{BMOP_OPSLOT_VEC, "co"}, //the coordinate of the new vert
+ {BMOP_OPSLOT_ELEMENT_BUF, "newvertout"}, //the new vert
+ {0, /*null-terminating sentinel*/}},
+ bmesh_makevert_exec,
+ 0,
+};
+
+/*
+ Join Triangles
+
+ Tries to intelligently join triangles according
+ to various settings and stuff.
+
+ */
+BMOpDefine def_join_triangles= {
+ "join_triangles",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "faces"}, //input geometry.
+ {BMOP_OPSLOT_ELEMENT_BUF, "faceout"}, //joined faces
+ {BMOP_OPSLOT_INT, "compare_sharp"},
+ {BMOP_OPSLOT_INT, "compare_uvs"},
+ {BMOP_OPSLOT_INT, "compare_vcols"},
+ {BMOP_OPSLOT_INT, "compare_materials"},
+ {BMOP_OPSLOT_FLT, "limit"},
+ {0, /*null-terminating sentinel*/}},
+ bmesh_jointriangles_exec,
+ 0,
+};
+
+/*
+ Contextual Create
+
+ This is basically fkey, it creates
+ new faces from vertices, makes stuff from edge nets,
+ makes wire edges, etc. It also dissolves
+ faces.
+
+ Three verts become a triangle, four become a quad. Two
+ become a wire edge.
+ */
+BMOpDefine def_contextual_create= {
+ "contextual_create",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "geom"}, //input geometry.
+ {BMOP_OPSLOT_ELEMENT_BUF, "faceout"}, //newly-made face(s)
+ {0, /*null-terminating sentinel*/}},
+ bmesh_contextual_create_exec,
+ 0,
+};
+
+BMOpDefine def_edgenet_fill= {
+ "edgenet_fill",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, /*input edges*/
+ {BMOP_OPSLOT_MAPPING, "restrict"}, /*restricts edges to groups. maps edges to integers*/
+ {BMOP_OPSLOT_INT, "use_restrict"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "excludefaces"}, /*list of faces to ignore for manifold checks*/
+ {BMOP_OPSLOT_MAPPING, "faceout_groupmap"}, /*maps new faces to the group numbers they came from*/
+ {BMOP_OPSLOT_ELEMENT_BUF, "faceout"}, /*new faces*/
+ {0, /*null-terminating sentinel*/}},
+ bmesh_edgenet_fill_exec,
+ 0,
+};
+
+/*
+ Edgenet Prepare
+
+ Identifies several useful edge loop cases and modifies them so
+ they'll become a face when edgenet_fill is called. The cases covered are:
+
+ * One single loop; an edge is added to connect the ends
+ * Two loops; two edges are added to connect the endpoints (based on the
+ shortest distance between each endpont).
+*/
+BMOpDefine def_edgenet_prepare= {
+ "edgenet_prepare",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, //input edges
+ {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"}, //new edges
+ {0, /*null-terminating sentinel*/}},
+ bmesh_edgenet_prepare,
+ 0,
+};
+
+/*
+ Rotate
+
+ Rotate vertices around a center, using a 3x3 rotation
+ matrix. Equivilent of the old rotateflag function.
+*/
+BMOpDefine def_rotate = {
+ "rotate",
+ {{BMOP_OPSLOT_VEC, "cent"}, //center of rotation
+ {BMOP_OPSLOT_MAT, "mat"}, //matrix defining rotation
+ {BMOP_OPSLOT_ELEMENT_BUF, "verts"}, //input vertices
+ {0, /*null-terminating sentinel*/}},
+ bmesh_rotate_exec,
+ 0,
+};
+
+/*
+ Translate
+
+ Translate vertices by an offset. Equivelent of the
+ old translateflag function.
+*/
+BMOpDefine def_translate= {
+ "translate",
+ {{BMOP_OPSLOT_VEC, "vec"}, //translation offset
+ {BMOP_OPSLOT_ELEMENT_BUF, "verts"}, //input vertices
+ {0, /*null-terminating sentinel*/}},
+ bmesh_translate_exec,
+ 0,
+};
+
+/*
+ Scale
+
+ Scales vertices by an offset.
+*/
+BMOpDefine def_scale= {
+ "scale",
+ {{BMOP_OPSLOT_VEC, "vec"}, //scale factor
+ {BMOP_OPSLOT_ELEMENT_BUF, "verts"}, //input vertices
+ {0, /*null-terminating sentinel*/}},
+ bmesh_scale_exec,
+ 0,
+};
+
+
+/*
+ Transform
+
+ Transforms a set of vertices by a matrix. Multiplies
+ the vertex coordinates with the matrix.
+*/
+BMOpDefine def_transform = {
+ "transform",
+ {{BMOP_OPSLOT_MAT, "mat"}, //transform matrix
+ {BMOP_OPSLOT_ELEMENT_BUF, "verts"}, //input vertices
+ {0, /*null-terminating sentinel*/}},
+ bmesh_transform_exec,
+ 0,
+};
+
+/*
+ Object Load BMesh
+
+ Loads a bmesh into an object/mesh. This is a "private"
+ bmop.
+*/
+BMOpDefine def_object_load_bmesh = {
+ "object_load_bmesh",
+ {{BMOP_OPSLOT_PNT, "scene"},
+ {BMOP_OPSLOT_PNT, "object"},
+ {0, /*null-terminating sentinel*/}},
+ object_load_bmesh_exec,
+ 0,
+};
+
+
+/*
+ BMesh to Mesh
+
+ Converts a bmesh to a Mesh. This is reserved for exiting editmode.
+*/
+BMOpDefine def_bmesh_to_mesh = {
+ "bmesh_to_mesh",
+ {{BMOP_OPSLOT_PNT, "mesh"}, //pointer to a mesh structure to fill in
+ {BMOP_OPSLOT_PNT, "object"}, //pointer to an object structure
+ {BMOP_OPSLOT_INT, "notesselation"}, //don't calculate mfaces
+ {0, /*null-terminating sentinel*/}},
+ bmesh_to_mesh_exec,
+ 0,
+};
+
+/*
+ Mesh to BMesh
+
+ Load the contents of a mesh into the bmesh. this bmop is private, it's
+ reserved exclusively for entering editmode.
+*/
+BMOpDefine def_mesh_to_bmesh = {
+ "mesh_to_bmesh",
+ {{BMOP_OPSLOT_PNT, "mesh"}, //pointer to a Mesh structure
+ {BMOP_OPSLOT_PNT, "object"}, //pointer to an Object structure
+ {0, /*null-terminating sentinel*/}},
+ mesh_to_bmesh_exec,
+ 0
+};
+
+/*
+ Individual Face Extrude
+
+ Extrudes faces individually.
+*/
+BMOpDefine def_extrude_indivface = {
+ "extrude_face_indiv",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "faces"}, //input faces
+ {BMOP_OPSLOT_ELEMENT_BUF, "faceout"}, //output faces
+ {BMOP_OPSLOT_ELEMENT_BUF, "skirtout"}, //output skirt geometry, faces and edges
+ {0} /*null-terminating sentinel*/},
+ bmesh_extrude_face_indiv_exec,
+ 0
+};
+
+/*
+ Extrude Only Edges
+
+ Extrudes Edges into faces, note that this is very simple, there's no fancy
+ winged extrusion.
+*/
+BMOpDefine def_extrude_onlyedge = {
+ "extrude_edge_only",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, //input vertices
+ {BMOP_OPSLOT_ELEMENT_BUF, "geomout"}, //output geometry
+ {0} /*null-terminating sentinel*/},
+ bmesh_extrude_onlyedge_exec,
+ 0
+};
+
+/*
+ Individual Vertex Extrude
+
+ Extrudes wire edges from vertices.
+*/
+BMOpDefine def_extrudeverts_indiv = {
+ "extrude_vert_indiv",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"}, //input vertices
+ {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"}, //output wire edges
+ {BMOP_OPSLOT_ELEMENT_BUF, "vertout"}, //output vertices
+ {0} /*null-terminating sentinel*/},
+ extrude_vert_indiv_exec,
+ 0
+};
+
+#if 0
+BMOpDefine def_makeprim = {
+ "makeprim",
+ {{BMOP_OPSLOT_INT, "type"},
+ {BMOP_OPSLOT_INT, "tot", /*rows/cols also applies to spheres*/
+ {BMOP_OPSLOT_INT, "seg",
+ {BMOP_OPSLOT_INT, "subdiv"},
+ {BMOP_OPSLOT_INT, "ext"},
+ {BMOP_OPSLOT_INT, "fill"},
+ {BMOP_OPSLOT_FLT, "dia"},
+ {BMOP_OPSLOT_FLT, "depth"},
+ {BMOP_OPSLOT_PNT, "mat"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "geomout"}, //won't be implemented right away
+ {0}}
+ makeprim_exec,
+ 0
+};
+#endif
+
+BMOpDefine def_connectverts = {
+ "connectverts",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"},
+ {0} /*null-terminating sentinel*/},
+ connectverts_exec,
+ 0
+};
+
+BMOpDefine def_extrudefaceregion = {
+ "extrudefaceregion",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edgefacein"},
+ {BMOP_OPSLOT_MAPPING, "exclude"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "geomout"},
+ {0} /*null-terminating sentinel*/},
+ extrude_edge_context_exec,
+ 0
+};
+
+BMOpDefine def_dissolvevertsop = {
+ "dissolveverts",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"},
+ {0} /*null-terminating sentinel*/},
+ dissolveverts_exec,
+ 0
+};
+
+BMOpDefine def_dissolveedgessop = {
+ "dissolveedges",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "regionout"},
+ {0} /*null-terminating sentinel*/},
+ dissolveedges_exec,
+ 0
+};
+
+BMOpDefine def_dissolveedgeloopsop = {
+ "dissolveedgeloop",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "regionout"},
+ {0} /*null-terminating sentinel*/},
+ dissolve_edgeloop_exec,
+ 0
+};
+
+BMOpDefine def_dissolvefacesop = {
+ "dissolvefaces",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "faces"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "regionout"},
+ {0} /*null-terminating sentinel*/},
+ dissolvefaces_exec,
+ 0
+};
+
+
+BMOpDefine def_triangop = {
+ "triangulate",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "faces"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "faceout"},
+ {BMOP_OPSLOT_MAPPING, "facemap"},
+ {0} /*null-terminating sentinel*/},
+ triangulate_exec,
+ 0
+};
+
+BMOpDefine def_subdop = {
+ "esubd",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"},
+ {BMOP_OPSLOT_INT, "numcuts"},
+ {BMOP_OPSLOT_FLT, "smooth"},
+ {BMOP_OPSLOT_FLT, "fractal"},
+ {BMOP_OPSLOT_INT, "beauty"},
+ {BMOP_OPSLOT_MAPPING, "custompatterns"},
+ {BMOP_OPSLOT_MAPPING, "edgepercents"},
+
+ /*these next three can have multiple types of elements in them.*/
+ {BMOP_OPSLOT_ELEMENT_BUF, "outinner"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "outsplit"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "geomout"}, /*contains all output geometry*/
+
+ {BMOP_OPSLOT_INT, "quadcornertype"}, //quad corner type, see bmesh_operators.h
+ {BMOP_OPSLOT_INT, "gridfill"}, //fill in fully-selected faces with a grid
+ {BMOP_OPSLOT_INT, "singleedge"}, //tesselate the case of one edge selected in a quad or triangle
+
+ {0} /*null-terminating sentinel*/,
+ },
+ esubdivide_exec,
+ 0
+};
+
+BMOpDefine def_delop = {
+ "del",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "geom"}, {BMOP_OPSLOT_INT, "context"},
+ {0} /*null-terminating sentinel*/},
+ delop_exec,
+ 0
+};
+
+BMOpDefine def_dupeop = {
+ "dupe",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "geom"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "origout"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "newout"},
+ /*facemap maps from source faces to dupe
+ faces, and from dupe faces to source faces.*/
+ {BMOP_OPSLOT_MAPPING, "facemap"},
+ {BMOP_OPSLOT_MAPPING, "boundarymap"},
+ {BMOP_OPSLOT_MAPPING, "isovertmap"},
+ {BMOP_OPSLOT_PNT, "dest"}, /*destination bmesh, if NULL will use current one*/
+ {0} /*null-terminating sentinel*/},
+ dupeop_exec,
+ 0
+};
+
+BMOpDefine def_splitop = {
+ "split",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "geom"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "geomout"},
+ {BMOP_OPSLOT_MAPPING, "boundarymap"},
+ {BMOP_OPSLOT_MAPPING, "isovertmap"},
+ {BMOP_OPSLOT_PNT, "dest"}, /*destination bmesh, if NULL will use current one*/
+ {0} /*null-terminating sentinel*/},
+ splitop_exec,
+ 0
+};
+
+/*
+ Similar faces search
+
+ Find similar faces (area/material/perimeter....).
+*/
+BMOpDefine def_similarfaces = {
+ "similarfaces",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "faces"}, /* input faces */
+ {BMOP_OPSLOT_ELEMENT_BUF, "faceout"}, /* output faces */
+ {BMOP_OPSLOT_INT, "type"}, /* type of selection */
+ {BMOP_OPSLOT_FLT, "thresh"}, /* threshold of selection */
+ {0} /*null-terminating sentinel*/},
+ bmesh_similarfaces_exec,
+ 0
+};
+
+/*
+ Similar edges search
+
+ Find similar edges (length, direction, edge, seam,....).
+*/
+BMOpDefine def_similaredges = {
+ "similaredges",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, /* input edges */
+ {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"}, /* output edges */
+ {BMOP_OPSLOT_INT, "type"}, /* type of selection */
+ {BMOP_OPSLOT_FLT, "thresh"}, /* threshold of selection */
+ {0} /*null-terminating sentinel*/},
+ bmesh_similaredges_exec,
+ 0
+};
+
+/*
+ Similar vertices search
+
+ Find similar vertices (normal, face, vertex group,....).
+*/
+BMOpDefine def_similarverts = {
+ "similarverts",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"}, /* input vertices */
+ {BMOP_OPSLOT_ELEMENT_BUF, "vertout"}, /* output vertices */
+ {BMOP_OPSLOT_INT, "type"}, /* type of selection */
+ {BMOP_OPSLOT_FLT, "thresh"}, /* threshold of selection */
+ {0} /*null-terminating sentinel*/},
+ bmesh_similarverts_exec,
+ 0
+};
+
+/*
+** uv rotation
+** cycle the uvs
+*/
+BMOpDefine def_meshrotateuvs = {
+ "meshrotateuvs",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "faces"}, /* input faces */
+ {BMOP_OPSLOT_INT, "dir"}, /* direction */
+ {0} /*null-terminating sentinel*/},
+ bmesh_rotateuvs_exec,
+ 0
+};
+
+/*
+** uv reverse
+** reverse the uvs
+*/
+BMOpDefine def_meshreverseuvs = {
+ "meshreverseuvs",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "faces"}, /* input faces */
+ {0} /*null-terminating sentinel*/},
+ bmesh_reverseuvs_exec,
+ 0
+};
+
+/*
+** color rotation
+** cycle the colors
+*/
+BMOpDefine def_meshrotatecolors = {
+ "meshrotatecolors",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "faces"}, /* input faces */
+ {BMOP_OPSLOT_INT, "dir"}, /* direction */
+ {0} /*null-terminating sentinel*/},
+ bmesh_rotatecolors_exec,
+ 0
+};
+
+/*
+** color reverse
+** reverse the colors
+*/
+BMOpDefine def_meshreversecolors = {
+ "meshreversecolors",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "faces"}, /* input faces */
+ {0} /*null-terminating sentinel*/},
+ bmesh_reversecolors_exec,
+ 0
+};
+
+/*
+ Similar vertices search
+
+ Find similar vertices (normal, face, vertex group,....).
+*/
+BMOpDefine def_vertexshortestpath = {
+ "vertexshortestpath",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "startv"}, /* start vertex */
+ {BMOP_OPSLOT_ELEMENT_BUF, "endv"}, /* end vertex */
+ {BMOP_OPSLOT_ELEMENT_BUF, "vertout"}, /* output vertices */
+ {BMOP_OPSLOT_INT, "type"}, /* type of selection */
+ {0} /*null-terminating sentinel*/},
+ bmesh_vertexshortestpath_exec,
+ 0
+};
+
+/*
+ Edge Split
+
+ Disconnects faces along input edges.
+ */
+BMOpDefine def_edgesplit = {
+ "edgesplit",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, /* input edges */
+ {BMOP_OPSLOT_ELEMENT_BUF, "edgeout1"}, /* old output disconnected edges */
+ {BMOP_OPSLOT_ELEMENT_BUF, "edgeout2"}, /* new output disconnected edges */
+ {0} /*null-terminating sentinel*/},
+ bmesh_edgesplitop_exec,
+ 0
+};
+
+/*
+ Create Grid
+
+ Creates a grid with a variable number of subdivisions
+*/
+BMOpDefine def_create_grid = {
+ "create_grid",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "vertout"}, //output verts
+ {BMOP_OPSLOT_INT, "xsegments"}, //number of x segments
+ {BMOP_OPSLOT_INT, "ysegments"}, //number of y segments
+ {BMOP_OPSLOT_FLT, "size"}, //size of the grid
+ {BMOP_OPSLOT_MAT, "mat"}, //matrix to multiply the new geometry with
+ {0, /*null-terminating sentinel*/}},
+ bmesh_create_grid_exec,
+ 0,
+};
+
+/*
+ Create UV Sphere
+
+ Creates a grid with a variable number of subdivisions
+*/
+BMOpDefine def_create_uvsphere = {
+ "create_uvsphere",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "vertout"}, //output verts
+ {BMOP_OPSLOT_INT, "segments"}, //number of u segments
+ {BMOP_OPSLOT_INT, "revolutions"}, //number of v segment
+ {BMOP_OPSLOT_FLT, "diameter"}, //diameter
+ {BMOP_OPSLOT_MAT, "mat"}, //matrix to multiply the new geometry with--
+ {0, /*null-terminating sentinel*/}},
+ bmesh_create_uvsphere_exec,
+ 0,
+};
+
+/*
+ Create Ico Sphere
+
+ Creates a grid with a variable number of subdivisions
+*/
+BMOpDefine def_create_icosphere = {
+ "create_icosphere",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "vertout"}, //output verts
+ {BMOP_OPSLOT_INT, "subdivisions"}, //how many times to recursively subdivide the sphere
+ {BMOP_OPSLOT_FLT, "diameter"}, //diameter
+ {BMOP_OPSLOT_MAT, "mat"}, //matrix to multiply the new geometry with
+ {0, /*null-terminating sentinel*/}},
+ bmesh_create_icosphere_exec,
+ 0,
+};
+
+/*
+ Create Suzanne
+
+ Creates a monkey. Be wary.
+*/
+BMOpDefine def_create_monkey = {
+ "create_monkey",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "vertout"}, //output verts
+ {BMOP_OPSLOT_MAT, "mat"}, //matrix to multiply the new geometry with--
+ {0, /*null-terminating sentinel*/}},
+ bmesh_create_monkey_exec,
+ 0,
+};
+
+/*
+ Create Cone
+
+ Creates a cone with variable depth at both ends
+*/
+BMOpDefine def_create_cone = {
+ "create_cone",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "vertout"}, //output verts
+ {BMOP_OPSLOT_INT, "cap_ends"}, //wheter or not to fill in the ends with faces
+ {BMOP_OPSLOT_INT, "segments"},
+ {BMOP_OPSLOT_FLT, "diameter1"}, //diameter of one end
+ {BMOP_OPSLOT_FLT, "diameter2"}, //diameter of the opposite
+ {BMOP_OPSLOT_FLT, "depth"}, //distance between ends
+ {BMOP_OPSLOT_MAT, "mat"}, //matrix to multiply the new geometry with--
+ {0, /*null-terminating sentinel*/}},
+ bmesh_create_cone_exec,
+ 0,
+};
+
+/*
+ Create Cone
+
+ Creates a cone with variable depth at both ends
+*/
+BMOpDefine def_create_cube = {
+ "create_cube",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "vertout"}, //output verts
+ {BMOP_OPSLOT_FLT, "size"}, //size of the cube
+ {BMOP_OPSLOT_MAT, "mat"}, //matrix to multiply the new geometry with--
+ {0, /*null-terminating sentinel*/}},
+ bmesh_create_cube_exec,
+ 0,
+};
+
+BMOpDefine *opdefines[] = {
+ &def_splitop,
+ &def_dupeop,
+ &def_delop,
+ &def_subdop,
+ &def_triangop,
+ &def_dissolvefacesop,
+ &def_dissolveedgessop,
+ &def_dissolveedgeloopsop,
+ &def_dissolvevertsop,
+ &def_extrudefaceregion,
+ &def_connectverts,
+ //&def_makeprim,
+ &def_extrudeverts_indiv,
+ &def_mesh_to_bmesh,
+ &def_object_load_bmesh,
+ &def_transform,
+ &def_translate,
+ &def_rotate,
+ &def_edgenet_fill,
+ &def_contextual_create,
+ &def_makevert,
+ &def_weldverts,
+ &def_removedoubles,
+ &def_finddoubles,
+ &def_mirror,
+ &def_edgebisect,
+ &def_reversefaces,
+ &def_edgerotate,
+ &def_regionextend,
+ &def_righthandfaces,
+ &def_vertexsmooth,
+ &def_extrude_onlyedge,
+ &def_extrude_indivface,
+ &def_collapse_uvs,
+ &def_pointmerge,
+ &def_collapse,
+ &def_similarfaces,
+ &def_similaredges,
+ &def_similarverts,
+ &def_pointmerge_facedata,
+ &def_vert_average_facedata,
+ &def_meshrotateuvs,
+ &def_bmesh_to_mesh,
+ &def_meshreverseuvs,
+ &def_edgenet_prepare,
+ &def_meshrotatecolors,
+ &def_meshreversecolors,
+ &def_vertexshortestpath,
+ &def_scale,
+ &def_edgesplit,
+ &def_automerge,
+ &def_create_uvsphere,
+ &def_create_grid,
+ &def_create_icosphere,
+ &def_create_monkey,
+ &def_create_cone,
+ &def_create_cube,
+ &def_join_triangles,
+};
+
+int bmesh_total_ops = (sizeof(opdefines) / sizeof(void*));
diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c
new file mode 100644
index 00000000000..d193f62d2ad
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -0,0 +1,1338 @@
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_mempool.h"
+#include "BLI_blenlib.h"
+#include "BLI_array.h"
+
+#include "BKE_utildefines.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+#include "stdarg.h"
+
+#include <string.h>
+
+/*forward declarations*/
+static void alloc_flag_layer(BMesh *bm);
+static void free_flag_layer(BMesh *bm);
+static void clear_flag_layer(BMesh *bm);
+static int bmesh_name_to_slotcode(BMOpDefine *def, const char *name);
+static int bmesh_opname_to_opcode(const char *opname);
+
+static const char *bmop_error_messages[] = {
+ 0,
+ "Self intersection error",
+ "Could not dissolve vert",
+ "Could not connect vertices",
+ "Could not traverse mesh",
+ "Could not dissolve faces",
+ "Could not dissolve vertices",
+ "Tesselation error",
+ "Can not deal with non-manifold geometry",
+ "Invalid selection",
+};
+
+
+/*operator slot type information - size of one element of the type given.*/
+const int BMOP_OPSLOT_TYPEINFO[] = {
+ 0,
+ sizeof(int),
+ sizeof(float),
+ sizeof(void*),
+ 0, /* unused */
+ 0, /* unused */
+ 0, /* unused */
+ sizeof(void*), /* pointer buffer */
+ sizeof(element_mapping)
+};
+
+/*
+ * BMESH OPSTACK PUSH
+ *
+ * Pushes the opstack down one level
+ * and allocates a new flag layer if
+ * appropriate.
+ *
+*/
+
+void BMO_push(BMesh *bm, BMOperator *op)
+{
+ bm->stackdepth++;
+
+ /*add flag layer, if appropriate*/
+ if (bm->stackdepth > 1)
+ alloc_flag_layer(bm);
+ else
+ clear_flag_layer(bm);
+}
+
+/*
+ * BMESH OPSTACK POP
+ *
+ * Pops the opstack one level
+ * and frees a flag layer if appropriate
+ * TODO: investigate NOT freeing flag
+ * layers.
+ *
+*/
+void BMO_pop(BMesh *bm)
+{
+ if(bm->stackdepth > 1)
+ free_flag_layer(bm);
+
+ bm->stackdepth--;
+}
+
+/*
+ * BMESH OPSTACK INIT OP
+ *
+ * Initializes an operator structure
+ * to a certain type
+ *
+*/
+
+void BMO_Init_Op(BMOperator *op, const char *opname)
+{
+ int i, opcode = bmesh_opname_to_opcode(opname);
+
+ memset(op, 0, sizeof(BMOperator));
+ op->type = opcode;
+
+ /*initialize the operator slot types*/
+ for(i = 0; opdefines[opcode]->slottypes[i].type; i++) {
+ op->slots[i].slottype = opdefines[opcode]->slottypes[i].type;
+ op->slots[i].index = i;
+ }
+
+ /*callback*/
+ op->exec = opdefines[opcode]->exec;
+
+ /*memarena, used for operator's slot buffers*/
+ op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "bmesh operator");
+ BLI_memarena_use_calloc (op->arena);
+}
+
+/*
+ * BMESH OPSTACK EXEC OP
+ *
+ * Executes a passed in operator. This handles
+ * the allocation and freeing of temporary flag
+ * layers and starting/stopping the modelling
+ * loop. Can be called from other operators
+ * exec callbacks as well.
+ *
+*/
+
+void BMO_Exec_Op(BMesh *bm, BMOperator *op)
+{
+
+ BMO_push(bm, op);
+
+ if(bm->stackdepth == 2)
+ bmesh_begin_edit(bm);
+ op->exec(bm, op);
+
+ if(bm->stackdepth == 2)
+ bmesh_end_edit(bm,0);
+
+ BMO_pop(bm);
+}
+
+/*
+ * BMESH OPSTACK FINISH OP
+ *
+ * Does housekeeping chores related to finishing
+ * up an operator.
+ *
+*/
+
+void BMO_Finish_Op(BMesh *bm, BMOperator *op)
+{
+ BMOpSlot *slot;
+ int i;
+
+ for (i=0; opdefines[op->type]->slottypes[i].type; i++) {
+ slot = &op->slots[i];
+ if (slot->slottype == BMOP_OPSLOT_MAPPING) {
+ if (slot->data.ghash)
+ BLI_ghash_free(slot->data.ghash, NULL, NULL);
+ }
+ }
+
+ BLI_memarena_free(op->arena);
+}
+
+/*
+ * BMESH OPSTACK GET SLOT
+ *
+ * Returns a pointer to the slot of
+ * type 'slotcode'
+ *
+*/
+
+BMOpSlot *BMO_GetSlot(BMOperator *op, const char *slotname)
+{
+ int slotcode = bmesh_name_to_slotcode(opdefines[op->type], slotname);
+
+ return &(op->slots[slotcode]);
+}
+
+/*
+ * BMESH OPSTACK COPY SLOT
+ *
+ * Copies data from one slot to another
+ *
+*/
+
+void BMO_CopySlot(BMOperator *source_op, BMOperator *dest_op, const char *src, const char *dst)
+{
+ BMOpSlot *source_slot = BMO_GetSlot(source_op, src);
+ BMOpSlot *dest_slot = BMO_GetSlot(dest_op, dst);
+
+ if(source_slot == dest_slot)
+ return;
+
+ if(source_slot->slottype != dest_slot->slottype)
+ return;
+
+ if (dest_slot->slottype > BMOP_OPSLOT_VEC) {
+ if (dest_slot->slottype != BMOP_OPSLOT_MAPPING) {
+ /*do buffer copy*/
+ dest_slot->data.buf = NULL;
+ dest_slot->len = source_slot->len;
+ if(dest_slot->len){
+ dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len);
+ memcpy(dest_slot->data.buf, source_slot->data.buf, BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len);
+ }
+ } else {
+ GHashIterator it;
+ element_mapping *srcmap, *dstmap;
+
+ /*sanity check*/
+ if (!source_slot->data.ghash) return;
+
+ if (!dest_slot->data.ghash) {
+ dest_slot->data.ghash =
+ BLI_ghash_new(BLI_ghashutil_ptrhash,
+ BLI_ghashutil_ptrcmp, "bmesh operator 2");
+ }
+
+ BLI_ghashIterator_init(&it, source_slot->data.ghash);
+ for (;srcmap=BLI_ghashIterator_getValue(&it);
+ BLI_ghashIterator_step(&it))
+ {
+ dstmap = BLI_memarena_alloc(dest_op->arena,
+ sizeof(*dstmap) + srcmap->len);
+
+ dstmap->element = srcmap->element;
+ dstmap->len = srcmap->len;
+ memcpy(dstmap+1, srcmap+1, srcmap->len);
+
+ BLI_ghash_insert(dest_slot->data.ghash,
+ dstmap->element, dstmap);
+ }
+ }
+ } else {
+ dest_slot->data = source_slot->data;
+ }
+}
+
+/*
+ * BMESH OPSTACK SET XXX
+ *
+ * Sets the value of a slot depending on it's type
+ *
+*/
+
+
+void BMO_Set_Float(BMOperator *op, const char *slotname, float f)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_FLT) )
+ return;
+
+ slot->data.f = f;
+}
+
+void BMO_Set_Int(BMOperator *op, const char *slotname, int i)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_INT) )
+ return;
+
+ slot->data.i = i;
+}
+
+/*only supports square mats*/
+void BMO_Set_Mat(struct BMOperator *op, const char *slotname, float *mat, int size)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_MAT) )
+ return;
+
+ slot->len = 4;
+ slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float)*4*4);
+
+ if (size == 4) {
+ memcpy(slot->data.p, mat, sizeof(float)*4*4);
+ } else if (size == 3) {
+ copy_m4_m3(slot->data.p, mat);
+ } else {
+ printf("yeek! invalid size in BMO_Set_Mat!\n");
+
+ memset(slot->data.p, 0, sizeof(float)*4*4);
+ return;
+ }
+}
+
+void BMO_Get_Mat4(struct BMOperator *op, const char *slotname, float mat[4][4])
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_MAT) )
+ return;
+
+ memcpy(mat, slot->data.p, sizeof(float)*4*4);
+}
+
+void BMO_Get_Mat3(struct BMOperator *op, const char *slotname, float mat[3][3])
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_MAT) )
+ return;
+
+ copy_m3_m4(mat, slot->data.p);
+}
+
+void BMO_Set_Pnt(BMOperator *op, const char *slotname, void *p)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_PNT) )
+ return;
+
+ slot->data.p = p;
+}
+
+void BMO_Set_Vec(BMOperator *op, const char *slotname, float *vec)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_VEC) )
+ return;
+
+ copy_v3_v3(slot->data.vec, vec);
+}
+
+
+float BMO_Get_Float(BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_FLT) )
+ return 0.0f;
+
+ return slot->data.f;
+}
+
+int BMO_Get_Int(BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_INT) )
+ return 0;
+
+ return slot->data.i;
+}
+
+
+void *BMO_Get_Pnt(BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_PNT) )
+ return NULL;
+
+ return slot->data.p;
+}
+
+void BMO_Get_Vec(BMOperator *op, const char *slotname, float *vec_out)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_VEC) )
+ return;
+
+ copy_v3_v3(vec_out, slot->data.vec);
+}
+
+/*
+ * BMO_COUNTFLAG
+ *
+ * Counts the number of elements of a certain type that
+ * have a specific flag set.
+ *
+*/
+
+int BMO_CountFlag(BMesh *bm, int flag, int type)
+{
+ BMIter elements;
+ BMHeader *e;
+ int count = 0;
+
+ if(type & BM_VERT){
+ for(e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)){
+ if(BMO_TestFlag(bm, e, flag))
+ count++;
+ }
+ }
+ if(type & BM_EDGE){
+ for(e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)){
+ if(BMO_TestFlag(bm, e, flag))
+ count++;
+ }
+ }
+ if(type & BM_FACE){
+ for(e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)){
+ if(BMO_TestFlag(bm, e, flag))
+ count++;
+ }
+ }
+
+ return count;
+}
+
+void BMO_Clear_Flag_All(BMesh *bm, BMOperator *op, int type, int flag) {
+ BMIter iter;
+ BMHeader *ele;
+ int i=0, types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
+
+ for (i=0; i<3; i++) {
+ if (i==0 && !(type & BM_VERT))
+ continue;
+ if (i==1 && !(type & BM_EDGE))
+ continue;
+ if (i==2 && !(type & BM_FACE))
+ continue;
+
+ BM_ITER(ele, &iter, bm, types[i], NULL) {
+ BMO_ClearFlag(bm, ele, flag);
+ }
+ }
+}
+
+int BMO_CountSlotBuf(struct BMesh *bm, struct BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+
+ /*check if its actually a buffer*/
+ if( !(slot->slottype > BMOP_OPSLOT_VEC) )
+ return 0;
+
+ return slot->len;
+}
+
+int BMO_CountSlotMap(BMesh *bm, BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+
+ /*check if its actually a buffer*/
+ if( !(slot->slottype == BMOP_OPSLOT_MAPPING) )
+ return 0;
+
+ return slot->data.ghash ? BLI_ghash_size(slot->data.ghash) : 0;
+}
+
+#if 0
+void *BMO_Grow_Array(BMesh *bm, BMOperator *op, int slotcode, int totadd) {
+ BMOpSlot *slot = &op->slots[slotcode];
+ void *tmp;
+
+ /*check if its actually a buffer*/
+ if( !(slot->slottype > BMOP_OPSLOT_VEC) )
+ return NULL;
+
+ if (slot->flag & BMOS_DYNAMIC_ARRAY) {
+ if (slot->len >= slot->size) {
+ slot->size = (slot->size+1+totadd)*2;
+
+ tmp = slot->data.buf;
+ slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size, "opslot dynamic array");
+ memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size);
+ MEM_freeN(tmp);
+ }
+
+ slot->len += totadd;
+ } else {
+ slot->flag |= BMOS_DYNAMIC_ARRAY;
+ slot->len += totadd;
+ slot->size = slot->len+2;
+ tmp = slot->data.buf;
+ slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len, "opslot dynamic array");
+ memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len);
+ }
+
+ return slot->data.buf;
+}
+#endif
+
+void BMO_Mapping_To_Flag(struct BMesh *bm, struct BMOperator *op,
+ const char *slotname, int flag)
+{
+ GHashIterator it;
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ BMHeader *ele;
+
+ /*sanity check*/
+ if (slot->slottype != BMOP_OPSLOT_MAPPING) return;
+ if (!slot->data.ghash) return;
+
+ BLI_ghashIterator_init(&it, slot->data.ghash);
+ for (;ele=BLI_ghashIterator_getKey(&it);BLI_ghashIterator_step(&it)) {
+ BMO_SetFlag(bm, ele, flag);
+ }
+}
+
+static void *alloc_slot_buffer(BMOperator *op, const char *slotname, int len){
+ int slotcode = bmesh_name_to_slotcode(opdefines[op->type], slotname);
+
+ /*check if its actually a buffer*/
+ if( !(op->slots[slotcode].slottype > BMOP_OPSLOT_VEC) )
+ return NULL;
+
+ op->slots[slotcode].len = len;
+ if(len)
+ op->slots[slotcode].data.buf = BLI_memarena_alloc(op->arena, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * len);
+ return op->slots[slotcode].data.buf;
+}
+
+
+/*
+ *
+ * BMO_ALL_TO_SLOT
+ *
+ * Copies all elements of a certain type into an operator slot.
+ *
+*/
+
+void BMO_All_To_Slot(BMesh *bm, BMOperator *op, const char *slotname, int type)
+{
+ BMIter elements;
+ BMHeader *e;
+ BMOpSlot *output = BMO_GetSlot(op, slotname);
+ int totelement=0, i=0;
+
+ if (type & BM_VERT) totelement += bm->totvert;
+ if (type & BM_EDGE) totelement += bm->totedge;
+ if (type & BM_FACE) totelement += bm->totface;
+
+ if(totelement){
+ alloc_slot_buffer(op, slotname, totelement);
+
+ if (type & BM_VERT) {
+ for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+
+ if (type & BM_EDGE) {
+ for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+
+ if (type & BM_FACE) {
+ for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+}
+
+/*
+ *
+ * BMO_HEADERFLAG_TO_SLOT
+ *
+ * Copies elements of a certain type, which have a certain header flag set
+ * into a slot for an operator.
+ *
+*/
+
+void BMO_HeaderFlag_To_Slot(BMesh *bm, BMOperator *op, const char *slotname, int flag, int type)
+{
+ BMIter elements;
+ BMHeader *e;
+ BMOpSlot *output = BMO_GetSlot(op, slotname);
+ int totelement=0, i=0;
+
+ totelement = BM_CountFlag(bm, type, flag, 1);
+
+ if(totelement){
+ alloc_slot_buffer(op, slotname, totelement);
+
+ if (type & BM_VERT) {
+ for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ if(!BM_TestHFlag(e, BM_HIDDEN) && BM_TestHFlag(e, flag)) {
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+
+ if (type & BM_EDGE) {
+ for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ if(!BM_TestHFlag(e, BM_HIDDEN) && BM_TestHFlag(e, flag)) {
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+
+ if (type & BM_FACE) {
+ for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ if(!BM_TestHFlag(e, BM_HIDDEN) && BM_TestHFlag(e, flag)) {
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+ } else {
+ output->len = 0;
+ }
+}
+
+/*
+ *
+ * BMO_FLAG_TO_SLOT
+ *
+ * Copies elements of a certain type, which have a certain flag set
+ * into an output slot for an operator.
+ *
+*/
+void BMO_Flag_To_Slot(BMesh *bm, BMOperator *op, const char *slotname, int flag, int type)
+{
+ BMIter elements;
+ BMHeader *e;
+ BMOpSlot *output = BMO_GetSlot(op, slotname);
+ int totelement = BMO_CountFlag(bm, flag, type), i=0;
+
+ if(totelement){
+ alloc_slot_buffer(op, slotname, totelement);
+
+ if (type & BM_VERT) {
+ for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ if(BMO_TestFlag(bm, e, flag)){
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+
+ if (type & BM_EDGE) {
+ for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ if(BMO_TestFlag(bm, e, flag)){
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+
+ if (type & BM_FACE) {
+ for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ if(BMO_TestFlag(bm, e, flag)){
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+ } else {
+ output->len = 0;
+ }
+}
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Header Flags elements in a slots buffer, automatically
+ * using the selection API where appropriate.
+ *
+*/
+
+void BMO_HeaderFlag_Buffer(BMesh *bm, BMOperator *op, const char *slotname, int flag, int type)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for(i = 0; i < slot->len; i++) {
+ if (!(type & data[i]->type))
+ continue;
+
+ if (flag & BM_SELECT)
+ BM_Select(bm, data[i], 1);
+ BM_SetHFlag(data[i], flag);
+ }
+}
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Removes flags from elements in a slots buffer, automatically
+ * using the selection API where appropriate.
+ *
+*/
+
+void BMO_UnHeaderFlag_Buffer(BMesh *bm, BMOperator *op, const char *slotname, int flag, int type)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for(i = 0; i < slot->len; i++) {
+ if (!(type & data[i]->type))
+ continue;
+
+ if (flag & BM_SELECT)
+ BM_Select(bm, data[i], 0);
+ BM_ClearHFlag(data[i], flag);
+ }
+}
+
+int BMO_Vert_CountEdgeFlags(BMesh *bm, BMVert *v, int toolflag)
+{
+ BMEdge *curedge;
+ int i, len=0, count=0;
+
+ if(v->e) {
+ len = bmesh_disk_count(v);
+
+ for(i = 0, curedge=v->e; i<len; i++){
+ if (BMO_TestFlag(bm, curedge, toolflag))
+ count++;
+ curedge = bmesh_disk_nextedge(curedge, v);
+ }
+ }
+
+ return count;
+}
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Flags elements in a slots buffer
+ *
+*/
+
+void BMO_Flag_Buffer(BMesh *bm, BMOperator *op, const char *slotname, int flag, int type)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for(i = 0; i < slot->len; i++) {
+ if (!(type & data[i]->type))
+ continue;
+
+ BMO_SetFlag(bm, data[i], flag);
+ }
+}
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Removes flags from elements in a slots buffer
+ *
+*/
+
+void BMO_Unflag_Buffer(BMesh *bm, BMOperator *op, const char *slotname, int flag, int type)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for(i = 0; i < slot->len; i++) {
+ if (!(type & data[i]->type))
+ continue;
+
+ BMO_ClearFlag(bm, data[i], flag);
+ }
+}
+
+
+/*
+ *
+ * ALLOC/FREE FLAG LAYER
+ *
+ * Used by operator stack to free/allocate
+ * private flag data. This is allocated
+ * using a mempool so the allocation/frees
+ * should be quite fast.
+ *
+ * TODO:
+ * Investigate not freeing flag layers until
+ * all operators have been executed. This would
+ * save a lot of realloc potentially.
+ *
+*/
+
+static void alloc_flag_layer(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+ BLI_mempool *oldpool = bm->toolflagpool; /*old flag pool*/
+ void *oldflags;
+
+ bm->totflags++;
+
+ /*allocate new flag pool*/
+ bm->toolflagpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512, 0, 0);
+
+ /*now go through and memcpy all the flags. Loops don't get a flag layer at this time...*/
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){
+ oldflags = v->head.flags;
+ v->head.flags = BLI_mempool_calloc(bm->toolflagpool);
+ memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*(bm->totflags-1));
+ }
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){
+ oldflags = e->head.flags;
+ e->head.flags = BLI_mempool_calloc(bm->toolflagpool);
+ memcpy(e->head.flags, oldflags, sizeof(BMFlagLayer)*(bm->totflags-1));
+ }
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){
+ oldflags = f->head.flags;
+ f->head.flags = BLI_mempool_calloc(bm->toolflagpool);
+ memcpy(f->head.flags, oldflags, sizeof(BMFlagLayer)*(bm->totflags-1));
+ }
+
+ BLI_mempool_destroy(oldpool);
+}
+
+static void free_flag_layer(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+ BLI_mempool *oldpool = bm->toolflagpool;
+ void *oldflags;
+
+ /*de-increment the totflags first...*/
+ bm->totflags--;
+ /*allocate new flag pool*/
+ bm->toolflagpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512, 1, 0);
+
+ /*now go through and memcpy all the flags*/
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){
+ oldflags = v->head.flags;
+ v->head.flags = BLI_mempool_calloc(bm->toolflagpool);
+ memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags); /*correct?*/
+ }
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){
+ oldflags = e->head.flags;
+ e->head.flags = BLI_mempool_calloc(bm->toolflagpool);
+ memcpy(e->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
+ }
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){
+ oldflags = f->head.flags;
+ f->head.flags = BLI_mempool_calloc(bm->toolflagpool);
+ memcpy(f->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
+ }
+
+ BLI_mempool_destroy(oldpool);
+}
+
+static void clear_flag_layer(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ /*now go through and memcpy all the flags*/
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){
+ memset(v->head.flags+(bm->totflags-1), 0, sizeof(BMFlagLayer));
+ }
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){
+ memset(e->head.flags+(bm->totflags-1), 0, sizeof(BMFlagLayer));
+ }
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){
+ memset(f->head.flags+(bm->totflags-1), 0, sizeof(BMFlagLayer));
+ }
+}
+
+void *BMO_FirstElem(BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+
+ if (slot->slottype != BMOP_OPSLOT_ELEMENT_BUF)
+ return NULL;
+
+ return slot->data.buf ? *(void**)slot->data.buf : NULL;
+}
+
+void *BMO_IterNew(BMOIter *iter, BMesh *bm, BMOperator *op,
+ const char *slotname, int restrict)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+
+ memset(iter, 0, sizeof(BMOIter));
+
+ iter->slot = slot;
+ iter->cur = 0;
+ iter->restrict = restrict;
+
+ if (iter->slot->slottype == BMOP_OPSLOT_MAPPING) {
+ if (iter->slot->data.ghash)
+ BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
+ else return NULL;
+ }
+
+ return BMO_IterStep(iter);
+}
+
+void *BMO_IterStep(BMOIter *iter)
+{
+ if (iter->slot->slottype == BMOP_OPSLOT_ELEMENT_BUF) {
+ BMHeader *h;
+
+ if (iter->cur >= iter->slot->len) return NULL;
+
+ h = ((void**)iter->slot->data.buf)[iter->cur++];
+ while (!(iter->restrict & h->type)) {
+ if (iter->cur >= iter->slot->len) return NULL;
+ h = ((void**)iter->slot->data.buf)[iter->cur++];
+ }
+
+ return h;
+ } else if (iter->slot->slottype == BMOP_OPSLOT_MAPPING) {
+ struct element_mapping *map;
+ void *ret = BLI_ghashIterator_getKey(&iter->giter);
+ map = BLI_ghashIterator_getValue(&iter->giter);
+
+ iter->val = map + 1;
+
+ BLI_ghashIterator_step(&iter->giter);
+
+ return ret;
+ }
+
+ return NULL;
+}
+
+/*used for iterating over mappings*/
+void *BMO_IterMapVal(BMOIter *iter)
+{
+ return iter->val;
+}
+
+void *BMO_IterMapValp(BMOIter *iter)
+{
+ return *((void**)iter->val);
+}
+
+float BMO_IterMapValf(BMOIter *iter)
+{
+ return *((float*)iter->val);
+}
+
+/*error system*/
+typedef struct bmop_error {
+ struct bmop_error *next, *prev;
+ int errorcode;
+ BMOperator *op;
+ const char *msg;
+} bmop_error;
+
+void BMO_ClearStack(BMesh *bm)
+{
+ while (BMO_PopError(bm, NULL, NULL));
+}
+
+void BMO_RaiseError(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
+{
+ bmop_error *err = MEM_callocN(sizeof(bmop_error), "bmop_error");
+
+ err->errorcode = errcode;
+ if (!msg) msg = bmop_error_messages[errcode];
+ err->msg = msg;
+ err->op = owner;
+
+ BLI_addhead(&bm->errorstack, err);
+}
+
+int BMO_HasError(BMesh *bm)
+{
+ return bm->errorstack.first != NULL;
+}
+
+/*returns error code or 0 if no error*/
+int BMO_GetError(BMesh *bm, const char **msg, BMOperator **op)
+{
+ bmop_error *err = bm->errorstack.first;
+ if (!err) return 0;
+
+ if (msg) *msg = err->msg;
+ if (op) *op = err->op;
+
+ return err->errorcode;
+}
+
+int BMO_PopError(BMesh *bm, const char **msg, BMOperator **op)
+{
+ int errorcode = BMO_GetError(bm, msg, op);
+
+ if (errorcode) {
+ bmop_error *err = bm->errorstack.first;
+
+ BLI_remlink(&bm->errorstack, bm->errorstack.first);
+ MEM_freeN(err);
+ }
+
+ return errorcode;
+}
+
+/*
+typedef struct bflag {
+ const char *str;
+ int flag;
+} bflag;
+
+#define b(f) {#f, f},
+static const char *bmesh_flags = {
+ b(BM_SELECT);
+ b(BM_SEAM);
+ b(BM_FGON);
+ b(BM_HIDDEN);
+ b(BM_SHARP);
+ b(BM_SMOOTH);
+ {NULL, 0};
+};
+
+int bmesh_str_to_flag(const char *str)
+{
+ int i;
+
+ while (bmesh_flags[i]->name) {
+ if (!strcmp(bmesh_flags[i]->name, str))
+ return bmesh_flags[i]->flag;
+ }
+
+ return -1;
+}
+*/
+
+//example:
+//BMO_CallOp(bm, "del %d %hv", DEL_ONLYFACES, BM_SELECT);
+/*
+ d - int
+ i - int
+ f - float
+ hv - header flagged verts
+ he - header flagged edges
+ hf - header flagged faces
+ fv - flagged verts
+ fe - flagged edges
+ ff - flagged faces
+
+*/
+
+#define nextc(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
+
+static int bmesh_name_to_slotcode(BMOpDefine *def, const char *name)
+{
+ int i;
+
+ for (i=0; def->slottypes[i].type; i++) {
+ if (!strcmp(name, def->slottypes[i].name)) return i;
+ }
+
+ printf("yeek! could not find bmesh slot for name %s!\n", name);
+ return 0;
+}
+
+static int bmesh_name_to_slotcode_check(BMOpDefine *def, const char *name)
+{
+ int i;
+
+ for (i=0; def->slottypes[i].type; i++) {
+ if (!strcmp(name, def->slottypes[i].name)) return i;
+ }
+
+ printf("yeek! could not find bmesh slot for name %s!\n", name);
+ return -1;
+}
+
+static int bmesh_opname_to_opcode(const char *opname) {
+ int i;
+
+ for (i=0; i<bmesh_total_ops; i++) {
+ if (!strcmp(opname, opdefines[i]->name)) break;
+ }
+
+ if (i == bmesh_total_ops) {
+ printf("yeek!! invalid op name %s!\n", opname);
+ return 0;
+ }
+
+ return i;
+}
+
+int BMO_VInitOpf(BMesh *bm, BMOperator *op, const char *_fmt, va_list vlist)
+{
+ BMOpDefine *def;
+ char *opname, *ofmt, *fmt = (char*)_fmt;
+ char slotname[64] = {0};
+ int i, n=strlen(fmt), stop, slotcode = -1, ret, type, state, c;
+ int noslot=0;
+
+ /*we muck around in here, so dup it*/
+ fmt = ofmt = strdup(fmt);
+
+ /*find operator name*/
+ i = strcspn(fmt, " \t");
+
+ opname = fmt;
+ if (!opname[i]) noslot = 1;
+ opname[i] = 0;
+
+ fmt += i + (noslot ? 0 : 1);
+
+ for (i=0; i<bmesh_total_ops; i++) {
+ if (!strcmp(opname, opdefines[i]->name)) break;
+ }
+
+ if (i == bmesh_total_ops) return 0;
+
+ BMO_Init_Op(op, opname);
+ def = opdefines[i];
+
+ i = 0;
+ state = 1; //0: not inside slotcode name, 1: inside slotcode name
+ c = 0;
+
+ while (*fmt) {
+ if (state) {
+ /*jump past leading whitespace*/
+ i = strspn(fmt, " \t");
+ fmt += i;
+
+ /*ignore trailing whitespace*/
+ if (!fmt[i])
+ break;
+
+ /*find end of slot name. currently this is
+ a little flexible, allowing "slot=%f",
+ "slot %f", "slot%f", and "slot\t%f". */
+ i = strcspn(fmt, "= \t%");
+ if (!fmt[i]) goto error;
+
+ fmt[i] = 0;
+
+ if (bmesh_name_to_slotcode_check(def, fmt) < 0) goto error;
+
+ strcpy(slotname, fmt);
+
+ state = 0;
+ fmt += i;
+ } else {
+ switch (*fmt) {
+ case ' ':
+ case '\t':
+ case '=':
+ case '%':
+ break;
+ case 'm': {
+ int size, c;
+
+ c = nextc(fmt);
+ fmt++;
+
+ if (c == '3') size = 3;
+ else if (c == '4') size = 4;
+ else goto error;
+
+ BMO_Set_Mat(op, slotname, va_arg(vlist, void*), size);
+ state = 1;
+ break;
+ }
+ case 'v': {
+ BMO_Set_Vec(op, slotname, va_arg(vlist, float*));
+ state = 1;
+ break;
+ }
+ case 'e': {
+ BMHeader *ele = va_arg(vlist, void*);
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+
+ slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void*)*4);
+ slot->len = 1;
+ *((void**)slot->data.buf) = ele;
+
+ state = 1;
+ break;
+ }
+ case 's': {
+ BMOperator *op2 = va_arg(vlist, void*);
+ const char *slotname2 = va_arg(vlist, char*);
+
+ BMO_CopySlot(op2, op, slotname2, slotname);
+ state = 1;
+ break;
+ }
+ case 'i':
+ case 'd':
+ BMO_Set_Int(op, slotname, va_arg(vlist, int));
+ state = 1;
+ break;
+ case 'p':
+ BMO_Set_Pnt(op, slotname, va_arg(vlist, void*));
+ state = 1;
+ break;
+ case 'f':
+ case 'h':
+ case 'a':
+ type = *fmt;
+
+ if (nextc(fmt) == ' ' || nextc(fmt) == '\t' ||
+ nextc(fmt)==0)
+ {
+ BMO_Set_Float(op,slotname,va_arg(vlist,double));
+ } else {
+ ret = 0;
+ stop = 0;
+ while (1) {
+ switch (nextc(fmt)) {
+ case 'f': ret |= BM_FACE;break;
+ case 'e': ret |= BM_EDGE;break;
+ case 'v': ret |= BM_VERT;break;
+ default:
+ stop = 1;
+ break;
+ }
+ if (stop) break;
+ fmt++;
+ }
+
+ if (type == 'h')
+ BMO_HeaderFlag_To_Slot(bm, op,
+ slotname, va_arg(vlist, int), ret);
+ else if (type == 'a')
+ BMO_All_To_Slot(bm, op, slotname, ret);
+ else
+ BMO_Flag_To_Slot(bm, op, slotname,
+ va_arg(vlist, int), ret);
+ }
+
+ state = 1;
+ break;
+ default:
+ printf("unrecognized bmop format char: %c\n", *fmt);
+ break;
+ }
+ }
+ fmt++;
+ }
+
+ free(ofmt);
+ return 1;
+error:
+ BMO_Finish_Op(bm, op);
+ return 0;
+}
+
+
+int BMO_InitOpf(BMesh *bm, BMOperator *op, const char *fmt, ...) {
+ va_list list;
+
+ va_start(list, fmt);
+ if (!BMO_VInitOpf(bm, op, fmt, list)) {
+ printf("BMO_InitOpf failed\n");
+ va_end(list);
+ return 0;
+ }
+ va_end(list);
+
+ return 1;
+}
+
+int BMO_CallOpf(BMesh *bm, const char *fmt, ...) {
+ va_list list;
+ BMOperator op;
+
+ va_start(list, fmt);
+ if (!BMO_VInitOpf(bm, &op, fmt, list)) {
+ printf("BMO_CallOpf failed, format is:\n \"%s\"\n", fmt);
+ va_end(list);
+ return 0;
+ }
+
+ BMO_Exec_Op(bm, &op);
+ BMO_Finish_Op(bm, &op);
+
+ va_end(list);
+ return 1;
+}
+
+
+/*
+ * BMO_SETFLAG
+ *
+ * Sets a flag for a certain element
+ *
+*/
+#ifdef BMO_SetFlag
+#undef BMO_SetFlag
+#endif
+void BMO_SetFlag(BMesh *bm, void *element, int flag)
+{
+ BMHeader *head = element;
+ head->flags[bm->stackdepth-1].f |= flag;
+}
+
+/*
+ * BMO_CLEARFLAG
+ *
+ * Clears a specific flag from a given element
+ *
+*/
+
+#ifdef BMO_ClearFlag
+#undef BMO_ClearFlag
+#endif
+void BMO_ClearFlag(BMesh *bm, void *element, int flag)
+{
+ BMHeader *head = element;
+ head->flags[bm->stackdepth-1].f &= ~flag;
+}
+
+/*
+ * BMO_TESTFLAG
+ *
+ * Tests whether or not a flag is set for a specific element
+ *
+ *
+*/
+
+#ifdef BMO_TestFlag
+#undef BMO_TestFlag
+#endif
+int BMO_TestFlag(BMesh *bm, void *element, int flag)
+{
+ BMHeader *head = element;
+ if(head->flags[bm->stackdepth-1].f & flag)
+ return 1;
+ return 0;
+}
diff --git a/source/blender/bmesh/intern/bmesh_operators_private.h b/source/blender/bmesh/intern/bmesh_operators_private.h
new file mode 100644
index 00000000000..e60d40efb24
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_operators_private.h
@@ -0,0 +1,72 @@
+#ifndef BM_OPERATORS_PRIVATE_H
+#define BM_OPERATORS_PRIVATE_H
+
+struct BMesh;
+struct BMOperator;
+
+void BMO_push(BMesh *bm, BMOperator *op);
+void BMO_pop(BMesh *bm);
+
+void splitop_exec(BMesh *bm, BMOperator *op);
+void dupeop_exec(BMesh *bm, BMOperator *op);
+void delop_exec(BMesh *bm, BMOperator *op);
+void esubdivide_exec(BMesh *bmesh, BMOperator *op);
+void edit2bmesh_exec(BMesh *bmesh, BMOperator *op);
+void bmesh2edit_exec(BMesh *bmesh, BMOperator *op);
+void triangulate_exec(BMesh *bmesh, BMOperator *op);
+void dissolvefaces_exec(BMesh *bmesh, BMOperator *op);
+void dissolveverts_exec(BMesh *bmesh, BMOperator *op);
+void bmesh_make_fgons_exec(BMesh *bmesh, BMOperator *op);
+void extrude_edge_context_exec(BMesh *bm, BMOperator *op);
+void connectverts_exec(BMesh *bm, BMOperator *op);
+void makeprim_exec(BMesh *bm, BMOperator *op);
+void extrude_vert_indiv_exec(BMesh *bm, BMOperator *op);
+void mesh_to_bmesh_exec(BMesh *bm, BMOperator *op);
+void bmesh_to_mesh_exec(BMesh *bm, BMOperator *op);
+void bmesh_translate_exec(BMesh *bm, BMOperator *op);
+void bmesh_transform_exec(BMesh *bm, BMOperator *op);
+void bmesh_contextual_create_exec(BMesh *bm, BMOperator *op);
+void bmesh_edgenet_fill_exec(BMesh *bm, BMOperator *op);
+void bmesh_rotate_exec(BMesh *bm, BMOperator *op);
+void bmesh_makevert_exec(BMesh *bm, BMOperator *op);
+void dissolveedges_exec(BMesh *bm, BMOperator *op);
+void dissolve_edgeloop_exec(BMesh *bm, BMOperator *op);
+void bmesh_weldverts_exec(BMesh *bm, BMOperator *op);
+void bmesh_removedoubles_exec(BMesh *bm, BMOperator *op);
+void bmesh_finddoubles_exec(BMesh *bm, BMOperator *op);
+void bmesh_mirror_exec(BMesh *bm, BMOperator *op);
+void esplit_exec(BMesh *bm, BMOperator *op);
+void bmesh_reversefaces_exec(BMesh *bm, BMOperator *op);
+void bmesh_edgerotate_exec(BMesh *bm, BMOperator *op);
+void bmesh_regionextend_exec(BMesh *bm, BMOperator *op);
+void bmesh_righthandfaces_exec(BMesh *bm, BMOperator *op);
+void bmesh_vertexsmooth_exec(BMesh *bm, BMOperator *op);
+void bmesh_extrude_onlyedge_exec(BMesh *bm, BMOperator *op);
+void bmesh_extrude_face_indiv_exec(BMesh *bm, BMOperator *op);
+void bmesh_collapsecon_exec(BMesh *bm, BMOperator *op);
+void bmesh_pointmerge_exec(BMesh *bm, BMOperator *op);
+void bmesh_collapse_exec(BMesh *bm, BMOperator *op);
+void bmesh_similarfaces_exec(BMesh *bm, BMOperator *op);
+void bmesh_similaredges_exec(BMesh *bm, BMOperator *op);
+void bmesh_similarverts_exec(BMesh *bm, BMOperator *op);
+void bmesh_pointmerge_facedata_exec(BMesh *bm, BMOperator *op);
+void bmesh_vert_average_facedata_exec(BMesh *bm, BMOperator *op);
+void bmesh_rotateuvs_exec(BMesh *bm, BMOperator *op);
+void object_load_bmesh_exec(BMesh *bm, BMOperator *op);
+void bmesh_reverseuvs_exec(BMesh *bm, BMOperator *op);
+void bmesh_edgenet_prepare(BMesh *bm, BMOperator *op);
+void bmesh_rotatecolors_exec(BMesh *bm, BMOperator *op);
+void bmesh_reversecolors_exec(BMesh *bm, BMOperator *op);
+void bmesh_vertexshortestpath_exec(BMesh *bm, BMOperator *op);
+void bmesh_scale_exec(BMesh *bm, BMOperator *op);
+void bmesh_edgesplitop_exec(BMesh *bm, BMOperator *op);
+void bmesh_automerge_exec(BMesh *bm, BMOperator *op);
+void bmesh_create_cone_exec(BMesh *bm, BMOperator *op);
+void bmesh_create_monkey_exec(BMesh *bm, BMOperator *op);
+void bmesh_create_icosphere_exec(BMesh *bm, BMOperator *op);
+void bmesh_create_uvsphere_exec(BMesh *bm, BMOperator *op);
+void bmesh_create_grid_exec(BMesh *bm, BMOperator *op);
+void bmesh_create_cube_exec(BMesh *bm, BMOperator *op);
+void bmesh_jointriangles_exec(BMesh *bm, BMOperator *op);
+
+#endif
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
new file mode 100644
index 00000000000..6a30d1c0a96
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -0,0 +1,916 @@
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include "BKE_utildefines.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_array.h"
+#include "BLI_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+/*
+ *
+ * BME POLYGON.C
+ *
+ * This file contains code for dealing
+ * with polygons (normal/area calculation,
+ * tesselation, ect)
+ *
+ * TODO:
+ * -Add in Tesselator frontend that creates
+ * BMTriangles from copied faces
+ * -Add in Function that checks for and flags
+ * degenerate faces.
+ *
+*/
+
+/*
+ * TEST EDGE SIDE and POINT IN TRIANGLE
+ *
+ * Point in triangle tests stolen from scanfill.c.
+ * Used for tesselator
+ *
+*/
+
+static short testedgeside(double *v1, double *v2, double *v3)
+/* is v3 to the right of v1-v2 ? With exception: v3==v1 || v3==v2 */
+{
+ double inp;
+
+ //inp= (v2[cox]-v1[cox])*(v1[coy]-v3[coy]) +(v1[coy]-v2[coy])*(v1[cox]-v3[cox]);
+ inp= (v2[0]-v1[0])*(v1[1]-v3[1]) +(v1[1]-v2[1])*(v1[0]-v3[0]);
+
+ if(inp<0.0) return 0;
+ else if(inp==0) {
+ if(v1[0]==v3[0] && v1[1]==v3[1]) return 0;
+ if(v2[0]==v3[0] && v2[1]==v3[1]) return 0;
+ }
+ return 1;
+}
+
+static short testedgesidef(float *v1, float *v2, float *v3)
+/* is v3 to the right of v1-v2 ? With exception: v3==v1 || v3==v2 */
+{
+ double inp;
+
+ //inp= (v2[cox]-v1[cox])*(v1[coy]-v3[coy]) +(v1[coy]-v2[coy])*(v1[cox]-v3[cox]);
+ inp= (v2[0]-v1[0])*(v1[1]-v3[1]) +(v1[1]-v2[1])*(v1[0]-v3[0]);
+
+ if(inp<0.0) return 0;
+ else if(inp==0) {
+ if(v1[0]==v3[0] && v1[1]==v3[1]) return 0;
+ if(v2[0]==v3[0] && v2[1]==v3[1]) return 0;
+ }
+ return 1;
+}
+
+static int point_in_triangle(double *v1, double *v2, double *v3, double *pt)
+{
+ if(testedgeside(v1,v2,pt) && testedgeside(v2,v3,pt) && testedgeside(v3,v1,pt))
+ return 1;
+ return 0;
+}
+
+/*
+ * COMPUTE POLY NORMAL
+ *
+ * Computes the normal of a planar
+ * polygon See Graphics Gems for
+ * computing newell normal.
+ *
+*/
+#define FEQ(f1, f2) (ABS((double)(f1)-(double)(f2)) < 0.1)
+
+static void compute_poly_normal(float normal[3], float (*verts)[3], int nverts)
+{
+
+ double u[3], v[3], w[3];/*, *w, v1[3], v2[3];*/
+ double n[3] = {0.0, 0.0, 0.0}, l, v1[3], v2[3];
+ double l2;
+ int i, s=0;
+
+ /*this fixes some weird numerical error*/
+ verts[0][0] += 0.0001f;
+ verts[0][1] += 0.0001f;
+ verts[0][2] += 0.0001f;
+
+ for(i = 0; i < nverts; i++){
+ copy_v3_v3(u, verts[i]);
+ copy_v3_v3(v, verts[(i+1) % nverts]);
+ copy_v3_v3(w, verts[(i+2) % nverts]);
+
+#if 0
+ VECSUB(v1, w, v);
+ VECSUB(v2, v, u);
+ Normalize_d(v1);
+ Normalize_d(v2);
+
+ l = INPR(v1, v2);
+ if (ABS(l-1.0) < 0.1)
+ continue;
+#endif
+ /* newell's method
+
+ so thats?:
+ (a[1] - b[1]) * (a[2] + b[2]);
+ a[1]*b[2] - b[1]*a[2] - b[1]*b[2] + a[1]*a[2]
+
+ odd. half of that is the cross product. . .what's the
+ other half?
+
+ also could be like a[1]*(b[2] + a[2]) - b[1]*(a[2] - b[2])
+ */
+
+ n[0] += (u[1] - v[1]) * (u[2] + v[2]);
+ n[1] += (u[2] - v[2]) * (u[0] + v[0]);
+ n[2] += (u[0] - v[0]) * (u[1] + v[1]);
+ }
+
+ l = n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
+ l = sqrt(l);
+ /*fast square root, newton/babylonian method:
+ l2 = l*0.1;
+
+ l2 = (l/l2 + l2)*0.5;
+ l2 = (l/l2 + l2)*0.5;
+ l2 = (l/l2 + l2)*0.5;
+ */
+
+ if (l == 0.0) {
+ normal[0] = 0.0f;
+ normal[1] = 0.0f;
+ normal[2] = 1.0f;
+
+ return;
+ } else l = 1.0f / l;
+
+ n[0] *= l;
+ n[1] *= l;
+ n[2] *= l;
+
+ normal[0] = (float) n[0];
+ normal[1] = (float) n[1];
+ normal[2] = (float) n[2];
+}
+
+/*
+ * COMPUTE POLY CENTER
+ *
+ * Computes the centroid and
+ * area of a polygon in the X/Y
+ * plane.
+ *
+*/
+
+static int compute_poly_center(float center[3], float *area, float (*verts)[3], int nverts)
+{
+ int i, j;
+ float atmp = 0.0, xtmp = 0.0, ytmp = 0.0, ai;
+
+ center[0] = center[1] = center[2] = 0.0;
+
+ if(nverts < 3)
+ return 0;
+
+ i = nverts-1;
+ j = 0;
+
+ while(j < nverts){
+ ai = verts[i][0] * verts[j][1] - verts[j][0] * verts[i][1];
+ atmp += ai;
+ xtmp += (verts[j][0] + verts[i][0]) * ai;
+ ytmp += (verts[j][1] + verts[i][1]) * ai;
+ i = j;
+ j += 1;
+ }
+
+ if(area)
+ *area = atmp / 2.0f;
+
+ if (atmp != 0){
+ center[0] = xtmp / (3.0f * atmp);
+ center[1] = xtmp / (3.0f * atmp);
+ return 1;
+ }
+ return 0;
+}
+
+float BM_face_area(BMFace *f)
+{
+ BMLoop *l;
+ BMIter iter;
+ float (*verts)[3], stackv[100][3];
+ float area, center[3];
+ int i;
+
+ if (f->len <= 100)
+ verts = stackv;
+ else verts = MEM_callocN(sizeof(float)*f->len*3, "bm_face_area tmp");
+
+ i = 0;
+ BM_ITER(l, &iter, NULL, BM_LOOPS_OF_FACE, f) {
+ VECCOPY(verts[i], l->v->co);
+ i++;
+ }
+
+ compute_poly_center(center, &area, verts, f->len);
+
+ if (f->len > 100)
+ MEM_freeN(verts);
+
+ return area;
+}
+/*
+computes center of face in 3d. uses center of bounding box.
+*/
+
+int BM_Compute_Face_Center(BMesh *bm, BMFace *f, float center[3])
+{
+ BMIter iter;
+ BMLoop *l;
+ float min[3], max[3];
+ int i;
+
+ INIT_MINMAX(min, max);
+ l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f);
+ for (i=0; l; l=BMIter_Step(&iter), i++) {
+ DO_MINMAX(l->v->co, min, max);
+ }
+
+ add_v3_v3v3(center, min, max);
+ mul_v3_fl(center, 0.5f);
+
+ return 0;
+}
+
+/*
+ * COMPUTE POLY PLANE
+ *
+ * Projects a set polygon's vertices to
+ * a plane defined by the average
+ * of its edges cross products
+ *
+*/
+
+void compute_poly_plane(float (*verts)[3], int nverts)
+{
+
+ float avgc[3], norm[3], temp[3], mag, avgn[3];
+ float *v1, *v2, *v3;
+ int i;
+
+ if(nverts < 3)
+ return;
+
+ avgn[0] = avgn[1] = avgn[2] = 0.0;
+ avgc[0] = avgc[1] = avgc[2] = 0.0;
+
+ for(i = 0; i < nverts; i++){
+ v1 = verts[i];
+ v2 = verts[(i+1) % nverts];
+ v3 = verts[(i+2) % nverts];
+ normal_tri_v3( norm,v1, v2, v3);
+
+ avgn[0] += norm[0];
+ avgn[1] += norm[1];
+ avgn[2] += norm[2];
+ }
+
+ /*what was this bit for?*/
+ if(avgn[0] == 0.0 && avgn[1] == 0.0 && avgn[2] == 0.0){
+ avgn[0] = 0.0;
+ avgn[1] = 0.0;
+ avgn[2] = 1.0;
+ } else {
+ avgn[0] /= nverts;
+ avgn[1] /= nverts;
+ avgn[2] /= nverts;
+ normalize_v3(avgn);
+ }
+
+ for(i = 0; i < nverts; i++){
+ v1 = verts[i];
+ VECCOPY(temp, v1);
+ mag = 0.0;
+ mag += (temp[0] * avgn[0]);
+ mag += (temp[1] * avgn[1]);
+ mag += (temp[2] * avgn[2]);
+
+ temp[0] = (avgn[0] * mag);
+ temp[1] = (avgn[1] * mag);
+ temp[2] = (avgn[2] * mag);
+
+ sub_v3_v3v3(v1, v1, temp);
+ }
+}
+
+/*
+ BM LEGAL EDGES
+
+ takes in a face and a list of edges, and sets to NULL any edge in
+ the list that bridges a concave region of the face or intersects
+ any of the faces's edges.
+*/
+static void shrink_edged(double *v1, double *v2, double fac)
+{
+ double mid[3];
+
+ add_v3_v3v3(mid, v1, v2);
+ mul_v3_fl(mid, 0.5);
+
+ sub_v3_v3v3(v1, v1, mid);
+ sub_v3_v3v3(v2, v2, mid);
+
+ mul_v3_fl(v1, fac);
+ mul_v3_fl(v2, fac);
+
+ add_v3_v3v3(v1, v1, mid);
+ add_v3_v3v3(v2, v2, mid);
+}
+
+static void shrink_edgef(float *v1, float *v2, float fac)
+{
+ float mid[3];
+
+ add_v3_v3v3(mid, v1, v2);
+ mul_v3_fl(mid, 0.5);
+
+ sub_v3_v3v3(v1, v1, mid);
+ sub_v3_v3v3(v2, v2, mid);
+
+ mul_v3_fl(v1, fac);
+ mul_v3_fl(v2, fac);
+
+ add_v3_v3v3(v1, v1, mid);
+ add_v3_v3v3(v2, v2, mid);
+}
+
+/*
+ * POLY ROTATE PLANE
+ *
+ * Rotates a polygon so that it's
+ * normal is pointing towards the mesh Z axis
+ *
+*/
+
+void poly_rotate_plane(float normal[3], float (*verts)[3], int nverts)
+{
+
+ float up[3] = {0.0f,0.0f,1.0f}, axis[3], q[4];
+ float mat[3][3];
+ double angle;
+ int i;
+
+ cross_v3_v3v3(axis, up, normal);
+ axis[0] *= -1;
+ axis[1] *= -1;
+ axis[2] *= -1;
+
+ angle = saacos(normal[0]*up[0]+normal[1]*up[1] + normal[2]*up[2]);
+
+ if (angle == 0.0f) return;
+
+ axis_angle_to_quat(q, axis, (float)angle);
+ quat_to_mat3(mat, q);
+
+ for(i = 0; i < nverts; i++)
+ mul_m3_v3(mat, verts[i]);
+}
+
+/*
+ * BMESH UPDATE FACE NORMAL
+ *
+ * Updates the stored normal for the
+ * given face. Requires that a buffer
+ * of sufficient length to store projected
+ * coordinates for all of the face's vertices
+ * is passed in as well.
+ *
+*/
+
+void BM_Face_UpdateNormal(BMesh *bm, BMFace *f)
+{
+ float projverts[200][3];
+ float (*proj)[3] = f->len < 200 ? projverts : MEM_mallocN(sizeof(float)*f->len*3, "projvertsn");
+ BMIter iter;
+ BMLoop *l;
+ int i=0;
+
+ if (f->len < 3) return;
+
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
+ VECCOPY(proj[i], l->v->co);
+ i += 1;
+ }
+
+ bmesh_update_face_normal(bm, f, proj);
+
+ if (projverts != proj) MEM_freeN(proj);
+}
+
+void BM_Edge_UpdateNormals(BMesh *bm, BMEdge *e)
+{
+ BMIter iter;
+ BMFace *f;
+
+ f = BMIter_New(&iter, bm, BM_FACES_OF_EDGE, e);
+ for (; f; f=BMIter_Step(&iter)) {
+ BM_Face_UpdateNormal(bm, f);
+ }
+
+ BM_Vert_UpdateNormal(bm, e->v1);
+ BM_Vert_UpdateNormal(bm, e->v2);
+}
+
+void BM_Vert_UpdateNormal(BMesh *bm, BMVert *v)
+{
+ BMIter iter;
+ BMFace *f;
+ int len=0;
+
+ v->no[0] = v->no[1] = v->no[2] = 0.0f;
+
+ f = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v);
+ for (; f; f=BMIter_Step(&iter), len++) {
+ add_v3_v3v3(v->no, f->no, v->no);
+ }
+
+ if (!len) return;
+
+ mul_v3_fl(v->no, 1.0f/(int)len);
+}
+
+void bmesh_update_face_normal(BMesh *bm, BMFace *f, float (*projectverts)[3])
+{
+ BMIter iter;
+ BMLoop *l;
+ int i;
+
+ if(f->len > 4) {
+ i = 0;
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
+ VECCOPY(projectverts[i], l->v->co);
+ l = (BMLoop*)(l->next);
+ i += 1;
+ }
+
+ compute_poly_normal(f->no, projectverts, f->len);
+ }
+ else if(f->len == 3){
+ BMVert *v1, *v2, *v3;
+ v1 = bm_firstfaceloop(f)->v;
+ v2 = bm_firstfaceloop(f)->next->v;
+ v3 = bm_firstfaceloop(f)->next->next->v;
+ normal_tri_v3( f->no,v1->co, v2->co, v3->co);
+ }
+ else if(f->len == 4){
+ BMVert *v1, *v2, *v3, *v4;
+ v1 = bm_firstfaceloop(f)->v;
+ v2 = bm_firstfaceloop(f)->next->v;
+ v3 = bm_firstfaceloop(f)->next->next->v;
+ v4 = bm_firstfaceloop(f)->prev->v;
+ normal_quad_v3( f->no,v1->co, v2->co, v3->co, v4->co);
+ }
+ else{ /*horrible, two sided face!*/
+ f->no[0] = 0.0;
+ f->no[1] = 0.0;
+ f->no[2] = 1.0;
+ }
+
+}
+
+
+/*
+ * BMESH FLIP NORMAL
+ *
+ * Reverses the winding of a face.
+ * Note that this updates the calculated
+ * normal.
+*/
+void BM_flip_normal(BMesh *bm, BMFace *f)
+{
+ bmesh_loop_reverse(bm, f);
+ BM_Face_UpdateNormal(bm, f);
+}
+
+/* detects if two line segments cross each other (intersects).
+ note, there could be more winding cases then there needs to be. */
+int linecrosses(double *v1, double *v2, double *v3, double *v4)
+{
+ int w1, w2, w3, w4, w5;
+
+ /*w1 = winding(v1, v3, v4);
+ w2 = winding(v2, v3, v4);
+ w3 = winding(v3, v1, v2);
+ w4 = winding(v4, v1, v2);
+
+ return (w1 == w2) && (w3 == w4);*/
+
+ w1 = testedgeside(v1, v3, v2);
+ w2 = testedgeside(v2, v4, v1);
+ w3 = !testedgeside(v1, v2, v3);
+ w4 = testedgeside(v3, v2, v4);
+ w5 = !testedgeside(v3, v1, v4);
+ return w1 == w2 && w2 == w3 && w3 == w4 && w4==w5;
+}
+
+/* detects if two line segments cross each other (intersects).
+ note, there could be more winding cases then there needs to be. */
+int linecrossesf(float *v1, float *v2, float *v3, float *v4)
+{
+ int w1, w2, w3, w4, w5, ret;
+
+/* int test1_a, test1_a, test2_a, test2_a;
+
+ test1_a = check_tri_clock_dir(l1p1, l1p2, l2p1);
+ test1_b = check_tri_clock_dir(l1p1, l1p2, l2p2);
+ if (test1_a != test1_b)
+ {
+ test2_a = check_tri_clock_dir(l2p1, l2p2, l1p1);
+ test2_b = check_tri_clock_dir(l2p1, l2p2, l1p2);
+ if (test2_a != test2_b)
+ {
+ return 1;
+ }
+ }*/
+ /*w1 = testedgesidef(v1, v2, v3);
+ w2 = testedgesidef(v1, v2, v4);
+ if(w1 != w2) {
+ w3 = testedgesidef(v3, v4, v1);
+ w4 = testedgesidef(v3, v4, v2);
+ if (w3 != w4) return 1;
+ }
+
+ return 0;*/
+
+ /*w1 = testedgesidef(v1, v3, v4);
+ w2 = testedgesidef(v2, v3, v4);
+ w3 = testedgesidef(v3, v1, v2);
+ w4 = testedgesidef(v4, v1, v2);
+
+ return (w1 == w2) && (w2 == w3) && (w3 == w4);*/
+
+ /*do an interval test on the x and y axes*/
+ /*first do x axis*/
+ #define T 0.01
+ if (ABS(v1[1]-v2[1]) < T && ABS(v3[1]-v4[1]) < T &&
+ ABS(v1[1]-v3[1]) < T) {
+ if (v3[0] >= v1[0] && v3[0] <= v2[0])
+ return 1;
+ if (v4[0] >= v1[0] && v4[0] <= v2[0])
+ return 1;
+ if (v3[0] <= v1[0] && v4[0] >= v2[0])
+ return 1;
+ }
+
+ /*now do y axis*/
+ if (ABS(v1[0]-v2[0]) < T && ABS(v3[0]-v4[0]) < T &&
+ ABS(v1[0]-v3[0]) < T) {
+ if (v3[1] >= v1[1] && v3[1] <= v2[1])
+ return 1;
+ if (v4[1] >= v1[1] && v4[1] <= v2[1])
+ return 1;
+ if (v3[1] <= v1[1] && v4[1] >= v2[1])
+ return 1;
+ }
+
+ /*now test winding*/
+ w1 = testedgesidef(v1, v3, v2);
+ w2 = testedgesidef(v2, v4, v1);
+ w3 = !testedgesidef(v1, v2, v3);
+ w4 = testedgesidef(v3, v2, v4);
+ w5 = !testedgesidef(v3, v1, v4);
+
+ return w1 == w2 && w2 == w3 && w3 == w4 && w4==w5;
+}
+
+int goodline(float (*projectverts)[3], BMFace *f, int v1i,
+ int v2i, int v3i, int nvert) {
+ BMLoop *l = bm_firstfaceloop(f);
+ double v1[3], v2[3], v3[3], pv1[3], pv2[3];
+ int i;
+
+ VECCOPY(v1, projectverts[v1i]);
+ VECCOPY(v2, projectverts[v2i]);
+ VECCOPY(v3, projectverts[v3i]);
+
+ if (testedgeside(v1, v2, v3)) return 0;
+
+ //for (i=0; i<nvert; i++) {
+ do {
+ i = l->v->head.eflag2;
+ if (i == v1i || i == v2i || i == v3i) {
+ l = (BMLoop*)l->next;
+ continue;
+ }
+
+ VECCOPY(pv1, projectverts[l->v->head.eflag2]);
+ VECCOPY(pv2, projectverts[((BMLoop*)l->next)->v->head.eflag2]);
+
+ //if (linecrosses(pv1, pv2, v1, v3)) return 0;
+ if (point_in_triangle(v1, v2, v3, pv1)) return 0;
+ if (point_in_triangle(v3, v2, v1, pv1)) return 0;
+
+ l = (BMLoop*)l->next;
+ } while (l != bm_firstfaceloop(f));
+ return 1;
+}
+/*
+ * FIND EAR
+ *
+ * Used by tesselator to find
+ * the next triangle to 'clip off'
+ * of a polygon while tesselating.
+ *
+*/
+
+static BMLoop *find_ear(BMesh *bm, BMFace *f, float (*verts)[3],
+ int nvert)
+{
+ BMVert *v1, *v2, *v3;
+ BMLoop *bestear = NULL, *l;
+ float angle, bestangle = 180.0f;
+ int isear, i=0;
+
+ l = bm_firstfaceloop(f);
+ do {
+ isear = 1;
+
+ v1 = ((BMLoop*)(l->prev))->v;
+ v2 = l->v;
+ v3 = ((BMLoop*)(l->next))->v;
+
+ if (BM_Edge_Exist(v1, v3)) isear = 0;
+
+ if (isear && !goodline(verts, f, v1->head.eflag2, v2->head.eflag2,
+ v3->head.eflag2, nvert))
+ isear = 0;
+
+ if(isear) {
+ /*angle = angle_v3v3v3(verts[v1->head.eflag2], verts[v2->head.eflag2], verts[v3->head.eflag2]);
+ if(!bestear || ABS(angle-45.0f) < bestangle) {
+ bestear = l;
+ bestangle = ABS(45.0f-angle);
+ }
+
+ if (angle > 20 && angle < 90) break;
+ if (angle < 100 && i > 5) break;
+ i += 1;*/
+ bestear = l;
+ break;
+ }
+ l = (BMLoop*)(l->next);
+ }
+ while(l != bm_firstfaceloop(f));
+
+ return bestear;
+}
+
+/*
+ * BMESH TRIANGULATE FACE
+ *
+ * Triangulates a face using a
+ * simple 'ear clipping' algorithm
+ * that tries to favor non-skinny
+ * triangles (angles less than
+ * 90 degrees). If the triangulator
+ * has bits left over (or cannot
+ * triangulate at all) it uses a
+ * simple fan triangulation
+ *
+ * newfaces, if non-null, must be an array of BMFace pointers,
+ * with a length equal to f->len. it will be filled with the new
+ * triangles, and will be NULL-terminated.
+*/
+void BM_Triangulate_Face(BMesh *bm, BMFace *f, float (*projectverts)[3],
+ int newedgeflag, int newfaceflag, BMFace **newfaces)
+{
+ int i, done, nvert, nf_i = 0;
+ BMLoop *l, *newl, *nextloop;
+ BMVert *v;
+
+ /*copy vertex coordinates to vertspace array*/
+ i = 0;
+ l = bm_firstfaceloop(f);
+ do{
+ VECCOPY(projectverts[i], l->v->co);
+ l->v->head.eflag2 = i; /*warning, abuse! never duplicate in tools code! never you hear?*/ /*actually, get rid of this completely, use a new structure for this....*/
+ i++;
+ l = (BMLoop*)(l->next);
+ }while(l != bm_firstfaceloop(f));
+
+ ///bmesh_update_face_normal(bm, f, projectverts);
+
+ compute_poly_normal(f->no, projectverts, f->len);
+ poly_rotate_plane(f->no, projectverts, i);
+
+ nvert = f->len;
+
+ //compute_poly_plane(projectverts, i);
+ for (i=0; i<nvert; i++) {
+ projectverts[i][2] = 0.0f;
+ }
+
+ done = 0;
+ while(!done && f->len > 3){
+ done = 1;
+ l = find_ear(bm, f, projectverts, nvert);
+ if(l) {
+ done = 0;
+ v = l->v;
+ f = BM_Split_Face(bm, l->f, ((BMLoop*)(l->prev))->v,
+ ((BMLoop*)(l->next))->v,
+ &newl, NULL);
+ VECCOPY(f->no, l->f->no);
+
+ if (!f) {
+ printf("yeek! triangulator failed to split face!\n");
+ break;
+ }
+
+ BMO_SetFlag(bm, newl->e, newedgeflag);
+ BMO_SetFlag(bm, f, newfaceflag);
+
+ if (newfaces) newfaces[nf_i++] = f;
+
+ /*l = f->loopbase;
+ do {
+ if (l->v == v) {
+ f->loopbase = l;
+ break;
+ }
+ l = l->next;
+ } while (l != f->loopbase);*/
+ }
+ }
+
+ if (f->len > 3){
+ l = bm_firstfaceloop(f);
+ while (l->f->len > 3){
+ nextloop = ((BMLoop*)(l->next->next));
+ f = BM_Split_Face(bm, l->f, l->v, nextloop->v,
+ &newl, NULL);
+ if (!f) {
+ printf("triangle fan step of triangulator failed.\n");
+
+ /*NULL-terminate*/
+ if (newfaces) newfaces[nf_i] = NULL;
+ return;
+ }
+
+ if (newfaces) newfaces[nf_i++] = f;
+
+ BMO_SetFlag(bm, newl->e, newedgeflag);
+ BMO_SetFlag(bm, f, newfaceflag);
+ l = nextloop;
+ }
+ }
+
+ /*NULL-terminate*/
+ if (newfaces) newfaces[nf_i] = NULL;
+}
+
+/*each pair of loops defines a new edge, a split. this function goes
+ through and sets pairs that are geometrically invalid to null. a
+ split is invalid, if it forms a concave angle or it intersects other
+ edges in the face, or it intersects another split. in the case of
+ intersecting splits, only the first of the set of intersecting
+ splits survives.*/
+void BM_LegalSplits(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len)
+{
+ BMIter iter;
+ BMLoop *l;
+ float v1[3], v2[3], v3[3], v4[3], no[3], mid[3], *p1, *p2, *p3, *p4;
+ float out[3] = {-234324.0f, -234324.0f, 0.0f};
+ float projectverts[100][3];
+ float edgevertsstack[200][3];
+ float (*projverts)[3] = projectverts;
+ float (*edgeverts)[3] = edgevertsstack;
+ float fac1 = 1.0000001f, fac2 = 0.9f; //9999f; //0.999f;
+ int i, j, a=0, clen;
+
+ if (f->len > 100) projverts = MEM_mallocN(sizeof(float)*3*f->len, "projvertsb");
+ if (len > 100) edgeverts = MEM_mallocN(sizeof(float)*3*2*len, "edgevertsb");
+
+ i = 0;
+ l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f);
+ for (; l; l=BMIter_Step(&iter)) {
+ l->head.eflag2 = i;
+ VECCOPY(projverts[i], l->v->co);
+ i++;
+ }
+
+ for (i=0; i<len; i++) {
+ VECCOPY(v1, loops[i][0]->v->co);
+ VECCOPY(v2, loops[i][1]->v->co);
+
+ shrink_edgef(v1, v2, fac2);
+
+ VECCOPY(edgeverts[a], v1);
+ a++;
+ VECCOPY(edgeverts[a], v2);
+ a++;
+ }
+
+ compute_poly_normal(no, projverts, f->len);
+ poly_rotate_plane(no, projverts, f->len);
+ poly_rotate_plane(no, edgeverts, len*2);
+
+ l = bm_firstfaceloop(f);
+ for (i=0; i<f->len; i++) {
+ p1 = projverts[i];
+ out[0] = MAX2(out[0], p1[0]) + 0.01f;
+ out[1] = MAX2(out[1], p1[1]) + 0.01f;
+ out[2] = 0.0f;
+ p1[2] = 0.0f;
+
+ //VECCOPY(l->v->co, p1);
+
+ l = (BMLoop*) l->next;
+ }
+
+ for (i=0; i<len; i++) {
+ edgeverts[i*2][2] = 0.0f;
+ edgeverts[i*2+1][2] = 0.0f;
+ }
+
+ /*do convexity test*/
+ for (i=0; i<len; i++) {
+ VECCOPY(v2, edgeverts[i*2]);
+ VECCOPY(v3, edgeverts[i*2+1]);
+
+ add_v3_v3v3(mid, v2, v3);
+ mul_v3_fl(mid, 0.5f);
+
+ clen = 0;
+ for (j=0; j<f->len; j++) {
+ p1 = projverts[j];
+ p2 = projverts[(j+1)%f->len];
+
+ VECCOPY(v1, p1);
+ VECCOPY(v2, p2);
+
+ shrink_edgef(v1, v2, fac1);
+
+ if (linecrossesf(p1, p2, mid, out)) clen++;
+ }
+
+ if (clen%2 == 0) {
+ loops[i][0] = NULL;
+ }
+ }
+
+ /*do line crossing tests*/
+ for (i=0; i<f->len; i++) {
+ p1 = projverts[i];
+ p2 = projverts[(i+1)%f->len];
+
+ VECCOPY(v1, p1);
+ VECCOPY(v2, p2);
+
+ shrink_edgef(v1, v2, fac1);
+
+ for (j=0; j<len; j++) {
+ if (!loops[j][0]) continue;
+
+ p3 = edgeverts[j*2];
+ p4 = edgeverts[j*2+1];
+
+ if (linecrossesf(v1, v2, p3, p4))
+ {
+ loops[j][0] = NULL;
+ }
+ }
+ }
+
+ for (i=0; i<len; i++) {
+ for (j=0; j<len; j++) {
+ if (j == i) continue;
+ if (!loops[i][0]) continue;
+ if (!loops[j][0]) continue;
+
+ p1 = edgeverts[i*2];
+ p2 = edgeverts[i*2+1];
+ p3 = edgeverts[j*2];
+ p4 = edgeverts[j*2+1];
+
+ VECCOPY(v1, p1);
+ VECCOPY(v2, p2);
+
+ shrink_edgef(v1, v2, fac1);
+
+ if (linecrossesf(v1, v2, p3, p4)) {
+ loops[i][0]=NULL;
+ }
+ }
+ }
+
+ if (projverts != projectverts) MEM_freeN(projverts);
+ if (edgeverts != edgevertsstack) MEM_freeN(edgeverts);
+}
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
new file mode 100644
index 00000000000..fa3172055d8
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -0,0 +1,105 @@
+/**
+ * bmesh_private.h jan 2007
+ *
+ * Private function prototypes for bmesh public API.
+ * This file is a grab-bag of functions from various
+ * parts of the bmesh internals.
+ *
+ *
+ * $Id: BKE_bmesh.h,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BMESH_PRIVATE_H
+#define BMESH_PRIVATE_H
+
+#include "bmesh.h"
+struct Link;
+struct BMLoop;
+
+/*returns positive nonzero on error*/
+int bmesh_check_element(BMesh *bm, void *element, int type);
+
+#define CHECK_ELEMENT(bm, el) \
+if (bmesh_check_element(bm, el, ((BMHeader*)el)->type))\
+ printf("check_element failure, with code %i on line %i in file\n \"%s\"\n\n", bmesh_check_element(bm, el, ((BMHeader*)el)->type), __LINE__, __FILE__);
+
+#define bm_get_edge_link(e, v) (Link*)((v) == ((BMEdge*)(e))->v1 ? &(((BMEdge*)(e))->dlink1) : &(((BMEdge*)(e))->dlink2))
+
+int bmesh_radial_length(struct BMLoop *l);
+int bmesh_disk_count(BMVert *v);
+
+/*start/stop edit*/
+void bmesh_begin_edit(struct BMesh *bm);
+void bmesh_end_edit(struct BMesh *bm, int flag);
+
+/*internal selection flushing*/
+void bmesh_selectmode_flush(struct BMesh *bm);
+
+/*internal filter API*/
+void *bmesh_get_filter_callback(int type);
+int bmesh_get_filter_argtype(int type);
+
+/*system flag access*/
+void bmesh_set_sysflag(struct BMHeader *element, int flag);
+void bmesh_clear_sysflag(struct BMHeader *element, int flag);
+int bmesh_test_sysflag(struct BMHeader *element, int flag);
+
+/*NOTE: ensure different parts of the API do not conflict
+ on using these internal flags!*/
+#define _FLAG_JF 1 /*join faces*/
+#define _FLAG_SF 2 /*split faces*/
+#define _FLAG_MF 4 /*make face*/
+
+#define bmesh_api_setflag(element, f) (((BMHeader*)(element))->flags[0].pflag |= (f))
+#define bmesh_api_getflag(element, f) (((BMHeader*)(element))->flags[0].pflag & (f))
+#define bmesh_api_clearflag(element, f) (((BMHeader*)(element))->flags[0].pflag &= ~(f))
+
+/*Polygon Utilities ? FIXME... where do these each go?*/
+/*newedgeflag sets a flag layer flag, obviously not the header flag.*/
+void BM_Triangulate_Face(BMesh *bm, BMFace *f, float (*projectverts)[3],
+ int newedgeflag, int newfaceflag, BMFace **newfaces);
+void bmesh_update_face_normal(struct BMesh *bm, struct BMFace *f,
+ float (*projectverts)[3]);
+void compute_poly_plane(float (*verts)[3], int nverts);
+void poly_rotate_plane(float normal[3], float (*verts)[3], int nverts);
+void bmesh_flip_normal(struct BMesh *bm, struct BMFace *f);
+
+/*Error reporting. Shouldnt be called by tools ever.*/
+void BME_error(void);
+
+BMEdge *bmesh_disk_next(BMEdge *e, BMVert *v);
+BMEdge *bmesh_disk_prev(BMEdge *e, BMVert *v);
+
+/*include the rest of our private declarations*/
+#include "bmesh_structure.h"
+#include "bmesh_operators_private.h"
+
+#endif
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
new file mode 100644
index 00000000000..0d6e0c45050
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -0,0 +1,541 @@
+#include <string.h>
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include "BKE_utildefines.h"
+
+#include "BLI_math.h"
+#include "BLI_array.h"
+#include "BLI_utildefines.h"
+
+#define BM_OVERLAP (1<<13)
+
+/*
+ * BM_QUERIES.C
+ *
+ * This file contains functions for answering common
+ * Topological and geometric queries about a mesh, such
+ * as, "What is the angle between these two faces?" or,
+ * "How many faces are incident upon this vertex?" Tool
+ * authors should use the functions in this file instead
+ * of inspecting the mesh structure directly.
+ *
+*/
+
+/*
+ * BMESH COUNT ELEMENT
+ *
+ * Return the amount of element of
+ * type 'type' in a given bmesh.
+ *
+ *
+*/
+
+int BM_Count_Element(BMesh *bm, int type)
+{
+ if(type == BM_VERT) return bm->totvert;
+ else if(type == BM_EDGE) return bm->totedge;
+ else if(type == BM_FACE) return bm->totface;
+
+ return 0;
+}
+
+
+/*
+ * BMESH VERT IN EDGE
+ *
+ * Returns whether or not a given vertex is
+ * is part of a given edge.
+ *
+*/
+
+int BM_Vert_In_Edge(BMEdge *e, BMVert *v)
+{
+ return bmesh_vert_in_edge(e, v);
+}
+
+/*
+ * BMESH OTHER EDGE IN FACE SHARING A VERTEX
+ *
+ * Returns an opposing loop that shares the same face.
+ *
+*/
+
+BMLoop *BM_OtherFaceLoop(BMEdge *e, BMFace *f, BMVert *v)
+{
+ BMLoop *l = bm_firstfaceloop(f), *l2, *l3;
+ int found = 0;
+
+ do {
+ if (l->e == e) break;
+ found = 1;
+ l = l->next;
+ } while (l != bm_firstfaceloop(f));
+
+ return l->v == v ? l->prev : l->next;
+}
+
+/*
+ * BMESH VERT IN FACE
+ *
+ * Returns whether or not a given vertex is
+ * is part of a given face.
+ *
+*/
+
+int BM_Vert_In_Face(BMFace *f, BMVert *v)
+{
+ BMLoopList *lst;
+ BMLoop *l;
+
+ for (lst=f->loops.first; lst; lst=lst->next) {
+ l = lst->first;
+ do {
+ if(l->v == v) return 1;
+ l = l->next;
+ } while (l != lst->first);
+ }
+
+ return 0;
+}
+
+/*
+ * BMESH VERTS IN FACE
+ *
+ * Compares the number of vertices in an array
+ * that appear in a given face
+ *
+*/
+int BM_Verts_In_Face(BMesh *bm, BMFace *f, BMVert **varr, int len)
+{
+ BMLoopList *lst;
+ BMLoop *curloop = NULL;
+ int i, count = 0;
+
+ for(i=0; i < len; i++) BMO_SetFlag(bm, varr[i], BM_OVERLAP);
+
+ for (lst=f->loops.first; lst; lst=lst->next) {
+ curloop = lst->first;
+
+ do {
+ if(BMO_TestFlag(bm, curloop->v, BM_OVERLAP))
+ count++;
+
+ curloop = curloop->next;
+ } while (curloop != lst->first);
+ }
+
+ for(i=0; i < len; i++) BMO_ClearFlag(bm, varr[i], BM_OVERLAP);
+
+ return count;
+}
+
+/*
+ * BMESH EDGE IN FACE
+ *
+ * Returns whether or not a given edge is
+ * is part of a given face.
+ *
+*/
+
+int BM_Edge_In_Face(BMFace *f, BMEdge *e)
+{
+ BMLoop *l;
+
+ l = bm_firstfaceloop(f);
+ do{
+
+ if(l->e == e) return 1;
+ l = ((BMLoop*)(l->next));
+ }while(l != bm_firstfaceloop(f));
+
+ return 0;
+}
+
+/*
+ * BMESH VERTS IN EDGE
+ *
+ * Returns whether or not two vertices are in
+ * a given edge
+ *
+*/
+
+int BM_Verts_In_Edge(BMVert *v1, BMVert *v2, BMEdge *e)
+{
+ return bmesh_verts_in_edge(v1,v2,e);
+}
+
+/*
+ * BMESH GET OTHER EDGEVERT
+ *
+ * Given a edge and one of its vertices, returns
+ * the other vertex.
+ *
+*/
+
+BMVert *BM_OtherEdgeVert(BMEdge *e, BMVert *v)
+{
+ return bmesh_edge_getothervert(e,v);
+}
+
+/*
+ * BMESH VERT EDGECOUNT
+ *
+ * Returns the number of edges around this vertex.
+ */
+
+int BM_Vert_EdgeCount(BMVert *v)
+{
+ return bmesh_disk_count(v);
+}
+
+/**
+ * BMESH EDGE FACECOUNT
+ *
+ * Returns the number of faces around this edge
+*/
+
+int BM_Edge_FaceCount(BMEdge *e)
+{
+ int count = 0;
+ BMLoop *curloop = NULL;
+
+ if(e->l){
+ curloop = e->l;
+ do{
+ count++;
+ curloop = bmesh_radial_nextloop(curloop);
+ }while(curloop != e->l);
+ }
+
+ return count;
+}
+
+/**
+ * BMESH VERT FACECOUNT
+ *
+ * Returns the number of faces around this vert
+*/
+
+int BM_Vert_FaceCount(BMVert *v){
+ int count = 0;
+ BMLoop *l;
+ BMIter iter;
+
+ BM_ITER(l, &iter, NULL, BM_LOOPS_OF_VERT, v)
+ count++;
+
+ return count;
+#if 0 //this code isn't working
+ BMEdge *curedge = NULL;
+
+ if(v->e){
+ curedge = v->e;
+ do{
+ if(curedge->l) count += BM_Edge_FaceCount(curedge);
+ curedge = bmesh_disk_nextedge(curedge,v);
+ }while(curedge != v->e);
+ }
+ return count;
+#endif
+}
+
+/**
+ * BMESH WIRE VERT
+ *
+ * Tests whether or not the vertex is part of a wire edge.
+ * (ie: has no faces attached to it)
+ *
+ * Returns -
+ * 1 for true, 0 for false.
+ */
+
+int BM_Wire_Vert(BMesh *bm, BMVert *v)
+{
+ BMEdge *curedge;
+
+ if(!(v->e)) return 0;
+
+ curedge = v->e;
+ do{
+ if(curedge->l) return 0;
+ curedge = bmesh_disk_nextedge(curedge, v);
+ }while(curedge != v->e);
+
+ return 1;
+}
+
+/**
+ * BMESH WIRE EDGE
+ *
+ * Tests whether or not the edge is part of a wire.
+ * (ie: has no faces attached to it)
+ *
+ * Returns -
+ * 1 for true, 0 for false.
+ */
+
+int BM_Wire_Edge(BMesh *bm, BMEdge *e)
+{
+ if(e->l) return 0;
+ return 1;
+}
+
+/**
+ * BMESH NONMANIFOLD VERT
+ *
+ * A vertex is non-manifold if it meets the following conditions:
+ * 1: Loose - (has no edges/faces incident upon it)
+ * 2: Joins two distinct regions - (two pyramids joined at the tip)
+ * 3: Is part of a non-manifold edge (edge with more than 2 faces)
+ * 4: Is part of a wire edge
+ *
+ * Returns -
+ * 1 for true, 0 for false.
+ */
+
+int BM_Nonmanifold_Vert(BMesh *bm, BMVert *v) {
+ BMEdge *e, *oe;
+ BMLoop *l;
+ int len, count, flag;
+
+ if (v->e == NULL) {
+ /* loose vert */
+ return 1;
+ }
+
+ /* count edges while looking for non-manifold edges */
+ oe = v->e;
+ for (len=0,e=v->e; e != oe || (e == oe && len == 0); len++,e=bmesh_disk_nextedge(e,v)) {
+ if (e->l == NULL) {
+ /* loose edge */
+ return 1;
+ }
+
+ if (bmesh_radial_length(e->l) > 2) {
+ /* edge shared by more than two faces */
+ return 1;
+ }
+ }
+
+ count = 1;
+ flag = 1;
+ e = NULL;
+ oe = v->e;
+ l = oe->l;
+ while(e != oe) {
+ if (l->v == v) l = ((BMLoop*)(l->prev));
+ else l = ((BMLoop*)(l->next));
+ e = l->e;
+ count++; /* count the edges */
+
+ if (flag && l->radial_next == l) {
+ /* we've hit the edge of an open mesh, reset once */
+ flag = 0;
+ count = 1;
+ oe = e;
+ e = NULL;
+ l = oe->l;
+ }
+ else if (l->radial_next == l) {
+ /* break the loop */
+ e = oe;
+ }
+ else {
+ l = l->radial_next;
+ }
+ }
+
+ if (count < len) {
+ /* vert shared by multiple regions */
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * BMESH NONMANIFOLD EDGE
+ *
+ * Tests whether or not this edge is manifold.
+ * A manifold edge either has 1 or 2 faces attached
+ * to it.
+ *
+ * Returns -
+ * 1 for true, 0 for false.
+ */
+
+int BM_Nonmanifold_Edge(BMesh *bm, BMEdge *e)
+{
+ int count = BM_Edge_FaceCount(e);
+ if(count != 2 && count != 1) return 1;
+ return 0;
+}
+
+/**
+ * BMESH BOUNDARY EDGE
+ *
+ * Tests whether or not an edge is on the boundary
+ * of a shell (has one face associated with it)
+ *
+ * Returns -
+ * 1 for true, 0 for false.
+ */
+
+int BM_Boundary_Edge(BMEdge *e)
+{
+ int count = BM_Edge_FaceCount(e);
+ if(count == 1) return 1;
+ return 0;
+}
+
+/**
+ * BMESH FACE SHAREDEDGES
+ *
+ * Counts the number of edges two faces share (if any)
+ *
+ * TODO:
+ * Move this to structure, and wrap.
+ *
+ * Returns -
+ * Integer
+ */
+
+int BM_Face_Sharededges(BMFace *f1, BMFace *f2){
+ BMLoop *l;
+ int count = 0;
+
+ l = bm_firstfaceloop(f1);
+ do{
+ if(bmesh_radial_find_face(l->e,f2)) count++;
+ l = ((BMLoop*)(l->next));
+ }while(l != bm_firstfaceloop(f1));
+
+ return count;
+}
+
+/**
+ *
+ * BMESH EDGE SHARE FACES
+ *
+ * Tests to see if e1 shares any faces with e2
+ *
+*/
+
+int BM_Edge_Share_Faces(BMEdge *e1, BMEdge *e2)
+{
+ BMLoop *l;
+ BMFace *f;
+
+ if(e1->l && e2->l){
+ l = e1->l;
+ do{
+ f = l->f;
+ if(bmesh_radial_find_face(e2,f)){
+ return 1;
+ }
+ l = (BMLoop*)(l->radial_next);
+ }while(l != e1->l);
+ }
+ return 0;
+}
+
+
+
+/**
+ * BMESH FACE ANGLE
+ *
+ * Calculates the angle between two faces. Assumes
+ * That face normals are correct.
+ *
+ * Returns -
+ * Float.
+ */
+
+float BM_Face_Angle(BMesh *bm, BMEdge *e)
+{
+ BMLoop *l1, *l2;
+ int radlen;
+ float edge_angle_cos = 0.0;
+
+ radlen = BM_Edge_FaceCount(e);
+ if(radlen == 2){
+ l1 = e->l;
+ l2 = e->l->radial_next;
+ edge_angle_cos = INPR(l1->f->no, l2->f->no);
+ }
+ return edge_angle_cos;
+
+}
+
+/*
+ * BMESH EXIST FACE OVERLAPS
+ *
+ * Given a set of vertices (varr), find out if
+ * all those vertices overlap an existing face.
+ *
+ * Returns:
+ * 0 for no overlap
+ * 1 for overlap
+ *
+ *
+*/
+
+int BM_Exist_Face_Overlaps(BMesh *bm, BMVert **varr, int len, BMFace **overlapface)
+{
+ BMIter vertfaces;
+ BMFace *f;
+ int i, amount;
+
+ if (overlapface) *overlapface = NULL;
+
+ for(i=0; i < len; i++){
+ f = BMIter_New(&vertfaces, bm, BM_FACES_OF_VERT, varr[i] );
+ while(f){
+ amount = BM_Verts_In_Face(bm, f, varr, len);
+ if(amount >= len){
+ if (overlapface) *overlapface = f;
+ return 1;
+ }
+ f = BMIter_Step(&vertfaces);
+ }
+ }
+ return 0;
+}
+
+/*
+ * BMESH FACE EXISTS
+ *
+ * Given a set of vertices (varr), find out if
+ * there is a face with exactly those vertices
+ * (and only those vertices).
+ *
+ * Returns:
+ * 0 for no face found
+ * 1 for face found
+ *
+ *
+*/
+
+int BM_Face_Exists(BMesh *bm, BMVert **varr, int len, BMFace **existface)
+{
+ BMIter vertfaces;
+ BMFace *f;
+ int i, amount;
+
+ if (existface) *existface = NULL;
+
+ for(i=0; i < len; i++){
+ f = BMIter_New(&vertfaces, bm, BM_FACES_OF_VERT, varr[i] );
+ while(f){
+ amount = BM_Verts_In_Face(bm, f, varr, len);
+ if(amount == len && amount == f->len){
+ if (existface) *existface = f;
+ return 1;
+ }
+ f = BMIter_Step(&vertfaces);
+ }
+ }
+ return 0;
+}
diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c
new file mode 100644
index 00000000000..3e71a9fee82
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_structure.c
@@ -0,0 +1,938 @@
+/**
+ * bmesh_structure.c jan 2007
+ *
+ * Low level routines for manipulating the BM structure.
+ *
+ * $Id: bmesh_structure.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** 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.
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "BKE_utildefines.h"
+#include "bmesh.h"
+#include "bmesh_private.h"
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+#include "BLI_ghash.h"
+/**
+ * MISC utility functions.
+ *
+ */
+
+int bmesh_vert_in_edge(BMEdge *e, BMVert *v){
+ if(e->v1 == v || e->v2 == v) return 1;
+ return 0;
+}
+int bmesh_verts_in_edge(BMVert *v1, BMVert *v2, BMEdge *e){
+ if(e->v1 == v1 && e->v2 == v2) return 1;
+ else if(e->v1 == v2 && e->v2 == v1) return 1;
+ return 0;
+}
+
+BMVert *bmesh_edge_getothervert(BMEdge *e, BMVert *v){
+ if(e->v1 == v) return e->v2;
+ else if(e->v2 == v) return e->v1;
+ return NULL;
+}
+
+int bmesh_edge_swapverts(BMEdge *e, BMVert *orig, BMVert *newv){
+ if(e->v1 == orig){
+ e->v1 = newv;
+ e->dlink1.next = e->dlink1.prev = NULL;
+ return 1;
+ }
+ else if(e->v2 == orig){
+ e->v2 = newv;
+ e->dlink2.next = e->dlink2.prev = NULL;
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * BMESH CYCLES
+ * (this is somewhat outdate, though bits of its API are still used) - joeedh
+ *
+ * Cycles are circular doubly linked lists that form the basis of adjacency
+ * information in the BME modeller. Full adjacency relations can be derived
+ * from examining these cycles very quickly. Although each cycle is a double
+ * circular linked list, each one is considered to have a 'base' or 'head',
+ * and care must be taken by Euler code when modifying the contents of a cycle.
+ *
+ * The contents of this file are split into two parts. First there are the
+ * bmesh_cycle family of functions which are generic circular double linked list
+ * procedures. The second part contains higher level procedures for supporting
+ * modification of specific cycle types.
+ *
+ * The three cycles explicitly stored in the BM data structure are as follows:
+ *
+ * 1: The Disk Cycle - A circle of edges around a vertex
+ * Base: vertex->edge pointer.
+ *
+ * This cycle is the most complicated in terms of its structure. Each bmesh_Edge contains
+ * two bmesh_CycleNode structures to keep track of that edge's membership in the disk cycle
+ * of each of its vertices. However for any given vertex it may be the first in some edges
+ * in its disk cycle and the second for others. The bmesh_disk_XXX family of functions contain
+ * some nice utilities for navigating disk cycles in a way that hides this detail from the
+ * tool writer.
+ *
+ * Note that the disk cycle is completley independant from face data. One advantage of this
+ * is that wire edges are fully integrated into the topology database. Another is that the
+ * the disk cycle has no problems dealing with non-manifold conditions involving faces.
+ *
+ * Functions relating to this cycle:
+ *
+ * bmesh_disk_append_edge
+ * bmesh_disk_remove_edge
+ * bmesh_disk_nextedge
+ * bmesh_disk_getpointer
+ *
+ * 2: The Radial Cycle - A circle of face edges (bmesh_Loop) around an edge
+ * Base: edge->l->radial structure.
+ *
+ * The radial cycle is similar to the radial cycle in the radial edge data structure.*
+ * Unlike the radial edge however, the radial cycle does not require a large amount of memory
+ * to store non-manifold conditions since BM does not keep track of region/shell
+ * information.
+ *
+ * Functions relating to this cycle:
+ *
+ * bmesh_radial_append
+ * bmesh_radial_remove_loop
+ * bmesh_radial_nextloop
+ * bmesh_radial_find_face
+ *
+ *
+ * 3: The Loop Cycle - A circle of face edges around a polygon.
+ * Base: polygon->lbase.
+ *
+ * The loop cycle keeps track of a faces vertices and edges. It should be noted that the
+ * direction of a loop cycle is either CW or CCW depending on the face normal, and is
+ * not oriented to the faces editedges.
+ *
+ * Functions relating to this cycle:
+ *
+ * bmesh_cycle_XXX family of functions.
+ *
+ *
+ * Note that the order of elements in all cycles except the loop cycle is undefined. This
+ * leads to slightly increased seek time for deriving some adjacency relations, however the
+ * advantage is that no intrinsic properties of the data structures are dependant upon the
+ * cycle order and all non-manifold conditions are represented trivially.
+ *
+*/
+int bmesh_disk_append_edge(struct BMEdge *e, struct BMVert *v)
+{
+ if (!v->e) {
+ Link *e1 = (Link*)bm_get_edge_link(e, v);
+
+ v->e = e;
+ e1->next = e1->prev = (Link*)e;
+ } else {
+ Link *e1, *e2, *e3;
+
+ e1 = bm_get_edge_link(e, v);
+ e2 = bm_get_edge_link(v->e, v);
+ e3 = e2->prev ? bm_get_edge_link(e2->prev, v) : NULL;
+
+ e1->next = (Link*)v->e;
+ e1->prev = e2->prev;
+
+ e2->prev = (Link*)e;
+ if (e3)
+ e3->next = (Link*)e;
+ }
+
+ return 1;
+}
+
+void bmesh_disk_remove_edge(struct BMEdge *e, struct BMVert *v)
+{
+ Link *e1, *e2;
+
+ e1 = bm_get_edge_link(e, v);
+ if (e1->prev) {
+ e2 = bm_get_edge_link(e1->prev, v);
+ e2->next = e1->next;
+ }
+
+ if (e1->next) {
+ e2 = bm_get_edge_link(e1->next, v);
+ e2->prev = e1->prev;
+ }
+
+ if (v->e == e)
+ v->e = e!=e1->next ? (BMEdge*)e1->next : NULL;
+
+ e1->next = e1->prev = NULL;
+}
+
+struct BMEdge *bmesh_disk_nextedge(struct BMEdge *e, struct BMVert *v)
+{
+ if (v == e->v1)
+ return e->dlink1.next;
+ if (v == e->v2)
+ return e->dlink2.next;
+ return NULL;
+}
+
+BMEdge *bmesh_disk_prevedge(BMEdge *e, BMVert *v)
+{
+ if (v == e->v1)
+ return e->dlink1.prev;
+ if (v == e->v2)
+ return e->dlink2.prev;
+ return NULL;
+}
+
+int bmesh_disk_count(struct BMVert *v)
+{
+ BMEdge *e = v->e;
+ int i=0;
+
+ if (!e)
+ return 0;
+
+ do {
+ if (!e)
+ return 0;
+ e = bmesh_disk_nextedge(e, v);
+
+ if (i >= (1<<20)) {
+ printf("bmesh error: infinite loop in disk cycle!\n");
+ return 0;
+ }
+
+ i += 1;
+ } while (e != v->e);
+
+ return i;
+}
+
+int bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
+{
+ BMEdge *e2;
+
+ if (!BM_Vert_In_Edge(e, v))
+ return 0;
+ if (bmesh_disk_count(v) != len || len == 0)
+ return 0;
+
+ e2 = e;
+ do {
+ if (len!=1 && bmesh_disk_prevedge(e2, v) == e2)
+ return 0;
+
+ e2 = bmesh_disk_nextedge(e2, v);
+ } while (e2 != e);
+
+ return 1;
+}
+
+/*
+ * BME DISK COUNT FACE VERT
+ *
+ * Counts the number of loop users
+ * for this vertex. Note that this is
+ * equivalent to counting the number of
+ * faces incident upon this vertex
+ *
+*/
+
+int bmesh_disk_count_facevert(BMVert *v)
+{
+ BMEdge *curedge;
+ int count = 0;
+
+ /*is there an edge on this vert at all?*/
+ if(!v->e)
+ return count;
+
+ /*first, loop around edges*/
+ curedge = v->e;
+ do{
+ if(curedge->l) count += bmesh_radial_count_facevert(curedge->l, v);
+ curedge = bmesh_disk_nextedge(curedge, v);
+ }while(curedge != v->e);
+
+ return count;
+}
+
+struct BMEdge *bmesh_disk_find_first_faceedge(struct BMEdge *e, struct BMVert *v)
+{
+ BMEdge *searchedge = NULL;
+ searchedge = e;
+ do{
+ if(searchedge->l && bmesh_radial_count_facevert(searchedge->l,v)) return searchedge;
+ searchedge = bmesh_disk_nextedge(searchedge,v);
+ }while(searchedge != e);
+
+ return NULL;
+}
+
+struct BMEdge *bmesh_disk_find_next_faceedge(struct BMEdge *e, struct BMVert *v)
+{
+ BMEdge *searchedge = NULL;
+ searchedge = bmesh_disk_nextedge(e,v);
+ do{
+ if(searchedge->l && bmesh_radial_count_facevert(searchedge->l,v)) return searchedge;
+ searchedge = bmesh_disk_nextedge(searchedge,v);
+ }while(searchedge !=e);
+ return e;
+}
+
+/*****radial cycle functions, e.g. loops surrounding edges******/
+int bmesh_radial_validate(int radlen, BMLoop *l)
+{
+ BMLoop *l2 = l;
+
+ if (bmesh_radial_length(l) != radlen)
+ return 0;
+
+ do {
+ if (l2->e != l->e)
+ return 0;
+ if (l2->v != l->e->v1 && l2->v != l->e->v2)
+ return 0;
+
+ l2 = l2->radial_next;
+ } while (l2 != l);
+
+ return 1;
+}
+
+void bmesh_radial_remove_loop(BMLoop *l, BMEdge *e)
+{
+ if (l->radial_next != l) {
+ if (e && l == e->l)
+ e->l = l->radial_next;
+
+ l->radial_next->radial_prev = l->radial_prev;
+ l->radial_prev->radial_next = l->radial_next;
+ } else {
+ l->radial_next = l->radial_prev = NULL;
+ if (e && l == e->l)
+ e->l = NULL;
+ else if (e)
+ bmesh_error();
+ }
+}
+
+
+/*
+ * BME RADIAL FIND FIRST FACE VERT
+ *
+ * Finds the first loop of v around radial
+ * cycle
+ *
+*/
+BMLoop *bmesh_radial_find_first_facevert(BMLoop *l, BMVert *v)
+{
+ BMLoop *curloop;
+ curloop = l;
+ do{
+ if(curloop->v == v) return curloop;
+ curloop = bmesh_radial_nextloop(curloop);
+ }while(curloop != l);
+ return NULL;
+}
+
+BMLoop *bmesh_radial_find_next_facevert(BMLoop *l, BMVert *v)
+{
+ BMLoop *curloop;
+ curloop = bmesh_radial_nextloop(l);
+ do{
+ if(curloop->v == v) return curloop;
+ curloop = bmesh_radial_nextloop(curloop);
+ }while(curloop !=l);
+ return l;
+}
+
+BMLoop *bmesh_radial_nextloop(BMLoop *l)
+{
+ return l->radial_next;
+}
+
+int bmesh_radial_length(BMLoop *l)
+{
+ BMLoop *l2 = l;
+ int i = 0;
+
+ if (!l)
+ return 0;
+
+ do {
+ i++;
+ l2 = l2->radial_next;
+ if (i >= 555555)
+ return -1;
+ } while (l2 != l);
+
+ return i;
+}
+
+void bmesh_radial_append(BMEdge *e, BMLoop *l){
+ if(e->l == NULL) {
+ e->l = l;
+ l->radial_next = l->radial_prev = l;
+ } else {
+ l->radial_prev = e->l;
+ l->radial_next = e->l->radial_next;
+
+ e->l->radial_next->radial_prev = l;
+ e->l->radial_next = l;
+
+ e->l = l;
+ }
+}
+
+int bmesh_radial_find_face(BMEdge *e, BMFace *f)
+{
+ BMLoop *curloop;
+ int i, len;
+
+ len = bmesh_radial_length(e->l);
+ for(i = 0, curloop = e->l; i < len; i++, curloop = curloop->radial_next) {
+ if(curloop->f == f)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * BME RADIAL COUNT FACE VERT
+ *
+ * Returns the number of times a vertex appears
+ * in a radial cycle
+ *
+*/
+
+int bmesh_radial_count_facevert(BMLoop *l, BMVert *v)
+{
+ BMLoop *curloop;
+ int count = 0;
+ curloop = l;
+ do{
+ if(curloop->v == v) count++;
+ curloop = bmesh_radial_nextloop(curloop);
+ }while(curloop != l);
+ return count;
+}
+
+#if 0
+ void bmesh_cycle_append(void *h, void *nt)
+{
+ BMNode *oldtail, *head, *newtail;
+
+ head = (BMNode*)h;
+ newtail = (BMNode*)nt;
+
+ if(head->next == NULL){
+ head->next = newtail;
+ head->prev = newtail;
+ newtail->next = head;
+ newtail->prev = head;
+ }
+ else{
+ oldtail = head->prev;
+ oldtail->next = newtail;
+ newtail->next = head;
+ newtail->prev = oldtail;
+ head->prev = newtail;
+
+ }
+}
+
+/**
+ * bmesh_cycle_length
+ *
+ * Count the nodes in a cycle.
+ *
+ * Returns -
+ * Integer
+ */
+
+int bmesh_cycle_length(BMEdge *e, BMVert *v) {
+ BMEdge *next, *prev, *cur;
+ int len, vi = v == e->v1 ? 0 : 1;
+
+ /*should skip 2 forward if v is 1, happily reduces to
+ v*2*/
+ prev = *(&e->v1_prev + vi*2);
+
+ cur = e;
+ len = 1;
+ while (cur != prev) {
+ vi = cur->v1 == v ? 0 : 1;
+
+ len++;
+ cur = *(&cur->v1_next + vi*2);
+ }
+
+ return len;
+}
+
+/**
+ * bmesh_cycle_remove
+ *
+ * Removes a node from a cycle.
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+ */
+
+int bmesh_cycle_remove(void *h, void *remn)
+{
+ int i, len;
+ BMNode *head, *remnode, *curnode;
+
+ head = (BMNode*)h;
+ remnode = (BMNode*)remn;
+ len = bmesh_cycle_length(h);
+
+ if(len == 1 && head == remnode){
+ head->next = NULL;
+ head->prev = NULL;
+ return 1;
+ }
+ else{
+ for(i=0, curnode = head; i < len; curnode = curnode->next){
+ if(curnode == remnode){
+ remnode->prev->next = remnode->next;
+ remnode->next->prev = remnode->prev;
+ /*zero out remnode pointers, important!*/
+ //remnode->next = NULL;
+ //remnode->prev = NULL;
+ return 1;
+
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * bmesh_cycle_validate
+ *
+ * Validates a cycle. Takes as an argument the expected length of the cycle and
+ * a pointer to the cycle head or base.
+ *
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+ */
+
+int bmesh_cycle_validate(int len, void *h){
+ int i;
+ BMNode *curnode, *head;
+ head = (BMNode*)h;
+
+ /*forward validation*/
+ for(i = 0, curnode = head; i < len; i++, curnode = curnode->next);
+ if(curnode != head) return 0;
+
+ /*reverse validation*/
+ for(i = 0, curnode = head; i < len; i++, curnode = curnode->prev);
+ if(curnode != head) return 0;
+
+ return 1;
+}
+
+/*Begin Disk Cycle routines*/
+
+/**
+ * bmesh_disk_nextedge
+ *
+ * Find the next edge in a disk cycle
+ *
+ * Returns -
+ * Pointer to the next edge in the disk cycle for the vertex v.
+ */
+
+BMEdge *bmesh_disk_nextedge(BMEdge *e, BMVert *v)
+{
+ if(bmesh_vert_in_edge(e, v)){
+ if(e->v1 == v) return e->d1.next->data;
+ else if(e->v2 == v) return e->d2.next->data;
+ }
+ return NULL;
+}
+
+/**
+ * bmesh_disk_getpointer
+ *
+ * Given an edge and one of its vertices, find the apporpriate CycleNode
+ *
+ * Returns -
+ * Pointer to bmesh_CycleNode.
+ */
+BMNode *bmesh_disk_getpointer(BMEdge *e, BMVert *v){
+ /*returns pointer to the cycle node for the appropriate vertex in this disk*/
+ if(e->v1 == v) return &(e->d1);
+ else if (e->v2 == v) return &(e->d2);
+ return NULL;
+}
+
+/**
+ * bmesh_disk_append_edge
+ *
+ * Appends edge to the end of a vertex disk cycle.
+ *
+ * Returns -
+ * 1 for success, 0 for failure
+ */
+
+int bmesh_disk_append_edge(BMEdge *e, BMVert *v)
+{
+
+ BMNode *base, *tail;
+
+ if(bmesh_vert_in_edge(e, v) == 0) return 0; /*check to make sure v is in e*/
+
+ /*check for loose vert first*/
+ if(v->e == NULL){
+ v->e = e;
+ base = tail = bmesh_disk_getpointer(e, v);
+ bmesh_cycle_append(base, tail); /*circular reference is ok!*/
+ return 1;
+ }
+
+ /*insert e at the end of disk cycle and make it the new v->e*/
+ base = bmesh_disk_getpointer(v->e, v);
+ tail = bmesh_disk_getpointer(e, v);
+ bmesh_cycle_append(base, tail);
+ return 1;
+}
+
+/**
+ * bmesh_disk_remove_edge
+ *
+ * Removes an edge from a disk cycle. If the edge to be removed is
+ * at the base of the cycle, the next edge becomes the new base.
+ *
+ *
+ * Returns -
+ * Nothing
+ */
+
+void bmesh_disk_remove_edge(BMEdge *e, BMVert *v)
+{
+ BMNode *base, *remnode;
+ BMEdge *newbase;
+ int len;
+
+ base = bmesh_disk_getpointer(v->e, v);
+ remnode = bmesh_disk_getpointer(e, v);
+
+ /*first deal with v->e pointer...*/
+ len = bmesh_cycle_length(base);
+ if(len == 1) newbase = NULL;
+ else if(v->e == e) newbase = base->next-> data;
+ else newbase = v->e;
+
+ /*remove and rebase*/
+ bmesh_cycle_remove(base, remnode);
+ v->e = newbase;
+}
+
+/**
+ * bmesh_disk_next_edgeflag
+ *
+ * Searches the disk cycle of v, starting with e, for the
+ * next edge that has either eflag or tflag.
+ *
+ * bmesh_Edge pointer.
+ */
+
+BMEdge *bmesh_disk_next_edgeflag(BMEdge *e, BMVert *v, int eflag, int tflag)
+{
+
+ BMNode *diskbase;
+ BMEdge *curedge;
+ int len, ok;
+
+ if(eflag && tflag) return NULL;
+
+ ok = bmesh_vert_in_edge(e,v);
+ if(ok){
+ diskbase = bmesh_disk_getpointer(e, v);
+ len = bmesh_cycle_length(diskbase);
+ curedge = bmesh_disk_nextedge(e,v);
+ while(curedge != e){
+ if(eflag){
+ if(curedge->head.eflag1 == eflag) return curedge;
+ }
+ curedge = bmesh_disk_nextedge(curedge, v);
+ }
+ }
+ return NULL;
+}
+
+/**
+ * bmesh_disk_count_edgeflag
+ *
+ * Counts number of edges in this verts disk cycle which have
+ * either eflag or tflag (but not both!)
+ *
+ * Returns -
+ * Integer.
+ */
+
+int bmesh_disk_count_edgeflag(BMVert *v, int eflag, int tflag)
+{
+ BMNode *diskbase;
+ BMEdge *curedge;
+ int i, len=0, count=0;
+
+ if(v->e){
+ if(eflag && tflag) return 0; /*tflag and eflag are reserved for different functions!*/
+ diskbase = bmesh_disk_getpointer(v->e, v);
+ len = bmesh_cycle_length(diskbase);
+
+ for(i = 0, curedge=v->e; i<len; i++){
+ if(eflag){
+ if(curedge->head.eflag1 == eflag) count++;
+ }
+ curedge = bmesh_disk_nextedge(curedge, v);
+ }
+ }
+ return count;
+}
+
+
+int bmesh_disk_hasedge(BMVert *v, BMEdge *e){
+ BMNode *diskbase;
+ BMEdge *curedge;
+ int i, len=0;
+
+ if(v->e){
+ diskbase = bmesh_disk_getpointer(v->e,v);
+ len = bmesh_cycle_length(diskbase);
+
+ for(i = 0, curedge=v->e; i<len; i++){
+ if(curedge == e) return 1;
+ else curedge=bmesh_disk_nextedge(curedge, v);
+ }
+ }
+ return 0;
+}
+
+BMEdge *bmesh_disk_existedge(BMVert *v1, BMVert *v2){
+ BMNode *diskbase;
+ BMEdge *curedge;
+ int i, len=0;
+
+ if(v1->e){
+ diskbase = bmesh_disk_getpointer(v1->e,v1);
+ len = bmesh_cycle_length(diskbase);
+
+ for(i=0,curedge=v1->e;i<len;i++,curedge = bmesh_disk_nextedge(curedge,v1)){
+ if(bmesh_verts_in_edge(v1,v2,curedge)) return curedge;
+ }
+ }
+
+ return NULL;
+}
+
+/*end disk cycle routines*/
+
+BMLoop *bmesh_radial_nextloop(BMLoop *l){
+ return (BMLoop*)(l->radial_next);
+}
+
+void bmesh_radial_append(BMEdge *e, BMLoop *l){
+ if(e->l == NULL) e->l = l;
+ bmesh_cycle_append(&(e->l->radial), &(l->radial));
+}
+
+void bmesh_radial_remove_loop(BMLoop *l, BMEdge *e)
+{
+ BMLoop *newbase;
+ int len;
+
+ /*deal with edge->l pointer*/
+ len = bmesh_cycle_length(&(e->l->radial));
+ if(len == 1) newbase = NULL;
+ else if(e->l == l) newbase = e->l->radial_next;
+ else newbase = e->l;
+
+ /*remove and rebase*/
+ bmesh_cycle_remove(&(e->l->radial), &(l->radial));
+ e->l = newbase;
+}
+
+int bmesh_radial_find_face(BMEdge *e,BMFace *f)
+{
+
+ BMLoop *curloop;
+ int i, len;
+
+ len = bmesh_cycle_length(&(e->l->radial));
+ for(i = 0, curloop = e->l; i < len; i++, curloop = curloop->radial_next){
+ if(curloop->f == f) return 1;
+ }
+ return 0;
+}
+
+
+/*
+ * BME RADIAL COUNT FACE VERT
+ *
+ * Returns the number of times a vertex appears
+ * in a radial cycle
+ *
+*/
+
+int bmesh_radial_count_facevert(BMLoop *l, BMVert *v)
+{
+ BMLoop *curloop;
+ int count = 0;
+ curloop = l;
+ do{
+ if(curloop->v == v) count++;
+ curloop = bmesh_radial_nextloop(curloop);
+ }while(curloop != l);
+ return count;
+}
+
+/*
+ * BME DISK COUNT FACE VERT
+ *
+ * Counts the number of loop users
+ * for this vertex. Note that this is
+ * equivalent to counting the number of
+ * faces incident upon this vertex
+ *
+*/
+
+int bmesh_disk_count_facevert(BMVert *v)
+{
+ BMEdge *curedge;
+ int count = 0;
+
+ /*is there an edge on this vert at all?*/
+ if(!v->e)
+ return count;
+
+ /*first, loop around edges*/
+ curedge = v->e;
+ do{
+ if(curedge->l) count += bmesh_radial_count_facevert(curedge->l, v);
+ curedge = bmesh_disk_nextedge(curedge, v);
+ }while(curedge != v->e);
+
+ return count;
+}
+
+/*
+ * BME RADIAL FIND FIRST FACE VERT
+ *
+ * Finds the first loop of v around radial
+ * cycle
+ *
+*/
+BMLoop *bmesh_radial_find_first_facevert(BMLoop *l, BMVert *v)
+{
+ BMLoop *curloop;
+ curloop = l;
+ do{
+ if(curloop->v == v) return curloop;
+ curloop = bmesh_radial_nextloop(curloop);
+ }while(curloop != l);
+ return NULL;
+}
+
+BMLoop *bmesh_radial_find_next_facevert(BMLoop *l, BMVert *v)
+{
+ BMLoop *curloop;
+ curloop = bmesh_radial_nextloop(l);
+ do{
+ if(curloop->v == v) return curloop;
+ curloop = bmesh_radial_nextloop(curloop);
+ }while(curloop !=l);
+ return l;
+}
+
+
+/*
+ * BME FIND FIRST FACE EDGE
+ *
+ * Finds the first edge in a vertices
+ * Disk cycle that has one of this
+ * vert's loops attached
+ * to it.
+ *
+ *
+*/
+
+BMEdge *bmesh_disk_find_first_faceedge(BMEdge *e, BMVert *v)
+{
+ BMEdge *searchedge = NULL;
+ searchedge = e;
+ do{
+ if(searchedge->l && bmesh_radial_count_facevert(searchedge->l,v)) return searchedge;
+ searchedge = bmesh_disk_nextedge(searchedge,v);
+ }while(searchedge != e);
+
+ return NULL;
+}
+
+BMEdge *bmesh_disk_find_next_faceedge(BMEdge *e, BMVert *v)
+{
+ BMEdge *searchedge = NULL;
+ searchedge = bmesh_disk_nextedge(e,v);
+ do{
+ if(searchedge->l && bmesh_radial_count_facevert(searchedge->l,v)) return searchedge;
+ searchedge = bmesh_disk_nextedge(searchedge,v);
+ }while(searchedge !=e);
+ return e;
+}
+
+
+
+
+
+struct BMLoop *bmesh_loop_find_loop(struct BMFace *f, struct BMVert *v) {
+ BMLoop *l;
+ int i, len;
+
+ len = bmesh_cycle_length(f->lbase);
+ for (i = 0, l=f->loopbase; i < len; i++, l=((BMLoop*)(l->next)) ) {
+ if (l->v == v) return l;
+ }
+ return NULL;
+}
+
+#endif
diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h
new file mode 100644
index 00000000000..58f7cbc16f2
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_structure.h
@@ -0,0 +1,100 @@
+/**
+ * bmesh_structure.h jan 2007
+ *
+ * The lowest level of functionality for manipulating bmesh structures.
+ * None of these functions should ever be exported to the rest of Blender.
+ *
+ * ***** 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BM_STRUCTURE_H
+#define BM_STRUCTURE_H
+
+/*low-level, base bmesh API. in the vast majority of cases thes should not be
+ used directly. if absolutely necassary, see function defitions in code for
+ descriptive comments. but seriously, don't use this stuff.
+*/
+struct ListBase;
+
+void remove_loop_radial_link(BMLoop *l);
+
+/*DOUBLE CIRCULAR LINKED LIST FUNCTIONS*/
+void bmesh_cycle_append(void *h, void *nt);
+int bmesh_cycle_remove(void *h, void *remn);
+int bmesh_cycle_validate(int len, void *h);
+int bmesh_cycle_length(void *h);
+
+/*DISK CYCLE MANAGMENT*/
+int bmesh_disk_append_edge(struct BMEdge *e, struct BMVert *v);
+void bmesh_disk_remove_edge(struct BMEdge *e, struct BMVert *v);
+struct BMEdge *bmesh_disk_nextedge(struct BMEdge *e, struct BMVert *v);
+struct BMNode *bmesh_disk_getpointer(struct BMEdge *e, struct BMVert *v);
+int bmesh_disk_count_facevert(struct BMVert *v);
+struct BMEdge *bmesh_disk_find_first_faceedge(struct BMEdge *e, struct BMVert *v);
+struct BMEdge *bmesh_disk_find_next_faceedge(struct BMEdge *e, struct BMVert *v);
+
+/*RADIAL CYCLE MANAGMENT*/
+void bmesh_radial_append(struct BMEdge *e, struct BMLoop *l);
+void bmesh_radial_remove_loop(struct BMLoop *l, struct BMEdge *e);
+int bmesh_radial_find_face(struct BMEdge *e, struct BMFace *f);
+struct BMLoop *bmesh_radial_nextloop(struct BMLoop *l);
+int bmesh_radial_count_facevert(struct BMLoop *l, struct BMVert *v);
+struct BMLoop *bmesh_radial_find_first_facevert(struct BMLoop *l, struct BMVert *v);
+struct BMLoop *bmesh_radial_find_next_facevert(struct BMLoop *l, struct BMVert *v);
+int bmesh_radial_validate(int radlen, struct BMLoop *l);
+
+/*EDGE UTILITIES*/
+int bmesh_vert_in_edge(struct BMEdge *e, struct BMVert *v);
+int bmesh_verts_in_edge(struct BMVert *v1, struct BMVert *v2, struct BMEdge *e);
+int bmesh_edge_swapverts(struct BMEdge *e, struct BMVert *orig, struct BMVert *newv); /*relink edge*/
+struct BMVert *bmesh_edge_getothervert(struct BMEdge *e, struct BMVert *v);
+int bmesh_disk_hasedge(struct BMVert *v, struct BMEdge *e);
+struct BMEdge *bmesh_disk_existedge(BMVert *v1, BMVert *v2);
+struct BMEdge *bmesh_disk_next_edgeflag(struct BMEdge *e, struct BMVert *v, int eflag, int tflag);
+int bmesh_disk_count_edgeflag(struct BMVert *v, int eflag, int tflag);
+int bmesh_disk_validate(int len, struct BMEdge *e, struct BMVert *v);
+
+/*EULER API - For modifying structure*/
+struct BMVert *bmesh_mv(struct BMesh *bm, float *vec);
+struct BMEdge *bmesh_me(struct BMesh *bm, struct BMVert *v1, struct BMVert *v2);
+struct BMFace *bmesh_mf(struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMEdge **elist, int len);
+int bmesh_kv(struct BMesh *bm, struct BMVert *v);
+int bmesh_ke(struct BMesh *bm, struct BMEdge *e);
+int bmesh_kf(struct BMesh *bm, struct BMFace *bply);
+struct BMVert *bmesh_semv(struct BMesh *bm, struct BMVert *tv, struct BMEdge *e, struct BMEdge **re);
+struct BMFace *bmesh_sfme(struct BMesh *bm, struct BMFace *f, struct BMVert *v1,
+ struct BMVert *v2, struct BMLoop **rl, struct ListBase *holes);
+int bmesh_jekv(struct BMesh *bm, struct BMEdge *ke, struct BMVert *kv);
+int bmesh_loop_reverse(struct BMesh *bm, struct BMFace *f);
+struct BMFace *bmesh_jfke(struct BMesh *bm, struct BMFace *f1, struct BMFace *f2, struct BMEdge *e);
+
+struct BMVert *bmesh_urmv(struct BMesh *bm, struct BMFace *sf, struct BMVert *sv);
+//int *bmesh_grkv(struct BMesh *bm, struct BMFace *sf, struct BMVert *kv);
+
+#endif
diff --git a/source/blender/bmesh/intern/bmesh_to_editmesh.c b/source/blender/bmesh/intern/bmesh_to_editmesh.c
new file mode 100644
index 00000000000..67b47064e68
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_to_editmesh.c
@@ -0,0 +1,318 @@
+#if 0
+#include "MEM_guardedalloc.h"
+#include "BKE_customdata.h"
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include <string.h>
+#include "BKE_utildefines.h"
+#include "BKE_mesh.h"
+#include "BKE_global.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
+
+#include "BLI_editVert.h"
+#include "mesh_intern.h"
+#include "ED_mesh.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
+#include "BLI_array.h"
+#include "BLI_array.h"
+
+#include "bmesh.h"
+
+/*
+ * BMESH TO EDITMESH
+ *
+ * This file contains functions for converting
+ * from a bmesh to an editmesh
+ *
+*/
+
+/*
+ * LOOPS TO EDITMESH CORNERS
+ *
+ * Converts N-Gon loop (face-edge)
+ * data (UVs, Verts Colors, ect) to
+ * face corner data.
+ *
+*/
+
+static void loops_to_editmesh_corners(BMesh *bm, CustomData *facedata, void *face_block, BMFace *f,int numCol, int numTex){
+ int i, j;
+ BMLoop *l;
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_em_get_n(facedata, face_block, CD_MTFACE, i);
+ texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
+
+ texface->tpage = texpoly->tpage;
+ texface->flag = texpoly->flag;
+ texface->transp = texpoly->transp;
+ texface->mode = texpoly->mode;
+ texface->tile = texpoly->tile;
+ texface->unwrap = texpoly->unwrap;
+
+ j = 0;
+ l = f->loopbase;
+ do {
+ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
+ texface->uv[j][0] = mloopuv->uv[0];
+ texface->uv[j][1] = mloopuv->uv[1];
+ j++;
+ l = ((BMLoop*)(l->next));
+ } while(l!=f->lbase);
+
+ }
+
+ for(i=0; i < numCol; i++){
+ mcol = CustomData_em_get_n(facedata, face_block, CD_MCOL, i);
+ j = 0;
+ l = f->loopbase;
+ do {
+ mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
+ mcol[j].r = mloopcol->r;
+ mcol[j].g = mloopcol->g;
+ mcol[j].b = mloopcol->b;
+ mcol[j].a = mloopcol->a;
+ j++;
+ l = ((BMLoop*)(l->next));
+ } while(l!=f->lbase);
+ }
+}
+
+static EditVert *bmeshvert_to_editvert(BMesh *bm, EditMesh *em, BMVert *v, int index, EditVert **evlist)
+{
+ EditVert *eve = NULL;
+
+ v->head.eflag1 = index; /*abuse!*/
+ eve = addvertlist(em, v->co, NULL);
+ eve->keyindex = index;
+ evlist[index]= eve;
+
+ /*copy flags*/
+ if(v->head.flag & BM_HIDDEN) eve->h = 1;
+ if (v->head.flag & BM_SELECT) eve->f |= SELECT;
+
+ eve->bweight = v->bweight;
+ CustomData_em_copy_data(&bm->vdata, &em->vdata, v->head.data, &eve->data);
+ /*copy normal*/
+ eve->no[0] = v->no[0];
+ eve->no[1] = v->no[1];
+ eve->no[2] = v->no[2];
+
+ return eve;
+}
+
+static void bmeshedge_to_editedge_internal(BMesh *bm, EditMesh *em, BMEdge *e, EditEdge *eed)
+{
+ eed->crease = e->crease;
+ eed->bweight = e->bweight;
+
+ //copy relavent flags
+ if (e->head.flag & BM_SELECT) eed->f |= SELECT;
+ if (e->head.flag & BM_SEAM) eed->seam = 1;
+ if (e->head.flag & BM_SHARP) eed->sharp = 1;
+ if (e->head.flag & BM_HIDDEN) eed->h = 1;
+ if (e->head.flag & BM_FGON) eed->h |= EM_FGON;
+
+ CustomData_em_copy_data(&bm->edata, &em->edata, e->head.data, &eed->data);
+}
+
+static EditEdge *bmeshedge_to_editedge(BMesh *bm, EditMesh *em, BMEdge *e, EditVert **evlist)
+{
+ EditEdge *eed = NULL;
+
+ if(!(findedgelist(em, evlist[e->v1->head.eflag1], evlist[e->v2->head.eflag1]))){
+ eed= addedgelist(em, evlist[e->v1->head.eflag1], evlist[e->v2->head.eflag1], NULL);
+ bmeshedge_to_editedge_internal(bm, em, e, eed);
+ }
+
+ return eed;
+}
+
+static EditFace *bmeshface_to_editface(BMesh *bm, EditMesh *em, BMFace *f, EditVert **evlist, int numCol, int numTex)
+{
+ EditVert *eve1, *eve2, *eve3, *eve4;
+ EditFace *efa = NULL;
+ int len;
+
+ len = f->len;
+
+ eve1= evlist[f->lbase->v->head.eflag1];
+ eve2= evlist[((BMLoop*)(f->lbase->next))->v->head.eflag1];
+ eve3= evlist[((BMLoop*)(f->lbase->next->next))->v->head.eflag1];
+ if (len == 4) {
+ eve4= evlist[ ((BMLoop*)(f->lbase->prev))->v->head.eflag1];
+ }
+ else {
+ eve4= NULL;
+ }
+
+ if (eve1==eve2 || eve1==eve3 || eve1==eve4 || eve2==eve3 || eve3==eve4
+ || eve2==eve4) return NULL;
+
+ efa = addfacelist(em, eve1, eve2, eve3, eve4, NULL, NULL);
+ if (!efa) return NULL;
+
+ bmeshedge_to_editedge_internal(bm, em, f->lbase->e, efa->e1);
+ bmeshedge_to_editedge_internal(bm, em, ((BMLoop*)(f->lbase->next))->e, efa->e2);
+ bmeshedge_to_editedge_internal(bm, em, ((BMLoop*)(f->lbase->next->next))->e, efa->e3);
+ if(eve4)
+ bmeshedge_to_editedge_internal(bm, em, ((BMLoop*)(f->lbase->prev))->e, efa->e4);
+
+ efa->mat_nr = (unsigned char)f->mat_nr;
+
+ /*Copy normal*/
+ efa->n[0] = f->no[0];
+ efa->n[1] = f->no[1];
+ efa->n[2] = f->no[2];
+
+ //copy relavent original flags
+ if (f->head.flag & BM_SELECT) efa->f |= SELECT;
+ if (f->head.flag & BM_HIDDEN) efa->h = 1;
+ if (f->head.flag & BM_SMOOTH) efa->flag |= ME_SMOOTH;
+ if (f->head.flag & BM_ACTIVE) EM_set_actFace(em, efa);
+
+ CustomData_em_copy_data(&bm->pdata, &em->fdata, f->head.data, &efa->data);
+ loops_to_editmesh_corners(bm, &em->fdata, efa->data, f, numCol,numTex);
+
+ return efa;
+}
+
+EditMesh *bmesh_to_editmesh_intern(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ EditMesh *em;
+ EditVert *eve, **evlist;
+
+ int totvert, i, numTex, numCol, flag;
+
+ em = MEM_callocN(sizeof(EditMesh), "EditMesh from bmesh");
+
+ em->selectmode = bm->selectmode;
+
+ flag = CD_MASK_BMESH & ~CD_MASK_MTEXPOLY;
+
+ CustomData_copy(&bm->vdata, &em->vdata, flag, CD_CALLOC, 0);
+ CustomData_copy(&bm->edata, &em->edata, flag, CD_CALLOC, 0);
+ CustomData_copy(&bm->pdata, &em->fdata, flag, CD_CALLOC, 0);
+ CustomData_from_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata,0);
+ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
+
+ totvert = BM_Count_Element(bm, BM_VERT);
+ evlist= MEM_mallocN(totvert*sizeof(EditVert *),"evlist");
+
+ /* make vertices */
+ for(i=0, v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts), i++)
+ eve = bmeshvert_to_editvert(bm, em, v, i, evlist);
+
+ /* make edges */
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges))
+ bmeshedge_to_editedge(bm, em, e, evlist);
+
+ /* make faces */
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces))
+ bmeshface_to_editface(bm, em, f, evlist, numCol, numTex);
+
+ MEM_freeN(evlist);
+
+ EM_fgon_flags(em);
+
+ EM_nvertices_selected(em);
+ EM_nedges_selected(em);
+ EM_nfaces_selected(em);
+
+ return em;
+}
+
+void bmesh2edit_exec(BMesh *bmesh, BMOperator *op)
+{
+ BMO_Set_Pnt(op, "emout", bmesh_to_editmesh_intern(bmesh));
+}
+
+#define FACE_NGON 1
+
+void bmesh_make_fgons_exec(BMesh *bmesh, BMOperator *op)
+{
+ BMOperator triop;
+ BMFace *face;
+ BMIter iter, liter;
+ BMEdge *edge;
+ BMLoop *l, *nl;
+ BMOpSlot *eout;
+ int i, trifan = BMO_Get_Int(op, "trifan");
+
+ if (!trifan) BMO_Init_Op(&triop, "triangulate");
+
+ /*instead of properly tesselate, just make a triangle fan, this
+ should make bmesh -> editmesh -> bmesh conversions always properly
+ work.*/
+ for (face = BMIter_New(&iter, bmesh, BM_FACES_OF_MESH, NULL); face; face=BMIter_Step(&iter)) {
+ if (face->len > 4) {
+ BMO_SetFlag(bmesh, face, FACE_NGON);
+ if (trifan) {
+ while (face->len > 4) {
+ face = BM_Split_Face(bmesh, face,
+ face->lbase->v,
+ ((BMLoop*)face->lbase->next->next)->v,
+ &nl, NULL);
+ BM_SetHFlag(nl->e, BM_FGON);
+ }
+ }
+ }
+ }
+
+ if (!trifan) {
+ BMO_Flag_To_Slot(bmesh, &triop, "faces", FACE_NGON, BM_FACE);
+ BMO_Exec_Op(bmesh, &triop);
+
+ eout = BMO_GetSlot(&triop, "edgeout");
+ for (i=0; i<eout->len; i++) {
+ edge = ((BMEdge**)eout->data.buf)[i];
+ edge->head.flag |= BM_FGON;
+ face = BMIter_New(&iter, bmesh, BM_FACES_OF_EDGE, edge);
+
+ for (; face; face=BMIter_Step(&iter)) {
+ face->head.flag |= BM_NONORMCALC;
+ }
+ }
+
+ BMO_Finish_Op(bmesh, &triop);
+ }
+}
+
+EditMesh *bmesh_to_editmesh(BMesh *bmesh)
+{
+ BMOperator conv, makefgon;
+ EditMesh *em;
+
+ /*first fgon-afy the mesh*/
+ BMO_Init_Op(&makefgon, "makefgon");
+ BMO_Set_Int(&makefgon, "trifan", 1);
+ BMO_Exec_Op(bmesh, &makefgon);
+ BMO_Finish_Op(bmesh, &makefgon);
+
+ BMO_Init_Op(&conv, "bmesh_to_editmesh");
+ BMO_Exec_Op(bmesh, &conv);
+ em = BMO_Get_Pnt(&conv, "emout");
+ BMO_Finish_Op(bmesh, &conv);
+
+ return em;
+}
+#endif \ No newline at end of file
diff --git a/source/blender/bmesh/intern/bmesh_walkers.c b/source/blender/bmesh/intern/bmesh_walkers.c
new file mode 100644
index 00000000000..5e824feb53a
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_walkers.c
@@ -0,0 +1,919 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "BKE_utildefines.h"
+#include "BKE_customdata.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BLI_mempool.h"
+#include "BLI_array.h"
+
+#include "bmesh_private.h"
+#include "bmesh_walkers.h"
+
+#include "bmesh.h"
+
+/*
+ - joeedh -
+ design notes:
+
+ original desing: walkers directly emulation recursive functions.
+ functions save their state onto a stack, and also push new states
+ to implement recursive or looping behaviour. generally only one
+ state push per call with a specific state is desired.
+
+ basic design pattern: the walker step function goes through it's
+ list of possible choices for recursion, and recurses (by pushing a new state)
+ using the first non-visited one. this choise is the flagged as visited using
+ the ghash. each step may push multiple new states onto the stack at once.
+
+ * walkers use tool flags, not header flags
+ * walkers now use ghash for storing visited elements,
+ rather then stealing flags. ghash can be rewritten
+ to be faster if necassary, in the far future :) .
+ * tools should ALWAYS have necassary error handling
+ for if walkers fail.
+*/
+
+typedef struct shellWalker{
+ struct shellWalker *prev;
+ BMVert *base;
+ BMEdge *curedge, *current;
+} shellWalker;
+
+typedef struct islandboundWalker {
+ struct islandboundWalker *prev;
+ BMLoop *base;
+ BMVert *lastv;
+ BMLoop *curloop;
+} islandboundWalker;
+
+typedef struct islandWalker {
+ struct islandWalker * prev;
+ BMFace *cur;
+} islandWalker;
+
+typedef struct loopWalker {
+ struct loopWalker * prev;
+ BMEdge *cur, *start;
+ BMVert *lastv, *startv;
+ int startrad, stage2;
+} loopWalker;
+
+typedef struct faceloopWalker {
+ struct faceloopWalker * prev;
+ BMLoop *l;
+ int nocalc;
+} faceloopWalker;
+
+typedef struct edgeringWalker {
+ struct edgeringWalker * prev;
+ BMLoop *l;
+} edgeringWalker;
+
+typedef struct uvedgeWalker {
+ struct uvedgeWalker *prev;
+ BMLoop *l;
+} uvedgeWalker;
+
+/* NOTE: this comment is out of date, update it - joeedh
+ * BMWalker - change this to use the filters functions.
+ *
+ * A generic structure for maintaing the state and callbacks nessecary for walking over
+ * the surface of a mesh. An example of usage:
+ *
+ * BMEdge *edge;
+ * BMWalker *walker = BMW_create(BM_SHELLWALKER, BM_SELECT);
+ * walker->begin(walker, vert);
+ * for(edge = BMW_walk(walker); edge; edge = bmeshWwalker_walk(walker)){
+ * bmesh_select_edge(edge);
+ * }
+ * BMW_free(walker);
+ *
+ * The above example creates a walker that walks over the surface a mesh by starting at
+ * a vertex and traveling across its edges to other vertices, and repeating the process
+ * over and over again until it has visited each vertex in the shell. An additional restriction
+ * is passed into the BMW_create function stating that we are only interested
+ * in walking over edges that have been flagged with the bitmask 'BM_SELECT'.
+ *
+ *
+*/
+
+/*Forward declerations*/
+static void *BMW_walk(struct BMWalker *walker);
+static void BMW_popstate(struct BMWalker *walker);
+static void BMW_pushstate(struct BMWalker *walker);
+
+static void shellWalker_begin(struct BMWalker *walker, void *data);
+static void *shellWalker_yield(struct BMWalker *walker);
+static void *shellWalker_step(struct BMWalker *walker);
+
+static void islandboundWalker_begin(BMWalker *walker, void *data);
+static void *islandboundWalker_yield(BMWalker *walker);
+static void *islandboundWalker_step(BMWalker *walker);
+
+static void islandWalker_begin(BMWalker *walker, void *data);
+static void *islandWalker_yield(BMWalker *walker);
+static void *islandWalker_step(BMWalker *walker);
+
+static void loopWalker_begin(BMWalker *walker, void *data);
+static void *loopWalker_yield(BMWalker *walker);
+static void *loopWalker_step(BMWalker *walker);
+
+static void faceloopWalker_begin(BMWalker *walker, void *data);
+static void *faceloopWalker_yield(BMWalker *walker);
+static void *faceloopWalker_step(BMWalker *walker);
+
+static void edgeringWalker_begin(BMWalker *walker, void *data);
+static void *edgeringWalker_yield(BMWalker *walker);
+static void *edgeringWalker_step(BMWalker *walker);
+
+static void uvedgeWalker_begin(BMWalker *walker, void *data);
+static void *uvedgeWalker_yield(BMWalker *walker);
+static void *uvedgeWalker_step(BMWalker *walker);
+
+/* Pointer hiding*/
+typedef struct bmesh_walkerGeneric{
+ struct bmesh_walkerGeneric *prev;
+} bmesh_walkerGeneric;
+
+
+void *BMW_Begin(BMWalker *walker, void *start) {
+ walker->begin(walker, start);
+
+ return walker->currentstate ? walker->step(walker) : NULL;
+}
+
+/*
+ * BMW_CREATE
+ *
+ * Allocates and returns a new mesh walker of
+ * a given type. The elements visited are filtered
+ * by the bitmask 'searchmask'.
+ *
+*/
+
+void BMW_Init(BMWalker *walker, BMesh *bm, int type, int searchmask, int flag)
+{
+ int size = 0;
+
+ memset(walker, 0, sizeof(BMWalker));
+
+ walker->flag = flag;
+ walker->bm = bm;
+ walker->restrictflag = searchmask;
+ walker->visithash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh walkers 1");
+
+ switch(type){
+ case BMW_SHELL:
+ walker->begin = shellWalker_begin;
+ walker->step = shellWalker_step;
+ walker->yield = shellWalker_yield;
+ size = sizeof(shellWalker);
+ break;
+ case BMW_ISLANDBOUND:
+ walker->begin = islandboundWalker_begin;
+ walker->step = islandboundWalker_step;
+ walker->yield = islandboundWalker_yield;
+ size = sizeof(islandboundWalker);
+ break;
+ case BMW_ISLAND:
+ walker->begin = islandWalker_begin;
+ walker->step = islandWalker_step;
+ walker->yield = islandWalker_yield;
+ size = sizeof(islandWalker);
+ break;
+ case BMW_LOOP:
+ walker->begin = loopWalker_begin;
+ walker->step = loopWalker_step;
+ walker->yield = loopWalker_yield;
+ size = sizeof(loopWalker);
+ break;
+ case BMW_FACELOOP:
+ walker->begin = faceloopWalker_begin;
+ walker->step = faceloopWalker_step;
+ walker->yield = faceloopWalker_yield;
+ size = sizeof(faceloopWalker);
+ break;
+ case BMW_EDGERING:
+ walker->begin = edgeringWalker_begin;
+ walker->step = edgeringWalker_step;
+ walker->yield = edgeringWalker_yield;
+ size = sizeof(edgeringWalker);
+ break;
+ case BMW_LOOPDATA_ISLAND:
+ walker->begin = uvedgeWalker_begin;
+ walker->step = uvedgeWalker_step;
+ walker->yield = uvedgeWalker_yield;
+ size = sizeof(uvedgeWalker);
+ break;
+ default:
+ break;
+ }
+ walker->stack = BLI_mempool_create(size, 100, 100, 1, 0);
+ walker->currentstate = NULL;
+}
+
+/*
+ * BMW_End
+ *
+ * Frees a walker's stack.
+ *
+*/
+
+void BMW_End(BMWalker *walker)
+{
+ BLI_mempool_destroy(walker->stack);
+ BLI_ghash_free(walker->visithash, NULL, NULL);
+}
+
+
+/*
+ * BMW_Step
+ *
+*/
+
+void *BMW_Step(BMWalker *walker)
+{
+ BMHeader *head;
+
+ head = BMW_walk(walker);
+
+ return head;
+}
+
+/*
+ * BMW_WALK
+ *
+ * Steps a mesh walker forward by one element
+ *
+ * TODO:
+ * -add searchmask filtering
+ *
+*/
+
+static void *BMW_walk(BMWalker *walker)
+{
+ void *current = NULL;
+
+ while(walker->currentstate){
+ current = walker->step(walker);
+ if(current) return current;
+ }
+ return NULL;
+}
+
+/*
+ * BMW_popstate
+ *
+ * Pops the current walker state off the stack
+ * and makes the previous state current
+ *
+*/
+
+static void BMW_popstate(BMWalker *walker)
+{
+ void *oldstate;
+ oldstate = walker->currentstate;
+ walker->currentstate
+ = ((bmesh_walkerGeneric*)walker->currentstate)->prev;
+ BLI_mempool_free(walker->stack, oldstate);
+}
+
+/*
+ * BMW_pushstate
+ *
+ * Pushes the current state down the stack and allocates
+ * a new one.
+ *
+*/
+
+static void BMW_pushstate(BMWalker *walker)
+{
+ bmesh_walkerGeneric *newstate;
+ newstate = BLI_mempool_alloc(walker->stack);
+ newstate->prev = walker->currentstate;
+ walker->currentstate = newstate;
+}
+
+void BMW_reset(BMWalker *walker) {
+ while (walker->currentstate) {
+ BMW_popstate(walker);
+ }
+}
+
+/* Shell Walker:
+ *
+ * Starts at a vertex on the mesh and walks over the 'shell' it belongs
+ * to via visiting connected edges.
+ *
+ * TODO:
+ *
+ * Add restriction flag/callback for wire edges.
+ *
+*/
+
+static void shellWalker_begin(BMWalker *walker, void *data){
+ BMIter eiter;
+ BMEdge *e;
+ BMVert *v = data;
+ shellWalker *shellWalk = NULL;
+
+ if (!v->e)
+ return;
+
+ if (walker->restrictflag) {
+ BM_ITER(e, &eiter, walker->bm, BM_EDGES_OF_VERT, v) {
+ if (BMO_TestFlag(walker->bm, e, walker->restrictflag))
+ break;
+ }
+ } else {
+ e = v->e;
+ }
+
+ if (!e)
+ return;
+
+ if (BLI_ghash_haskey(walker->visithash, e))
+ return;
+
+ BMW_pushstate(walker);
+
+ shellWalk = walker->currentstate;
+ shellWalk->base = v;
+ shellWalk->curedge = e;
+ BLI_ghash_insert(walker->visithash, e, NULL);
+}
+
+static void *shellWalker_yield(BMWalker *walker)
+{
+ shellWalker *shellWalk = walker->currentstate;
+ return shellWalk->curedge;
+}
+
+static void *shellWalker_step(BMWalker *walker)
+{
+ shellWalker *swalk = walker->currentstate;
+ BMEdge *e, *e2;
+ BMVert *v;
+ BMIter iter;
+ int i;
+
+ BMW_popstate(walker);
+
+ e = swalk->curedge;
+ for (i=0; i<2; i++) {
+ v = i ? e->v2 : e->v1;
+ BM_ITER(e2, &iter, walker->bm, BM_EDGES_OF_VERT, v) {
+ if (walker->restrictflag && !BMO_TestFlag(walker->bm, e2, walker->restrictflag))
+ continue;
+ if (BLI_ghash_haskey(walker->visithash, e2))
+ continue;
+
+ BMW_pushstate(walker);
+ BLI_ghash_insert(walker->visithash, e2, NULL);
+
+ swalk = walker->currentstate;
+ swalk->curedge = e2;
+ }
+ }
+
+ return e;
+}
+
+#if 0
+static void *shellWalker_step(BMWalker *walker)
+{
+ BMEdge *curedge, *next = NULL;
+ BMVert *ov = NULL;
+ int restrictpass = 1;
+ shellWalker shellWalk = *((shellWalker*)walker->currentstate);
+
+ if (!BLI_ghash_haskey(walker->visithash, shellWalk.base))
+ BLI_ghash_insert(walker->visithash, shellWalk.base, NULL);
+
+ BMW_popstate(walker);
+
+
+ /*find the next edge whose other vertex has not been visited*/
+ curedge = shellWalk.curedge;
+ do{
+ if (!BLI_ghash_haskey(walker->visithash, curedge)) {
+ if(!walker->restrictflag || (walker->restrictflag &&
+ BMO_TestFlag(walker->bm, curedge, walker->restrictflag)))
+ {
+ ov = BM_OtherEdgeVert(curedge, shellWalk.base);
+
+ /*push a new state onto the stack*/
+ BMW_pushstate(walker);
+ BLI_ghash_insert(walker->visithash, curedge, NULL);
+
+ /*populate the new state*/
+
+ ((shellWalker*)walker->currentstate)->base = ov;
+ ((shellWalker*)walker->currentstate)->curedge = curedge;
+ }
+ }
+ curedge = bmesh_disk_nextedge(curedge, shellWalk.base);
+ }while(curedge != shellWalk.curedge);
+
+ return shellWalk.curedge;
+}
+#endif
+
+/* Island Boundary Walker:
+ *
+ * Starts at a edge on the mesh and walks over the boundary of an
+ * island it belongs to.
+ *
+ * TODO:
+ *
+ * Add restriction flag/callback for wire edges.
+ *
+*/
+
+static void islandboundWalker_begin(BMWalker *walker, void *data){
+ BMLoop *l = data;
+ islandboundWalker *iwalk = NULL;
+
+ BMW_pushstate(walker);
+
+ iwalk = walker->currentstate;
+
+ iwalk->base = iwalk->curloop = l;
+ iwalk->lastv = l->v;
+
+ BLI_ghash_insert(walker->visithash, data, NULL);
+
+}
+
+static void *islandboundWalker_yield(BMWalker *walker)
+{
+ islandboundWalker *iwalk = walker->currentstate;
+
+ return iwalk->curloop;
+}
+
+static void *islandboundWalker_step(BMWalker *walker)
+{
+ islandboundWalker *iwalk = walker->currentstate, owalk;
+ BMVert *v;
+ BMEdge *e = iwalk->curloop->e;
+ BMFace *f;
+ BMLoop *l = iwalk->curloop;
+ int found=0;
+
+ owalk = *iwalk;
+
+ if (iwalk->lastv == e->v1) v = e->v2;
+ else v = e->v1;
+
+ if (BM_Nonmanifold_Vert(walker->bm, v)) {
+ BMW_reset(walker);
+ BMO_RaiseError(walker->bm, NULL,BMERR_WALKER_FAILED,
+ "Non-manifold vert"
+ " while searching region boundary");
+ return NULL;
+ }
+
+ /*pop off current state*/
+ BMW_popstate(walker);
+
+ f = l->f;
+
+ while (1) {
+ l = BM_OtherFaceLoop(e, f, v);
+ if (bmesh_radial_nextloop(l) != l) {
+ l = bmesh_radial_nextloop(l);
+ f = l->f;
+ e = l->e;
+ if(!BMO_TestFlag(walker->bm, f, walker->restrictflag)){
+ l = l->radial_next;
+ break;
+ }
+ } else {
+ f = l->f;
+ e = l->e;
+ break;
+ }
+ }
+
+ if (l == owalk.curloop) return NULL;
+ if (BLI_ghash_haskey(walker->visithash, l)) return owalk.curloop;
+
+ BLI_ghash_insert(walker->visithash, l, NULL);
+ BMW_pushstate(walker);
+ iwalk = walker->currentstate;
+ iwalk->base = owalk.base;
+
+ //if (!BMO_TestFlag(walker->bm, l->f, walker->restrictflag))
+ // iwalk->curloop = l->radial_next;
+ iwalk->curloop = l; //else iwalk->curloop = l;
+ iwalk->lastv = v;
+
+ return owalk.curloop;
+}
+
+
+/* Island Walker:
+ *
+ * Starts at a tool flagged-face and walks over the face region
+ *
+ * TODO:
+ *
+ * Add restriction flag/callback for wire edges.
+ *
+*/
+
+static void islandWalker_begin(BMWalker *walker, void *data){
+ islandWalker *iwalk = NULL;
+
+ BMW_pushstate(walker);
+
+ iwalk = walker->currentstate;
+ BLI_ghash_insert(walker->visithash, data, NULL);
+
+ iwalk->cur = data;
+}
+
+static void *islandWalker_yield(BMWalker *walker)
+{
+ islandWalker *iwalk = walker->currentstate;
+
+ return iwalk->cur;
+}
+
+static void *islandWalker_step(BMWalker *walker)
+{
+ islandWalker *iwalk = walker->currentstate, *owalk;
+ BMIter iter, liter;
+ BMFace *f, *curf = iwalk->cur;
+ BMLoop *l;
+ owalk = iwalk;
+
+ BMW_popstate(walker);
+
+ l = BMIter_New(&liter, walker->bm, BM_LOOPS_OF_FACE, iwalk->cur);
+ for (; l; l=BMIter_Step(&liter)) {
+ f = BMIter_New(&iter, walker->bm, BM_FACES_OF_EDGE, l->e);
+ for (; f; f=BMIter_Step(&iter)) {
+ if (!BMO_TestFlag(walker->bm, f, walker->restrictflag))
+ continue;
+ if (BLI_ghash_haskey(walker->visithash, f)) continue;
+
+ BMW_pushstate(walker);
+ iwalk = walker->currentstate;
+ iwalk->cur = f;
+ BLI_ghash_insert(walker->visithash, f, NULL);
+ break;
+
+ }
+ }
+
+ return curf;
+}
+
+
+/* Island Walker:
+ *
+ * Starts at a tool flagged-face and walks over the face region
+ *
+ * TODO:
+ *
+ * Add restriction flag/callback for wire edges.
+ *
+*/
+
+static void loopWalker_begin(BMWalker *walker, void *data){
+ loopWalker *lwalk = NULL, owalk;
+ BMEdge *e = data;
+ BMVert *v;
+ int found=1, val;
+
+ v = e->v1;
+
+ val = BM_Vert_EdgeCount(v);
+
+ BMW_pushstate(walker);
+
+ lwalk = walker->currentstate;
+ BLI_ghash_insert(walker->visithash, e, NULL);
+
+ lwalk->cur = lwalk->start = e;
+ lwalk->lastv = lwalk->startv = v;
+ lwalk->stage2 = 0;
+ lwalk->startrad = BM_Edge_FaceCount(e);
+
+ /*rewind*/
+ while (walker->currentstate) {
+ owalk = *((loopWalker*)walker->currentstate);
+ BMW_walk(walker);
+ }
+
+ BMW_pushstate(walker);
+ lwalk = walker->currentstate;
+ *lwalk = owalk;
+
+ if (lwalk->lastv == owalk.cur->v1) lwalk->lastv = owalk.cur->v2;
+ else lwalk->lastv = owalk.cur->v1;
+
+ lwalk->startv = lwalk->lastv;
+
+ BLI_ghash_free(walker->visithash, NULL, NULL);
+ walker->visithash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh walkers 2");
+ BLI_ghash_insert(walker->visithash, owalk.cur, NULL);
+}
+
+static void *loopWalker_yield(BMWalker *walker)
+{
+ loopWalker *lwalk = walker->currentstate;
+
+ return lwalk->cur;
+}
+
+static void *loopWalker_step(BMWalker *walker)
+{
+ loopWalker *lwalk = walker->currentstate, owalk;
+ BMEdge *e = lwalk->cur, *nexte = NULL;
+ BMLoop *l, *l2;
+ BMVert *v;
+ int val, rlen, found=0, i=0, stopi;
+
+ owalk = *lwalk;
+
+ if (e->v1 == lwalk->lastv) v = e->v2;
+ else v = e->v1;
+
+ val = BM_Vert_EdgeCount(v);
+
+ BMW_popstate(walker);
+
+ rlen = owalk.startrad;
+ l = e->l;
+ if (!l)
+ return owalk.cur;
+
+ if (val == 4 || val == 2 || rlen == 1) {
+ i = 0;
+ stopi = val / 2;
+ while (1) {
+ if (rlen != 1 && i == stopi) break;
+
+ l = BM_OtherFaceLoop(l->e, l->f, v);
+
+ if (!l)
+ break;
+
+ l2 = bmesh_radial_nextloop(l);
+
+ if (l2 == l) {
+ break;
+ }
+
+ l = l2;
+ i += 1;
+ }
+ }
+
+ if (!l)
+ return owalk.cur;
+
+ if (l != e->l && !BLI_ghash_haskey(walker->visithash, l->e)) {
+ if (!(rlen != 1 && i != stopi)) {
+ BMW_pushstate(walker);
+ lwalk = walker->currentstate;
+ *lwalk = owalk;
+ lwalk->cur = l->e;
+ lwalk->lastv = v;
+ BLI_ghash_insert(walker->visithash, l->e, NULL);
+ }
+ }
+
+ return owalk.cur;
+}
+
+static void faceloopWalker_begin(BMWalker *walker, void *data)
+{
+ faceloopWalker *lwalk, owalk;
+ BMEdge *e = data;
+
+ BMW_pushstate(walker);
+
+ if (!e->l) return;
+
+ lwalk = walker->currentstate;
+ lwalk->l = e->l;
+ lwalk->nocalc = 0;
+ BLI_ghash_insert(walker->visithash, lwalk->l->f, NULL);
+
+ /*rewind*/
+ while (walker->currentstate) {
+ owalk = *((faceloopWalker*)walker->currentstate);
+ BMW_walk(walker);
+ }
+
+ BMW_pushstate(walker);
+ lwalk = walker->currentstate;
+ *lwalk = owalk;
+ lwalk->nocalc = 0;
+
+ BLI_ghash_free(walker->visithash, NULL, NULL);
+ walker->visithash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh walkers 3");
+ BLI_ghash_insert(walker->visithash, lwalk->l->f, NULL);
+}
+
+static void *faceloopWalker_yield(BMWalker *walker)
+{
+ faceloopWalker *lwalk = walker->currentstate;
+
+ if (!lwalk) return NULL;
+
+ return lwalk->l->f;
+}
+
+static void *faceloopWalker_step(BMWalker *walker)
+{
+ faceloopWalker *lwalk = walker->currentstate;
+ BMFace *f = lwalk->l->f;
+ BMLoop *l = lwalk->l, *origl = lwalk->l;
+
+ BMW_popstate(walker);
+
+ l = l->radial_next;
+
+ if (lwalk->nocalc)
+ return f;
+
+ if (BLI_ghash_haskey(walker->visithash, l->f)) {
+ l = lwalk->l;
+ l = l->next->next;
+ if (l == l->radial_next) {
+ l = l->prev->prev;
+ }
+ l = l->radial_next;
+ }
+
+ if (!BLI_ghash_haskey(walker->visithash, l->f)) {
+ BMW_pushstate(walker);
+ lwalk = walker->currentstate;
+ lwalk->l = l;
+
+ if (l->f->len != 4) {
+ lwalk->nocalc = 1;
+ lwalk->l = origl;
+ } else
+ lwalk->nocalc = 0;
+
+ BLI_ghash_insert(walker->visithash, l->f, NULL);
+ }
+
+ return f;
+}
+
+static void edgeringWalker_begin(BMWalker *walker, void *data)
+{
+ edgeringWalker *lwalk, owalk;
+ BMEdge *e = data;
+
+ if (!e->l) return;
+
+ BMW_pushstate(walker);
+
+ lwalk = walker->currentstate;
+ lwalk->l = e->l;
+ BLI_ghash_insert(walker->visithash, lwalk->l->e, NULL);
+
+ /*rewind*/
+ while (walker->currentstate) {
+ owalk = *((edgeringWalker*)walker->currentstate);
+ BMW_walk(walker);
+ }
+
+ BMW_pushstate(walker);
+ lwalk = walker->currentstate;
+ *lwalk = owalk;
+
+ if (lwalk->l->f->len != 4)
+ lwalk->l = lwalk->l->radial_next;
+
+ BLI_ghash_free(walker->visithash, NULL, NULL);
+ walker->visithash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh walkers 4");
+ BLI_ghash_insert(walker->visithash, lwalk->l->e, NULL);
+}
+
+static void *edgeringWalker_yield(BMWalker *walker)
+{
+ edgeringWalker *lwalk = walker->currentstate;
+
+ if (!lwalk) return NULL;
+
+ return lwalk->l->e;
+}
+
+static void *edgeringWalker_step(BMWalker *walker)
+{
+ edgeringWalker *lwalk = walker->currentstate;
+ BMEdge *e = lwalk->l->e;
+ BMLoop *l = lwalk->l, *origl = lwalk->l;
+
+ BMW_popstate(walker);
+
+ l = l->radial_next;
+ l = l->next->next;
+
+ if (l->f->len != 4) {
+ l = lwalk->l->next->next;
+ }
+
+ if (l->f->len == 4 && !BLI_ghash_haskey(walker->visithash, l->e)) {
+ BMW_pushstate(walker);
+ lwalk = walker->currentstate;
+ lwalk->l = l;
+
+ BLI_ghash_insert(walker->visithash, l->e, NULL);
+ }
+
+ return e;
+}
+
+static void uvedgeWalker_begin(BMWalker *walker, void *data)
+{
+ uvedgeWalker *lwalk;
+ BMLoop *l = data;
+
+ if (BLI_ghash_haskey(walker->visithash, l))
+ return;
+
+ BMW_pushstate(walker);
+ lwalk = walker->currentstate;
+ lwalk->l = l;
+ BLI_ghash_insert(walker->visithash, l, NULL);
+}
+
+static void *uvedgeWalker_yield(BMWalker *walker)
+{
+ uvedgeWalker *lwalk = walker->currentstate;
+
+ if (!lwalk) return NULL;
+
+ return lwalk->l;
+}
+
+static void *uvedgeWalker_step(BMWalker *walker)
+{
+ uvedgeWalker *lwalk = walker->currentstate;
+ BMLoop *l, *l2, *l3, *nl, *cl;
+ BMIter liter;
+ void *d1, *d2;
+ int i, j, rlen, type;
+
+ l = lwalk->l;
+ nl = l->next;
+ type = walker->bm->ldata.layers[walker->flag].type;
+
+ BMW_popstate(walker);
+
+ if (walker->restrictflag && !BMO_TestFlag(walker->bm, l->e, walker->restrictflag))
+ return l;
+
+ /*go over loops around l->v and nl->v and see which ones share l and nl's
+ mloopuv's coordinates. in addition, push on l->next if necassary.*/
+ for (i=0; i<2; i++) {
+ cl = i ? nl : l;
+ BM_ITER(l2, &liter, walker->bm, BM_LOOPS_OF_VERT, cl->v) {
+ d1 = CustomData_bmesh_get_layer_n(&walker->bm->ldata,
+ cl->head.data, walker->flag);
+
+ rlen = BM_Edge_FaceCount(l2->e);
+ for (j=0; j<rlen; j++) {
+ if (BLI_ghash_haskey(walker->visithash, l2))
+ continue;
+ if (walker->restrictflag && !(BMO_TestFlag(walker->bm, l2->e, walker->restrictflag)))
+ {
+ if (l2->v != cl->v)
+ continue;
+ }
+
+ l3 = l2->v != cl->v ? (BMLoop*)l2->next : l2;
+ d2 = CustomData_bmesh_get_layer_n(&walker->bm->ldata,
+ l3->head.data, walker->flag);
+
+ if (!CustomData_data_equals(type, d1, d2))
+ continue;
+
+ BMW_pushstate(walker);
+ BLI_ghash_insert(walker->visithash, l2, NULL);
+ lwalk = walker->currentstate;
+
+ lwalk->l = l2;
+
+ l2 = l2->radial_next;
+ }
+ }
+ }
+
+ return l;
+}
+
diff --git a/source/blender/bmesh/intern/editmesh_to_bmesh.c b/source/blender/bmesh/intern/editmesh_to_bmesh.c
new file mode 100644
index 00000000000..77f421e7287
--- /dev/null
+++ b/source/blender/bmesh/intern/editmesh_to_bmesh.c
@@ -0,0 +1,476 @@
+#if 0
+
+#include "MEM_guardedalloc.h"
+#include "BKE_customdata.h"
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include <string.h>
+#include "BKE_utildefines.h"
+#include "BKE_mesh.h"
+#include "BKE_global.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
+
+#include "BLI_editVert.h"
+#include "mesh_intern.h"
+#include "ED_mesh.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
+#include "BLI_array.h"
+
+#include "bmesh.h"
+
+/*
+ * EDITMESH TO BMESH.C
+ *
+ * This file contains functions
+ * for converting an editmesh
+ * into a Bmesh
+ *
+*/
+
+/*
+ * EDITMESH CORNERS TO LOOPS
+ *
+ * Converts editmesh face corner data
+ * (UVs, Vert colors, ect) to N-Gon
+ * face-edge ('loop') data.
+ *
+*/
+
+static void editmesh_corners_to_loops(BMesh *bm, CustomData *facedata, void *face_block, BMFace *f,int numCol, int numTex){
+ int i, j;
+ BMLoop *l;
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ BMIter iter;
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_em_get_n(facedata, face_block, CD_MTFACE, i);
+ texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
+
+ texpoly->tpage = texface->tpage;
+ texpoly->flag = texface->flag;
+ texpoly->transp = texface->transp;
+ texpoly->mode = texface->mode;
+ texpoly->tile = texface->tile;
+ texpoly->unwrap = texface->unwrap;
+
+ for (j=0, l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f); l; j++, l=BMIter_Step(&iter)) {
+ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
+ mloopuv->uv[0] = texface->uv[j][0];
+ mloopuv->uv[1] = texface->uv[j][1];
+ }
+
+ }
+ for(i=0; i < numCol; i++){
+ mcol = CustomData_em_get_n(facedata, face_block, CD_MCOL, i);
+ for (j=0, l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f); l; j++, l=BMIter_Step(&iter)) {
+ mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
+ mloopcol->r = mcol[j].r;
+ mloopcol->g = mcol[j].g;
+ mloopcol->b = mcol[j].b;
+ mloopcol->a = mcol[j].a;
+ }
+ }
+}
+
+/*
+ * EDITVERT TO BMVert
+ *
+ * Converts an editvert to
+ * a BMVert.
+ *
+*/
+
+static BMVert *editvert_to_BMVert(BMesh *bm, BMOperator *op, EditMesh *em, EditVert *eve)
+{
+ BMVert *v = NULL;
+
+ v = BM_Make_Vert(bm, eve->co, NULL);
+ VECCOPY(v->no, eve->no);
+
+ /*transfer flags*/
+ v->head.flag = eve->h ? BM_HIDDEN : 0;
+ if(eve->f & SELECT) BM_Select_Vert(bm, v, 1);
+ v->bweight = eve->bweight;
+
+ BMO_Insert_MapPointer(bm, op, "map", eve, v);
+
+ /*Copy Custom Data*/
+ CustomData_bmesh_copy_data(&em->vdata, &bm->vdata, eve->data, &v->head.data);
+
+ return v;
+}
+
+/*
+ * EDITEDGE TO BMEdge
+ *
+ * Converts an editedge to
+ * a BMEdge
+ *
+*/
+
+static void editedge_to_BMEdge_internal(BMesh *bm, BMOperator *op, EditMesh *em, BMEdge *e, EditEdge *eed)
+{
+ e->crease = eed->crease;
+ e->bweight = eed->bweight;
+
+ BM_Select(bm, e, eed->f & SELECT);
+ e->head.flag |= eed->seam ? BM_SEAM : 0;
+ e->head.flag |= eed->h & 1 ? BM_HIDDEN : 0;
+ e->head.flag |= eed->h & EM_FGON ? BM_FGON : 0;
+ e->head.flag |= eed->sharp ? BM_SHARP : 0;
+
+ CustomData_bmesh_copy_data(&em->edata, &bm->edata, eed->data, &e->head.data);
+
+ BMO_Insert_MapPointer(bm, op, "map", eed, e);
+}
+
+static BMEdge *editedge_to_BMEdge(BMesh *bm, BMOperator *op, EditMesh *em, EditEdge *eed)
+{
+ BMVert *v1 = NULL, *v2 = NULL;
+ BMEdge *e = NULL;
+
+ v1 = eed->v1->tmp.p;
+ v2 = eed->v2->tmp.p;
+
+ e = BM_Make_Edge(bm, v1, v2,NULL, 0);
+
+ editedge_to_BMEdge_internal(bm, op, em, e, eed);
+
+ return e;
+}
+/*
+ * EDITFACE TO BMFace
+ *
+ * Converts an editface to a BMFace.
+ * Note that this also convert per-face
+ * corner data as well.
+ *
+*/
+
+static BMFace *editface_to_BMFace(BMesh *bm, BMOperator *op, EditMesh *em, EditFace *efa, int numCol, int numTex)
+{
+ BMVert *v1 = NULL, *v2 = NULL;
+ BMFace *f = NULL;
+ BMEdge *edar[4];
+ int len;
+
+ edar[0] = BM_Make_Edge(bm, efa->v1->tmp.p, efa->v2->tmp.p, NULL, 1);
+ edar[1] = BM_Make_Edge(bm, efa->v2->tmp.p, efa->v3->tmp.p, NULL, 1);
+ if(efa->v4){
+ edar[2] = BM_Make_Edge(bm, efa->v3->tmp.p, efa->v4->tmp.p, NULL, 1);
+ edar[3] = BM_Make_Edge(bm, efa->v4->tmp.p, efa->v1->tmp.p, NULL, 1);
+ }else{
+ edar[2] = BM_Make_Edge(bm, efa->v3->tmp.p, efa->v1->tmp.p, NULL, 1);
+ }
+
+ editedge_to_BMEdge_internal(bm, op, em, edar[0], efa->e1);
+ editedge_to_BMEdge_internal(bm, op, em, edar[1], efa->e2);
+ editedge_to_BMEdge_internal(bm, op, em, edar[2], efa->e3);
+ if(efa->v4)
+ editedge_to_BMEdge_internal(bm, op, em, edar[3], efa->e4);
+
+
+ if(efa->e1->fgoni) edar[0]->head.flag |= BM_FGON;
+ if(efa->e2->fgoni) edar[1]->head.flag |= BM_FGON;
+ if(efa->e3->fgoni) edar[2]->head.flag |= BM_FGON;
+ if(efa->v4 && efa->e4->fgoni) edar[3]->head.flag |= BM_FGON;
+
+ if(efa->v4) len = 4;
+ else len = 3;
+
+ /*find v1 and v2*/
+ v1 = efa->v1->tmp.p;
+ v2 = efa->v2->tmp.p;
+
+ f = BM_Make_Ngon(bm, v1, v2, edar, len, 0);
+
+ VECCOPY(f->no, efa->n);
+
+ BMO_Insert_MapPointer(bm, op, "map", efa, f);
+
+ f->head.flag = 0;
+ f->mat_nr = efa->mat_nr;
+ if(efa->f & SELECT) BM_Select_Face(bm, f, 1);
+ if (efa->flag & ME_SMOOTH) f->head.flag |= BM_SMOOTH;
+ if(efa->h) f->head.flag |= BM_HIDDEN;
+
+ if (efa == em->act_face) f->head.flag |= BM_ACTIVE;
+
+ CustomData_bmesh_copy_data(&em->fdata, &bm->pdata, efa->data, &f->head.data);
+ editmesh_corners_to_loops(bm, &em->fdata, efa->data, f,numCol,numTex);
+
+ return f;
+}
+
+/*
+ * BMESH FGONCONVERT
+ *
+ * This function and its associated structures
+ * /helpers (fgonsort, sortfgon, fuse_fgon) are
+ * used to convert f-gons to bmesh n-gons. This
+ * is accomplished by sorting a list of fgon faces
+ * such that faces that are part of the same fgon
+ * are next to each other. These faces are then
+ * converted as is into bmesh faces and
+ * fused togather.
+ *
+ * Note that currently, there is no support for
+ * holes in faces in the bmesh structure, so
+ * f-gons with holes will only partially convert.
+ *
+*/
+
+typedef struct fgonsort {
+ unsigned long x;
+ struct EditFace *efa;
+ struct BMFace *f;
+ int done;
+}fgonsort;
+
+static int sortfgon(const void *v1, const void *v2)
+{
+ const struct fgonsort *x1=v1, *x2=v2;
+
+ if( x1->x > x2->x ) return 1;
+ else if( x1->x < x2->x) return -1;
+ return 0;
+}
+
+static void fuse_fgon(BMesh *bm, BMFace *f)
+{
+ BMFace *sf;
+ BMLoop *l;
+ int done, act=0;
+
+ sf = f;
+ done = 0;
+ while(!done){
+ done = 1;
+ l = sf->loopbase;
+ do{
+ if(l->e->head.flag & BM_FGON) {
+ if (l->f->head.flag & BM_ACTIVE) act = BM_ACTIVE;
+ if (((BMLoop*)l->radial.next->data)->f->head.flag & BM_ACTIVE) act = BM_ACTIVE;
+
+ sf = BM_Join_TwoFaces(bm,l->f, ((BMLoop*)l->radial.next->data)->f, l->e);
+ if (!sf) {
+ //tesselation error
+ break;
+ }
+
+ sf->head.flag |= act;
+ if(sf){
+ done = 0;
+ break;
+ } else { /*we have to get out of here...*/
+ return;
+ }
+ }
+ l = ((BMLoop*)(l->next));
+ }while(l != sf->loopbase);
+ }
+}
+
+static BM_fgonconvert(BMesh *bm, BMOperator *op, EditMesh *em, int numCol, int numTex)
+{
+ EditFace *efa;
+ BMFace *f;
+ BMIter iter;
+ struct fgonsort *sortblock, *sb, *sb1;
+ int a, b, amount=0;
+
+ /*
+ for (efa=em->faces.first; efa; efa=efa->next) {
+ f = editface_to_BMFace(bm, em, efa, numCol, numTex);
+ }
+
+ for (f=bm->polys.first; f; f=f->next) {
+ fuse_fgon(bm, f);
+ }
+
+ return;*/
+
+ EM_fgon_flags(em);
+
+ /*zero out efa->tmp, we store fgon index here*/
+ for(efa = em->faces.first; efa; efa = efa->next){
+ efa->tmp.l = 0;
+ amount++;
+ }
+ /*go through and give each editface an fgon index*/
+ for(efa = em->faces.first; efa; efa = efa->next){
+ if(efa->e1->fgoni) efa->tmp.l = efa->e1->fgoni;
+ else if(efa->e2->fgoni) efa->tmp.l = efa->e2->fgoni;
+ else if(efa->e3->fgoni) efa->tmp.l = efa->e3->fgoni;
+ else if(efa->e4 && efa->e4->fgoni) efa->tmp.l = efa->e4->fgoni;
+ }
+
+ sb= sortblock= MEM_mallocN(sizeof(fgonsort)* amount,"fgon sort block");
+
+ for(efa = em->faces.first; efa; efa=efa->next){
+ sb->x = efa->tmp.l;
+ sb->efa = efa;
+ sb->done = 0;
+ sb++;
+ }
+
+ qsort(sortblock, amount, sizeof(fgonsort), sortfgon);
+
+ sb = sortblock;
+ for(a=0; a<amount; a++, sb++) {
+ if(sb->x && sb->done == 0){
+ /*first pass: add in faces for this fgon*/
+ for(b=a, sb1 = sb; b<amount && sb1->x == sb->x; b++, sb1++){
+ efa = sb1->efa;
+ sb1->f = editface_to_BMFace(bm, op, em, efa, numCol, numTex);
+ sb1->done = 1;
+ }
+ /*fuse fgon*/
+ fuse_fgon(bm, sb->f);
+ }
+ }
+ MEM_freeN(sortblock);
+}
+
+/*
+ * TAG WIRE EDGES
+ *
+ * Flags editedges 'f1' member
+ * if the edge has no faces.
+ *
+*/
+
+static void tag_wire_edges(EditMesh *em){
+ EditFace *efa;
+ EditEdge *eed;
+ for(eed = em->edges.first; eed; eed = eed->next) eed->f1 = 1;
+ for(efa = em->faces.first; efa; efa = efa->next){
+ efa->e1->f1 = 0;
+ efa->e2->f1 = 0;
+ efa->e3->f1 = 0;
+ if(efa->e4) efa->e4->f1 = 0;
+ }
+}
+
+/*
+ * EDITMESH TO BMESH
+ *
+ * Function to convert an editmesh to a bmesh
+ * Currently all custom data as well as
+ * f-gons should be converted correctly.
+ *
+*/
+
+BMesh *editmesh_to_bmesh_intern(EditMesh *em, BMesh *bm, BMOperator *op) {
+ BMVert *v;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+ BMEdge *e;
+ BMIter iter;
+ int allocsize[4] = {512,512,2048,512}, numTex, numCol;
+
+ /*make sure to update FGon flags*/
+ EM_fgon_flags(em);
+
+ /*copy custom data layout*/
+ CustomData_copy(&em->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&em->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&em->fdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+ /*copy face corner data*/
+ CustomData_to_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata, 0, 0);
+
+ CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
+
+ /*needed later*/
+ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
+
+ /*copy over selection mode*/
+ bm->selectmode = 0;
+ if(em->selectmode & SCE_SELECT_VERTEX) bm->selectmode |= SCE_SELECT_VERTEX;
+ if(em->selectmode & SCE_SELECT_EDGE) bm->selectmode |= SCE_SELECT_EDGE;
+ if(em->selectmode & SCE_SELECT_FACE) bm->selectmode |= SCE_SELECT_FACE;
+
+
+ /*begin editloop*/
+ //BM_Begin_Edit(bm);
+
+ /*tag wire edges*/
+ tag_wire_edges(em);
+
+ /*add verts*/
+ for(eve = em->verts.first; eve; eve = eve->next){
+ v = editvert_to_BMVert(bm, op, em, eve);
+ eve->tmp.p = v;
+ }
+ /*convert f-gons*/
+ BM_fgonconvert(bm, op, em, numCol, numTex);
+
+ /*clean up any dangling fgon flags*/
+ for (e=BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); e; e=BMIter_Step(&iter)){
+ e->head.flag &= ~BM_FGON;
+ }
+
+ /*do quads + triangles*/
+ for(efa = em->faces.first; efa; efa = efa->next){
+ if(!efa->tmp.l) editface_to_BMFace(bm, op, em, efa, numCol, numTex);
+ }
+
+ /*add wire edges*/
+ for(eed = em->edges.first; eed; eed = eed->next){
+ if(eed->f1) editedge_to_BMEdge(bm, op, em, eed);
+ }
+ //BM_end_edit(bm, BM_CALC_NORM);
+ return bm;
+}
+
+void edit2bmesh_exec(BMesh *bmesh, BMOperator *op)
+{
+ editmesh_to_bmesh_intern(BMO_Get_Pnt(op, "em"), bmesh, op);
+}
+
+BMesh *editmesh_to_bmesh(EditMesh *em)
+{
+ BMOperator conv;
+ BMesh *bm;
+ int allocsize[4] = {512,512,2048,512};
+
+ /*allocate a bmesh*/
+ bm = BM_Make_Mesh(allocsize);
+
+ BMO_Init_Op(&conv, "editmesh_to_bmesh");
+ BMO_Set_Pnt(&conv, "em", em);
+ BMO_Exec_Op(bm, &conv);
+ BMO_Finish_Op(bm, &conv);
+
+ return bm;
+}
+
+BMesh *init_editmesh_to_bmesh(EditMesh *em, BMOperator *op)
+{
+ BMesh *bm;
+ int allocsize[4] = {512,512,2048,512}, numTex, numCol;
+
+ /*allocate a bmesh*/
+ bm = BM_Make_Mesh(allocsize);
+
+ BMO_Init_Op(op, "editmesh_to_bmesh");
+ BMO_Set_Pnt(op, "em", em);
+
+ return bm;
+}
+#endif
diff --git a/source/blender/bmesh/intern/in-progress/BME_conversions.c b/source/blender/bmesh/intern/in-progress/BME_conversions.c
new file mode 100644
index 00000000000..d39bf689e76
--- /dev/null
+++ b/source/blender/bmesh/intern/in-progress/BME_conversions.c
@@ -0,0 +1,478 @@
+/**
+ * BME_conversions.c August 2008
+ *
+ * BM to Derived Mesh conversion functions.
+ *
+ * ***** 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.
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle, Levi Schooley.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+#include "BKE_customdata.h"
+
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_mesh.h"
+#include "bmesh.h"
+#include "BKE_global.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+#include "BLI_edgehash.h"
+#include "bmesh_private.h"
+
+
+
+/*
+ * BMESH DERIVED MESH CONVERSION FUNCTIONS
+ *
+ * The functions in this file provides
+ * methods for converting to and from
+ * a bmesh.
+ *
+*/
+
+
+/*
+ * DMCORNERS TO LOOPS
+ *
+ * Function to convert derived mesh per-face
+ * corner data (uvs, vertex colors), to n-gon
+ * per-loop data.
+ *
+*/
+
+static void DMcorners_to_loops(BMMesh *bm, CustomData *facedata, int index, BMFace *f, int numCol, int numTex){
+ int i, j;
+ BMLoop *l;
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+
+ for(i=0; i< numTex; i++){
+ texface = CustomData_get_layer_n(facedata, CD_MTFACE, i);
+ texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
+
+ texpoly->tpage = texface[index].tpage;
+ texpoly->flag = texface[index].flag;
+ texpoly->transp = texface[index].transp;
+ texpoly->mode = texface[index].mode;
+ texpoly->tile = texface[index].tile;
+ texpoly->unwrap = texface[index].unwrap;
+
+ j = 0;
+ l = f->loopbase;
+ do{
+ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
+ mloopuv->uv[0] = texface[index].uv[j][0];
+ mloopuv->uv[1] = texface[index].uv[j][1];
+ j++;
+ l = l->next;
+ }while(l!=f->loopbase);
+ }
+
+ for(i=0; i < numCol; i++){
+ mcol = CustomData_get_layer_n(facedata, CD_MCOL, i);
+ j = 0;
+ l = f->loopbase;
+ do{
+ mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
+ mloopcol->r = mcol[(index*4)+j].r;
+ mloopcol->g = mcol[(index*4)+j].g;
+ mloopcol->b = mcol[(index*4)+j].b;
+ mloopcol->a = mcol[(index*4)+j].a;
+ j++;
+ l = l->next;
+ }while(l!=f->loopbase);
+ }
+}
+
+/*
+ * LOOPS TO DMCORNERS
+ *
+ * Function to convert n-gon per-loop data
+ * (uvs, vertex colors, ect)to derived mesh
+ * face corner data.
+ *
+*/
+
+static void loops_to_DMcorners(BMMesh *bm, CustomData *facedata, int index, BMFace *f,int numCol, int numTex){
+ int i, j;
+ BMLoop *l;
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_get_layer_n(facedata, CD_MTFACE, i);
+ texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
+
+ texface[index].tpage = texpoly->tpage;
+ texface[index].flag = texpoly->flag;
+ texface[index].transp = texpoly->transp;
+ texface[index].mode = texpoly->mode;
+ texface[index].tile = texpoly->tile;
+ texface[index].unwrap = texpoly->unwrap;
+
+ j = 0;
+ l = f->loopbase;
+ do{
+ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
+ texface[index].uv[j][0] = mloopuv->uv[0];
+ texface[index].uv[j][1] = mloopuv->uv[1];
+ j++;
+ l = l->next;
+ }while(l!=f->loopbase);
+
+ }
+ for(i=0; i < numCol; i++){
+ mcol = CustomData_get_layer_n(facedata,CD_MCOL, i);
+ j = 0;
+ l = f->loopbase;
+ do{
+ mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
+ mcol[(index*4) + j].r = mloopcol->r;
+ mcol[(index*4) + j].g = mloopcol->g;
+ mcol[(index*4) + j].b = mloopcol->b;
+ mcol[(index*4) + j].a = mloopcol->a;
+ j++;
+ l = l->next;
+ }while(l!=f->loopbase);
+ }
+}
+
+/*
+ * MVERT TO BMESHVERT
+ *
+ * Converts a MVert to a BMVert
+ *
+*/
+static BMVert *mvert_to_bmeshvert(BMMesh *bm, BMVert **vert_array, int index, MVert *mv, CustomData *data)
+{
+ BMVert *v = NULL;
+
+ v = bmesh_make_vert(bm, mv->co, NULL);
+ vert_array[index] = v;
+ if(mv->flag & SELECT) bmesh_set_flag(v, BMESH_SELECT);
+ v->bweight = mv->bweight/255.0f;
+ CustomData_to_bmesh_block(data, &bm->vdata, index, &v->data);
+
+ return v;
+}
+
+/*
+ * MEDGE TO BMESHEDGE
+ *
+ * Converts a MEdge to a BMEdge
+ *
+*/
+
+static BMEdge *medge_to_bmeshedge(BMMesh *bm, BMVert **vert_array, int index, MEdge *me, CustomData *data, Edge_Hash *edge_hash)
+{
+ BMVert *v1, *v2;
+ BMEdge *e = NULL;
+
+ v1 = vert_array[me->v1];
+ v2 = vert_array[me->v2];
+ e = bmesh_make_edge(bm, v1, v2, NULL, 0);
+ e->crease = me->crease/255.0f;
+ e->bweight = me->bweight/255.0f;
+ if(me->flag & 1) bmesh_set_flag(e, BMESH_SELECT);
+ if(me->flag & ME_SEAM) bmesh_set_flag(e, BMESH_SEAM);
+ BLI_edgehash_insert(edge_hash,me->v1,me->v2,e);
+ CustomData_to_bmesh_block(data, &bm->edata, index, &e->data);
+
+ return e;
+}
+
+/*
+ * MFACE TO BMESHFACE
+ *
+ * Converts a MFace to a BMFace.
+ * Note that this will fail on eekadoodle
+ * faces.
+ *
+*/
+
+static BMFace *mface_to_bmeshface(BMMesh *bm, BMVert **vert_array, int index, MFace *mf, CustomData *data, Edge_Hash *edge_hash)
+{
+ BMVert *v1, *v2;
+ BMEdge *edar[4];
+ BMFace *f = NULL;
+ int len;
+
+ if(mf->v4) len = 4;
+ else len = 3;
+
+ edar[0] = BLI_edgehash_lookup(edge_hash,mf->v1,mf->v2);
+ edar[1] = BLI_edgehash_lookup(edge_hash,mf->v2,mf->v3);
+ if(len == 4){
+ edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v4);
+ edar[3] = BLI_edgehash_lookup(edge_hash,mf->v4,mf->v1);
+ }
+ else
+ edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v1);
+
+ /*find v1 and v2*/
+ v1 = vert_array[mf->v1];
+ v2 = vert_array[mf->v2];
+
+ f = bmesh_make_ngon(bm, v1, v2, edar, len, 0);
+ f->mat_nr = mf->mat_nr;
+ if(mf->flag & 1) bmesh_set_flag(f, BMESH_SELECT);
+ if(mf->flag & ME_HIDE) bmesh_set_flag(f, BMESH_HIDDEN);
+ CustomData_to_bmesh_block(data, &bm->pdata, index, &f->data);
+
+ return f;
+}
+
+/*
+ * DERIVEDMESH TO BMESH
+ *
+ * Converts a derived mesh to a bmesh.
+ *
+*/
+
+BMMesh *derivedmesh_to_bmesh(DerivedMesh *dm)
+{
+
+ BMMesh *bm;
+ BMVert **vert_array;
+ BMFace *f=NULL;
+
+ MVert *mvert, *mv;
+ MEdge *medge, *me;
+ MFace *mface, *mf;
+
+ int totface,totedge,totvert,i,len, numTex, numCol;
+ int allocsize[4] = {512,512,2048,512};
+
+ EdgeHash *edge_hash = BLI_edgehash_new();
+
+ /*allocate a new bmesh*/
+ bm = bmesh_make_mesh(allocsize);
+
+ /*copy custom data layout*/
+ CustomData_copy(&dm->vertData, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&dm->edgeData, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&dm->faceData, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+ /*copy face corner data*/
+ CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata);
+ /*initialize memory pools*/
+ CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
+
+ /*needed later*/
+ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
+
+ totvert = dm->getNumVerts(dm);
+ totedge = dm->getNumEdges(dm);
+ totface = dm->getNumFaces(dm);
+ mvert = dm->getVertArray(dm);
+ medge = dm->getEdgeArray(dm);
+ mface = dm->getFaceArray(dm);
+
+ vert_array = MEM_mallocN(sizeof(BMVert *)* totvert,"derivedmesh to bmesh vertex pointer array");
+
+ bmesh_begin_edit(bm);
+ /*add verts*/
+ for(i=0, mv = mvert; i < totvert; i++, mv++)
+ mvert_to_bmeshvert(bm, vert_array, i, mv, &dm->vertData);
+
+ /*add edges*/
+ for(i=0, me = medge; i < totedge; i++, me++)
+ medge_to_bmeshedge(bm, vert_array, i, me, &dm->edgeData, edge_hash);
+
+ /*add faces.*/
+ for(i=0, mf = mface; i < totface; i++, mf++){
+ f = mface_to_bmeshface(bm, vert_array, mf, &dm->faceData, edge_hash);
+ if(f) DMcorners_to_loops(bm, &dm->faceData, i, f, numCol, numTex);
+ }
+
+ bmesh_end__edit(bm);
+ BLI_edgehash_free(edge_hash, NULL);
+ MEM_freeN(vert_array);
+ return bm;
+}
+
+static void bmeshvert_to_mvert(BMMesh *bm, BMVert *v, MVert *mv, int index, CustomData *data)
+{
+ VECCOPY(mv->co,v->co);
+ if(bmesh_test_flag(v, BMESH_SELECT)) mv->flag |= 1;
+ if(bmesh_test_flag(v, BMESH_HIDDEN)) mv->flag |= ME_HIDE;
+ mv->bweight = (char)(255.0*v1->bweight);
+ CustomData_from_bmesh_block(&bm->vdata, data, &v1->data, index);
+}
+
+static int bmeshedge_to_medge(BMMesh *bm, BMEdge *e, MEdge *me, int index, CustomData *data)
+{
+ if(e->head.eflag2){
+ if(e->v1->head.eflag1 < e->v2->head.eflag1){
+ me->v1 = e->v1->head.eflag1;
+ me->v2 = e->v2->head.eflag1;
+ }
+ else{
+ me->v1 = e->v2->head.eflag1;
+ me->v2 = e->v1->eflag1;
+ }
+
+ me->crease = (char)(255.0*e->crease);
+ me->bweight = (char)(255.0*e->bweight);
+ if(bmesh_test_flag(e, BMESH_SELECT)) me->flag |= 1;
+ if(bmesh_test_flag(e, BMESH_HIDDEN)) me->flag |= ME_HIDE;
+ CustomData_from_bmesh_block(&bm->edata, data, &e->data, index);
+ return 1;
+ }
+ return 0;
+}
+
+static int bmeshface_to_mface(BMMesh *bm, BMFace *f, MFace *mf, int index, CustomData *data)
+{
+ if(f->len==3 || f->len==4){
+ mf->v1 = f->loopbase->v->head.eflag1;
+ mf->v2 = f->loopbase->next->v->head.eflag1;
+ mf->v3 = f->loopbase->next->next->v->head.eflag1;
+ if(len == 4){
+ mf->v4 = f->loopbase->prev->v->head.eflag1;
+ }
+ /* test and rotate indexes if necessary so that verts 3 and 4 aren't index 0 */
+ if(mf->v3 == 0 || (f->len == 4 && mf->v4 == 0)){
+ test_index_face(mf, NULL, index, f->len);
+ }
+ mf->mat_nr = (unsigned char)f->mat_nr;
+ if(bmesh_test_flag(f, BMESH_SELECT)) mf->flag |= 1;
+ if(bmesh_test_flag(f, BMESH_HIDDEN)) mf->flag |= ME_HIDE;
+ CustomData_from_bmesh_block(&bm->pdata, data, &f->data, index);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * BMESH TO DERIVEDMESH
+ *
+ * Converts a bmesh to a derived mesh.
+ *
+*/
+
+DerivedMesh *bmesh_to_derivedmesh(BMMesh *bm, DerivedMesh *dm)
+{
+ MFace *mface = NULL, *mf = NULL;
+ MEdge *medge = NULL, *me = NULL;
+ MVert *mvert = NULL, *mv = NULL;
+ DerivedMesh *result = NULL;
+
+ BMVert *v=NULL;
+ BMEdge *e=NULL, *oe=NULL;
+ BMFace *f=NULL;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ int totface = 0,totedge = 0,totvert = 0,i = 0, numTex, numCol;
+
+ EdgeHash *edge_hash = BLI_edgehash_new();
+
+ /*get element counts*/
+ totvert = bmesh_count_element(bm, BMESH_VERT);
+
+ /*store element indices. Note that the abuse of eflag here should NOT be duplicated!*/
+ for(i=0, v = bmeshIterator_init(verts, BM_VERTS, bm, 0); v; v = bmeshIterator_step(verts), i++)
+ v->head.eflag1 = i;
+
+ /*we cannot have double edges in a derived mesh!*/
+ for(e = bmeshIterator_init(edges, BM_EDGES, bm, 0); e; e = bmeshIterator_step(edges)){
+ oe = BLI_edgehash_lookup(edge_hash,e->v1->head.eflag1, e->v2->head.eflag1);
+ if(!oe){
+ totedge++;
+ BLI_edgehash_insert(edge_hash,e->v1->head.eflag1,e->v2->head.eflag1,e);
+ e->head.eflag2 = 1;
+ }
+ else{
+ e->head.eflag2 = 0;
+ }
+ }
+
+ /*count quads and tris*/
+ for(f = bmeshIterator_init(faces, BM_FACES, bm, 0); f; f = bmeshIterator_step(faces)){
+ if(f->len == 3 || f->len == 4) totface++;
+ }
+
+ /*Allocate derivedmesh and copy custom data*/
+ result = CDDM_from_template(dm,totvert,totedge,totface);
+ CustomData_merge(&bm->vdata, &result->vertData, CD_MASK_BMESH, CD_CALLOC, totvert);
+ CustomData_merge(&bm->edata, &result->edgeData, CD_MASK_BMESH, CD_CALLOC, totedge);
+ CustomData_merge(&bm->pdata, &result->faceData, CD_MASK_BMESH, CD_CALLOC, totface);
+ CustomData_from_bmeshpoly(&result->faceData, &bm->pdata, &bm->ldata,totface);
+ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
+
+ /*Make Verts*/
+ mvert = CDDM_get_verts(result);
+ for(i = 0, v = bmeshIterator_init(verts, BM_VERTS, bm, 0); v; v = bmeshIterator_step(verts), i++, mv++){
+ bmeshvert_to_mvert(bm,v,mv,i,&result->vertData);
+ }
+
+ /*Make Edges*/
+ medge = CDDM_get_edges(result);
+ i=0;
+ for(e = bmeshIterator_init(edges, BM_EDGES, bm, 0); e; e = bmeshIterator_step(edges)){
+ me = &medge[i];
+ if(bmeshedge_to_medge(bm, e, me, i, &result->edgeData){
+ me++;
+ i++;
+ }
+ }
+ /*Make Faces*/
+ if(totface){
+ mface = CDDM_get_faces(result);
+ i=0;
+ for(f = bmeshIterator_init(faces, BM_FACES, bm, 0); f; f = bmeshIterator_step(faces)){
+ mf = &mface[i];
+ if(bmeshface_to_mface(bm, f, mf, i, &result->faceData)){
+ loops_to_DMcorners(bm, &result->faceData, i, f, numCol, numTex);
+ i++;
+ }
+ }
+ }
+ BLI_edgehash_free(edge_hash, NULL);
+ return result;
+}
diff --git a/source/blender/bmesh/operators/bmesh_dupeops.c b/source/blender/bmesh/operators/bmesh_dupeops.c
new file mode 100644
index 00000000000..86ab8ed7cf4
--- /dev/null
+++ b/source/blender/bmesh/operators/bmesh_dupeops.c
@@ -0,0 +1,575 @@
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+#include "BLI_blenlib.h"
+#include "BLI_array.h"
+#include "BLI_math.h"
+
+#include "bmesh.h"
+#include "bmesh_operators_private.h"
+
+/*local flag defines*/
+#define DUPE_INPUT 1 /*input from operator*/
+#define DUPE_NEW 2
+#define DUPE_DONE 4
+#define DUPE_MAPPED 8
+
+/*
+ * COPY VERTEX
+ *
+ * Copy an existing vertex from one bmesh to another.
+ *
+*/
+static BMVert *copy_vertex(BMesh *source_mesh, BMVert *source_vertex, BMesh *target_mesh, GHash *vhash)
+{
+ BMVert *target_vertex = NULL;
+
+ /*Create a new vertex*/
+ target_vertex = BM_Make_Vert(target_mesh, source_vertex->co, NULL);
+
+ /*Insert new vertex into the vert hash*/
+ BLI_ghash_insert(vhash, source_vertex, target_vertex);
+
+ /*Copy attributes*/
+ BM_Copy_Attributes(source_mesh, target_mesh, source_vertex, target_vertex);
+
+ /*Set internal op flags*/
+ BMO_SetFlag(target_mesh, (BMHeader*)target_vertex, DUPE_NEW);
+
+ return target_vertex;
+}
+
+/*
+ * COPY EDGE
+ *
+ * Copy an existing edge from one bmesh to another.
+ *
+*/
+static BMEdge *copy_edge(BMOperator *op, BMesh *source_mesh,
+ BMEdge *source_edge, BMesh *target_mesh,
+ GHash *vhash, GHash *ehash)
+{
+ BMEdge *target_edge = NULL;
+ BMVert *target_vert1, *target_vert2;
+ BMFace *face;
+ BMIter fiter;
+ int rlen;
+
+ /*see if any of the neighboring faces are
+ not being duplicated. in that case,
+ add it to the new/old map.*/
+ rlen = 0;
+ for (face=BMIter_New(&fiter,source_mesh, BM_FACES_OF_EDGE,source_edge);
+ face; face=BMIter_Step(&fiter)) {
+ if (BMO_TestFlag(source_mesh, face, DUPE_INPUT)) {
+ rlen++;
+ }
+ }
+
+ /*Lookup v1 and v2*/
+ target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1);
+ target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2);
+
+ /*Create a new edge*/
+ target_edge = BM_Make_Edge(target_mesh, target_vert1, target_vert2, NULL, 0);
+
+ /*add to new/old edge map if necassary*/
+ if (rlen < 2) {
+ /*not sure what non-manifold cases of greater then three
+ radial should do.*/
+ BMO_Insert_MapPointer(source_mesh,op, "boundarymap",
+ source_edge, target_edge);
+ }
+
+ /*Insert new edge into the edge hash*/
+ BLI_ghash_insert(ehash, source_edge, target_edge);
+
+ /*Copy attributes*/
+ BM_Copy_Attributes(source_mesh, target_mesh, source_edge, target_edge);
+
+ /*Set internal op flags*/
+ BMO_SetFlag(target_mesh, (BMHeader*)target_edge, DUPE_NEW);
+
+ return target_edge;
+}
+
+/*
+ * COPY FACE
+ *
+ * Copy an existing face from one bmesh to another.
+ *
+*/
+static BMFace *copy_face(BMOperator *op, BMesh *source_mesh,
+ BMFace *source_face, BMesh *target_mesh,
+ BMEdge **edar, GHash *vhash, GHash *ehash)
+{
+ BMVert *target_vert1, *target_vert2;
+ BMLoop *source_loop, *target_loop;
+ BMFace *target_face = NULL;
+ BMIter iter, iter2;
+ int i;
+
+ /*lookup the first and second verts*/
+ target_vert1 = BLI_ghash_lookup(vhash, BMIter_New(&iter, source_mesh, BM_VERTS_OF_FACE, source_face));
+ target_vert2 = BLI_ghash_lookup(vhash, BMIter_Step(&iter));
+
+ /*lookup edges*/
+ for (i=0,source_loop=BMIter_New(&iter, source_mesh, BM_LOOPS_OF_FACE, source_face);
+ source_loop; source_loop=BMIter_Step(&iter), i++) {
+ edar[i] = BLI_ghash_lookup(ehash, source_loop->e);
+ }
+
+ /*create new face*/
+ target_face = BM_Make_Ngon(target_mesh, target_vert1, target_vert2, edar, source_face->len, 0);
+ BMO_Insert_MapPointer(source_mesh, op,
+ "facemap", source_face, target_face);
+ BMO_Insert_MapPointer(source_mesh, op,
+ "facemap", target_face, source_face);
+
+ BM_Copy_Attributes(source_mesh, target_mesh, source_face, target_face);
+
+ /*mark the face for output*/
+ BMO_SetFlag(target_mesh, (BMHeader*)target_face, DUPE_NEW);
+
+ /*copy per-loop custom data*/
+ for (i=0,source_loop=BMIter_New(&iter, source_mesh, BM_LOOPS_OF_FACE, source_face),
+ target_loop=BMIter_New(&iter2, target_mesh, BM_LOOPS_OF_FACE, target_face);
+ source_loop && target_loop; source_loop=BMIter_Step(&iter), target_loop=BMIter_Step(&iter2),
+ i++) {
+ BM_Copy_Attributes(source_mesh, target_mesh, source_loop, target_loop);
+ }
+
+
+ return target_face;
+}
+ /*
+ * COPY MESH
+ *
+ * Internal Copy function.
+*/
+
+static void copy_mesh(BMOperator *op, BMesh *source, BMesh *target)
+{
+
+ BMVert *v = NULL, *v2;
+ BMEdge *e = NULL, **edar = NULL;
+ BMFace *f = NULL;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ GHash *vhash;
+ GHash *ehash;
+
+ int maxlength = 0;
+
+ /*initialize pointer hashes*/
+ vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh dupeops v");
+ ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh dupeops e");
+
+ /*initialize edge pointer array*/
+ for(f = BMIter_New(&faces, source, BM_FACES_OF_MESH, source); f; f = BMIter_Step(&faces)){
+ if(f->len > maxlength) maxlength = f->len;
+ }
+ edar = MEM_callocN(sizeof(BMEdge*) * maxlength, "BM copy mesh edge pointer array");
+
+ for(v = BMIter_New(&verts, source, BM_VERTS_OF_MESH, source); v; v = BMIter_Step(&verts)){
+ if(BMO_TestFlag(source, (BMHeader*)v, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader*)v, DUPE_DONE))){
+ BMIter iter;
+ int iso = 1;
+
+ v2 = copy_vertex(source, v, target, vhash);
+
+ BM_ITER(f, &iter, source, BM_FACES_OF_VERT, v) {
+ if (BMO_TestFlag(source, f, DUPE_INPUT)) {
+ iso = 0;
+ break;
+ }
+ }
+
+ if (iso) {
+ BM_ITER(e, &iter, source, BM_EDGES_OF_VERT, v) {
+ if (BMO_TestFlag(source, e, DUPE_INPUT)) {
+ iso = 0;
+ break;
+ }
+ }
+ }
+
+ if (iso)
+ BMO_Insert_MapPointer(source, op, "isovertmap", v, v2);
+
+ BMO_SetFlag(source, (BMHeader*)v, DUPE_DONE);
+ }
+ }
+
+ /*now we dupe all the edges*/
+ for(e = BMIter_New(&edges, source, BM_EDGES_OF_MESH, source); e; e = BMIter_Step(&edges)){
+ if(BMO_TestFlag(source, (BMHeader*)e, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader*)e, DUPE_DONE))){
+ /*make sure that verts are copied*/
+ if(!BMO_TestFlag(source, (BMHeader*)e->v1, DUPE_DONE)) {
+ copy_vertex(source, e->v1, target, vhash);
+ BMO_SetFlag(source, (BMHeader*)e->v1, DUPE_DONE);
+ }
+ if(!BMO_TestFlag(source, (BMHeader*)e->v2, DUPE_DONE)) {
+ copy_vertex(source, e->v2, target, vhash);
+ BMO_SetFlag(source, (BMHeader*)e->v2, DUPE_DONE);
+ }
+ /*now copy the actual edge*/
+ copy_edge(op, source, e, target, vhash, ehash);
+ BMO_SetFlag(source, (BMHeader*)e, DUPE_DONE);
+ }
+ }
+
+ /*first we dupe all flagged faces and their elements from source*/
+ for(f = BMIter_New(&faces, source, BM_FACES_OF_MESH, source); f; f= BMIter_Step(&faces)){
+ if(BMO_TestFlag(source, (BMHeader*)f, DUPE_INPUT)){
+ /*vertex pass*/
+ for(v = BMIter_New(&verts, source, BM_VERTS_OF_FACE, f); v; v = BMIter_Step(&verts)){
+ if(!BMO_TestFlag(source, (BMHeader*)v, DUPE_DONE)){
+ copy_vertex(source,v, target, vhash);
+ BMO_SetFlag(source, (BMHeader*)v, DUPE_DONE);
+ }
+ }
+
+ /*edge pass*/
+ for(e = BMIter_New(&edges, source, BM_EDGES_OF_FACE, f); e; e = BMIter_Step(&edges)){
+ if(!BMO_TestFlag(source, (BMHeader*)e, DUPE_DONE)){
+ copy_edge(op, source, e, target, vhash, ehash);
+ BMO_SetFlag(source, (BMHeader*)e, DUPE_DONE);
+ }
+ }
+ copy_face(op, source, f, target, edar, vhash, ehash);
+ BMO_SetFlag(source, (BMHeader*)f, DUPE_DONE);
+ }
+ }
+
+ /*free pointer hashes*/
+ BLI_ghash_free(vhash, NULL, NULL);
+ BLI_ghash_free(ehash, NULL, NULL);
+
+ /*free edge pointer array*/
+ if(edar)
+ MEM_freeN(edar);
+}
+
+/*
+BMesh *bmesh_make_mesh_from_mesh(BMesh *bm, int allocsize[4])
+{
+ BMesh *target = NULL;
+ target = bmesh_make_mesh(allocsize);
+
+
+ CustomData_copy(&bm->vdata, &target->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->edata, &target->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->ldata, &target->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->pdata, &target->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+
+ CustomData_bmesh_init_pool(&target->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&target->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&target->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&target->pdata, allocsize[3]);
+
+ bmesh_begin_edit(bm);
+ bmesh_begin_edit(target);
+
+ bmesh_copy_mesh(bm, target, 0);
+
+ bmesh_end_edit(bm);
+ bmesh_end_edit(target);
+
+ return target;
+
+}
+*/
+
+/*
+ * Duplicate Operator
+ *
+ * Duplicates verts, edges and faces of a mesh.
+ *
+ * INPUT SLOTS:
+ *
+ * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be duplicated
+ * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be duplicated
+ * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be duplicated
+ *
+ * OUTPUT SLOTS:
+ *
+ * BMOP_DUPE_VORIGINAL: Buffer containing pointers to the original mesh vertices
+ * BMOP_DUPE_EORIGINAL: Buffer containing pointers to the original mesh edges
+ * BMOP_DUPE_FORIGINAL: Buffer containing pointers to the original mesh faces
+ * BMOP_DUPE_VNEW: Buffer containing pointers to the new mesh vertices
+ * BMOP_DUPE_ENEW: Buffer containing pointers to the new mesh edges
+ * BMOP_DUPE_FNEW: Buffer containing pointers to the new mesh faces
+ *
+*/
+
+void dupeop_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator *dupeop = op;
+ BMesh *bm2 = BMO_Get_Pnt(op, "dest");
+
+ if (!bm2)
+ bm2 = bm;
+
+ /*flag input*/
+ BMO_Flag_Buffer(bm, dupeop, "geom", DUPE_INPUT, BM_ALL);
+
+ /*use the internal copy function*/
+ copy_mesh(dupeop, bm, bm2);
+
+ /*Output*/
+ /*First copy the input buffers to output buffers - original data*/
+ BMO_CopySlot(dupeop, dupeop, "geom", "origout");
+
+ /*Now alloc the new output buffers*/
+ BMO_Flag_To_Slot(bm, dupeop, "newout", DUPE_NEW, BM_ALL);
+}
+
+/*executes the duplicate operation, feeding elements of
+ type flag etypeflag and header flag flag to it. note,
+ to get more useful information (such as the mapping from
+ original to new elements) you should run the dupe op manually.*/
+void BMOP_DupeFromFlag(BMesh *bm, int etypeflag, int flag)
+{
+ BMOperator dupeop;
+
+ BMO_Init_Op(&dupeop, "dupe");
+ BMO_HeaderFlag_To_Slot(bm, &dupeop, "geom", flag, etypeflag);
+
+ BMO_Exec_Op(bm, &dupeop);
+ BMO_Finish_Op(bm, &dupeop);
+}
+
+/*
+ * Split Operator
+ *
+ * Duplicates verts, edges and faces of a mesh but also deletes the originals.
+ *
+ * INPUT SLOTS:
+ *
+ * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be split
+ * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be split
+ * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be split
+ *
+ * OUTPUT SLOTS:
+ *
+ * BMOP_DUPE_VOUTPUT: Buffer containing pointers to the split mesh vertices
+ * BMOP_DUPE_EOUTPUT: Buffer containing pointers to the split mesh edges
+ * BMOP_DUPE_FOUTPUT: Buffer containing pointers to the split mesh faces
+ *
+*/
+
+#define SPLIT_INPUT 1
+void splitop_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator *splitop = op;
+ BMOperator dupeop;
+ BMOperator delop;
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+ BMIter iter, iter2;
+ int found;
+
+ /*initialize our sub-operators*/
+ BMO_Init_Op(&dupeop, "dupe");
+ BMO_Init_Op(&delop, "del");
+
+ BMO_CopySlot(splitop, &dupeop, "geom", "geom");
+ BMO_Exec_Op(bm, &dupeop);
+
+ BMO_Flag_Buffer(bm, splitop, "geom", SPLIT_INPUT, BM_ALL);
+
+ /*make sure to remove edges and verts we don't need.*/
+ for (e= BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);e;e=BMIter_Step(&iter)) {
+ found = 0;
+ f = BMIter_New(&iter2, bm, BM_FACES_OF_EDGE, e);
+ for (; f; f=BMIter_Step(&iter2)) {
+ if (!BMO_TestFlag(bm, f, SPLIT_INPUT)) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) BMO_SetFlag(bm, e, SPLIT_INPUT);
+ }
+
+ for (v= BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);v;v=BMIter_Step(&iter)) {
+ found = 0;
+ e = BMIter_New(&iter2, bm, BM_EDGES_OF_VERT, v);
+ for (; e; e=BMIter_Step(&iter2)) {
+ if (!BMO_TestFlag(bm, e, SPLIT_INPUT)) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) BMO_SetFlag(bm, v, SPLIT_INPUT);
+
+ }
+
+ /*connect outputs of dupe to delete, exluding keep geometry*/
+ BMO_Set_Int(&delop, "context", DEL_FACES);
+ BMO_Flag_To_Slot(bm, &delop, "geom", SPLIT_INPUT, BM_ALL);
+
+ BMO_Exec_Op(bm, &delop);
+
+ /*now we make our outputs by copying the dupe outputs*/
+ BMO_CopySlot(&dupeop, splitop, "newout", "geom");
+ BMO_CopySlot(&dupeop, splitop, "boundarymap",
+ "boundarymap");
+ BMO_CopySlot(&dupeop, splitop, "isovertmap",
+ "isovertmap");
+
+ /*cleanup*/
+ BMO_Finish_Op(bm, &delop);
+ BMO_Finish_Op(bm, &dupeop);
+}
+
+#define DEL_INPUT 1
+#define DEL_WIREVERT 2
+
+static void delete_verts(BMesh *bm);
+static void delete_context(BMesh *bm, int type);
+
+void delop_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator *delop = op;
+
+ /*Mark Buffers*/
+ BMO_Flag_Buffer(bm, delop, "geom", DEL_INPUT, BM_ALL);
+
+ delete_context(bm, BMO_Get_Int(op, "context"));
+}
+
+static void delete_verts(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMLoop *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){
+ if(BMO_TestFlag(bm, (BMHeader*)v, DEL_INPUT)) {
+ /*Visit edges*/
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_VERT, v); e; e = BMIter_Step(&edges))
+ BMO_SetFlag(bm, (BMHeader*)e, DEL_INPUT);
+ /*Visit faces*/
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_VERT, v); f; f = BMIter_Step(&faces))
+ BMO_SetFlag(bm, (BMHeader*)f, DEL_INPUT);
+ }
+ }
+
+ BM_remove_tagged_faces(bm, DEL_INPUT);
+ BM_remove_tagged_edges(bm, DEL_INPUT);
+ BM_remove_tagged_verts(bm, DEL_INPUT);
+}
+
+static void delete_edges(BMesh *bm){
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter edges;
+ BMIter faces;
+
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){
+ if(BMO_TestFlag(bm, (BMHeader*)e, DEL_INPUT)) {
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_EDGE, e); f; f = BMIter_Step(&faces)){
+ BMO_SetFlag(bm, (BMHeader*)f, DEL_INPUT);
+ }
+ }
+ }
+ BM_remove_tagged_faces(bm, DEL_INPUT);
+ BM_remove_tagged_edges(bm, DEL_INPUT);
+}
+
+/*you need to make remove tagged verts/edges/faces
+ api functions that take a filter callback.....
+ and this new filter type will be for opstack flags.
+ This is because the BM_remove_taggedXXX functions bypass iterator API.
+ -Ops dont care about 'UI' considerations like selection state, hide state, ect. If you want to work on unhidden selections for instance,
+ copy output from a 'select context' operator to another operator....
+*/
+
+/*Break this into smaller functions*/
+
+static void delete_context(BMesh *bm, int type){
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ if(type == DEL_VERTS) delete_verts(bm);
+ else if(type == DEL_EDGES){
+ /*flush down to verts*/
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){
+ if(BMO_TestFlag(bm, (BMHeader*)e, DEL_INPUT)){
+ BMO_SetFlag(bm, (BMHeader*)(e->v1), DEL_INPUT);
+ BMO_SetFlag(bm, (BMHeader*)(e->v2), DEL_INPUT);
+ }
+ }
+ delete_edges(bm);
+ /*remove loose vertices*/
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){
+ if(BMO_TestFlag(bm, (BMHeader*)v, DEL_INPUT) && (!(v->e)))
+ BMO_SetFlag(bm, (BMHeader*)v, DEL_WIREVERT);
+ }
+ BM_remove_tagged_verts(bm, DEL_WIREVERT);
+ }
+ else if(type == DEL_EDGESFACES) delete_edges(bm);
+ else if(type == DEL_ONLYFACES) BM_remove_tagged_faces(bm, DEL_INPUT);
+ else if (type == DEL_ONLYTAGGED) {
+ BM_remove_tagged_faces(bm, DEL_INPUT);
+ BM_remove_tagged_edges(bm, DEL_INPUT);
+ BM_remove_tagged_verts(bm, DEL_INPUT);
+ } else if(type == DEL_FACES){
+ /*go through and mark all edges and all verts of all faces for delete*/
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){
+ if(BMO_TestFlag(bm, (BMHeader*)f, DEL_INPUT)){
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_FACE, f); e; e = BMIter_Step(&edges))
+ BMO_SetFlag(bm, (BMHeader*)e, DEL_INPUT);
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_FACE, f); v; v = BMIter_Step(&verts))
+ BMO_SetFlag(bm, (BMHeader*)v, DEL_INPUT);
+ }
+ }
+ /*now go through and mark all remaining faces all edges for keeping.*/
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){
+ if(!BMO_TestFlag(bm, (BMHeader*)f, DEL_INPUT)){
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_FACE, f); e; e= BMIter_Step(&edges))
+ BMO_ClearFlag(bm, (BMHeader*)e, DEL_INPUT);
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_FACE, f); v; v= BMIter_Step(&verts))
+ BMO_ClearFlag(bm, (BMHeader*)v, DEL_INPUT);
+ }
+ }
+ /*now delete marked faces*/
+ BM_remove_tagged_faces(bm, DEL_INPUT);
+ /*delete marked edges*/
+ BM_remove_tagged_edges(bm, DEL_INPUT);
+ /*remove loose vertices*/
+ BM_remove_tagged_verts(bm, DEL_INPUT);
+ }
+ /*does this option even belong in here?*/
+ else if(type == DEL_ALL){
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces))
+ BMO_SetFlag(bm, (BMHeader*)f, DEL_INPUT);
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges))
+ BMO_SetFlag(bm, (BMHeader*)e, DEL_INPUT);
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts))
+ BMO_SetFlag(bm, (BMHeader*)v, DEL_INPUT);
+
+ BM_remove_tagged_faces(bm, DEL_INPUT);
+ BM_remove_tagged_edges(bm, DEL_INPUT);
+ BM_remove_tagged_verts(bm, DEL_INPUT);
+ }
+}
diff --git a/source/blender/bmesh/operators/connectops.c b/source/blender/bmesh/operators/connectops.c
new file mode 100644
index 00000000000..22e9d5494f0
--- /dev/null
+++ b/source/blender/bmesh/operators/connectops.c
@@ -0,0 +1,103 @@
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "bmesh.h"
+#include "mesh_intern.h"
+#include "bmesh_private.h"
+#include "BLI_math.h"
+#include "BLI_array.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#define VERT_INPUT 1
+#define EDGE_OUT 1
+#define FACE_NEW 2
+
+void connectverts_exec(BMesh *bm, BMOperator *op)
+{
+ BMIter iter, liter;
+ BMFace *f, *nf;
+ BMLoop **loops = NULL, *lastl = NULL;
+ BLI_array_declare(loops);
+ BMLoop *l, *nl;
+ BMVert *v1, *v2, **verts = NULL;
+ BLI_array_declare(verts);
+ int i;
+
+ BMO_Flag_Buffer(bm, op, "verts", VERT_INPUT, BM_VERT);
+
+ for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); f; f=BMIter_Step(&iter)){
+ BLI_array_empty(loops);
+ BLI_array_empty(verts);
+
+ if (BMO_TestFlag(bm, f, FACE_NEW)) continue;
+
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ v1 = v2 = NULL;
+ lastl = NULL;
+ for (; l; l=BMIter_Step(&liter)) {
+ if (BMO_TestFlag(bm, l->v, VERT_INPUT)) {
+ if (!lastl) {
+ lastl = l;
+ continue;
+ }
+
+ if (lastl != l->prev && lastl !=
+ l->next)
+ {
+ BLI_array_growone(loops);
+ loops[BLI_array_count(loops)-1] = lastl;
+
+ BLI_array_growone(loops);
+ loops[BLI_array_count(loops)-1] = l;
+
+ }
+ lastl = l;
+ }
+ }
+
+ if (BLI_array_count(loops) == 0) continue;
+
+ if (BLI_array_count(loops) > 2) {
+ BLI_array_growone(loops);
+ loops[BLI_array_count(loops)-1] = loops[BLI_array_count(loops)-2];
+
+ BLI_array_growone(loops);
+ loops[BLI_array_count(loops)-1] = loops[0];
+ }
+
+ BM_LegalSplits(bm, f, loops, BLI_array_count(loops)/2);
+
+ for (i=0; i<BLI_array_count(loops)/2; i++) {
+ if (loops[i*2]==NULL) continue;
+
+ BLI_array_growone(verts);
+ verts[BLI_array_count(verts)-1] = loops[i*2]->v;
+
+ BLI_array_growone(verts);
+ verts[BLI_array_count(verts)-1] = loops[i*2+1]->v;
+ }
+
+ for (i=0; i<BLI_array_count(verts)/2; i++) {
+ nf = BM_Split_Face(bm, f, verts[i*2],
+ verts[i*2+1], &nl, NULL);
+ f = nf;
+
+ if (!nl || !nf) {
+ BMO_RaiseError(bm, op,
+ BMERR_CONNECTVERT_FAILED, NULL);
+ BLI_array_free(loops);
+ return;;;
+ }
+ BMO_SetFlag(bm, nf, FACE_NEW);
+ BMO_SetFlag(bm, nl->e, EDGE_OUT);
+ }
+ }
+
+ BMO_Flag_To_Slot(bm, op, "edgeout", EDGE_OUT, BM_EDGE);
+
+ BLI_array_free(loops);
+ BLI_array_free(verts);
+}
diff --git a/source/blender/bmesh/operators/createops.c b/source/blender/bmesh/operators/createops.c
new file mode 100644
index 00000000000..fda4bd83b5f
--- /dev/null
+++ b/source/blender/bmesh/operators/createops.c
@@ -0,0 +1,1284 @@
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "BLI_memarena.h"
+#include "BLI_mempool.h"
+#include "BLI_heap.h"
+#include "BLI_ghash.h"
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_array.h"
+#include "BLI_smallhash.h"
+#include "BLI_rand.h"
+
+#include "bmesh.h"
+#include "bmesh_operators_private.h"
+
+#define EDGE_MARK 1
+#define EDGE_VIS 2
+
+#define FACE_NEW 1
+
+#define ELE_NEW 1
+#define ELE_OUT 2
+#define ELE_ORIG 4
+
+#define FACE_IGNORE 16
+
+typedef struct EPathNode {
+ struct EPathNode *next, *prev;
+ BMVert *v;
+ BMEdge *e;
+ BMEdge *cure;
+} EPathNode;
+
+typedef struct EPath {
+ ListBase nodes;
+ float weight;
+ int group;
+} EPath;
+
+typedef struct PathBase {
+ BLI_mempool *nodepool, *pathpool;
+} PathBase;
+
+typedef struct EdgeData {
+ int tag;
+ int ftag;
+
+ struct {
+ struct BMEdge *next, *prev;
+ } dlink1;
+ struct {
+ struct BMEdge *next, *prev;
+ } dlink2;
+} EdgeData;
+
+typedef struct VertData {
+ BMEdge *e;
+ float no[3], offco[3], sco[3]; /*offco is vertex coordinate slightly offset randomly*/
+ int tag;
+} VertData;
+
+static int count_edge_faces(BMesh *bm, BMEdge *e);
+
+/**** rotation system code ***/
+
+#define rs_get_edge_link(e, v, ed) (Link*)((v) == ((BMEdge*)(e))->v1 ? &(((EdgeData*)(ed))->dlink1) : &(((EdgeData*)(ed))->dlink2))
+
+int rotsys_append_edge(struct BMEdge *e, struct BMVert *v,
+ EdgeData *edata, VertData *vdata)
+{
+ EdgeData *ed = &edata[BMINDEX_GET(e)];
+ VertData *vd = &vdata[BMINDEX_GET(v)];
+
+ if (!vd->e) {
+ Link *e1 = (Link*)rs_get_edge_link(e, v, ed);
+
+ vd->e = e;
+ e1->next = e1->prev = (Link*)e;
+ } else {
+ Link *e1, *e2, *e3;
+ EdgeData *ved = &edata[BMINDEX_GET(vd->e)];
+
+ e1 = rs_get_edge_link(e, v, ed);
+ e2 = rs_get_edge_link(vd->e, v, ved);
+ e3 = e2->prev ? rs_get_edge_link(e2->prev, v, &edata[BMINDEX_GET(e2->prev)]) : NULL;
+
+ e1->next = (Link*)vd->e;
+ e1->prev = e2->prev;
+
+ e2->prev = (Link*)e;
+ if (e3)
+ e3->next = (Link*)e;
+ }
+
+ return 1;
+}
+
+void rotsys_remove_edge(struct BMEdge *e, struct BMVert *v,
+ EdgeData *edata, VertData *vdata)
+{
+ EdgeData *ed = edata + BMINDEX_GET(e);
+ VertData *vd = vdata + BMINDEX_GET(v);
+ Link *e1, *e2;
+
+ e1 = rs_get_edge_link(e, v, ed);
+ if (e1->prev) {
+ e2 = rs_get_edge_link(e1->prev, v, ed);
+ e2->next = e1->next;
+ }
+
+ if (e1->next) {
+ e2 = rs_get_edge_link(e1->next, v, ed);
+ e2->prev = e1->prev;
+ }
+
+ if (vd->e == e)
+ vd->e = e!=e1->next ? (BMEdge*)e1->next : NULL;
+
+ e1->next = e1->prev = NULL;
+}
+
+struct BMEdge *rotsys_nextedge(struct BMEdge *e, struct BMVert *v,
+ EdgeData *edata, VertData *vdata)
+{
+ if (v == e->v1)
+ return edata[BMINDEX_GET(e)].dlink1.next;
+ if (v == e->v2)
+ return edata[BMINDEX_GET(e)].dlink2.next;
+ return NULL;
+}
+
+BMEdge *rotsys_prevedge(BMEdge *e, BMVert *v,
+ EdgeData *edata, VertData *vdata)
+{
+ if (v == e->v1)
+ return edata[BMINDEX_GET(e)].dlink1.prev;
+ if (v == e->v2)
+ return edata[BMINDEX_GET(e)].dlink2.prev;
+ return NULL;
+}
+
+struct BMEdge *rotsys_reverse(struct BMEdge *e, struct BMVert *v, EdgeData *edata, VertData *vdata)
+{
+ BMEdge **edges = NULL;
+ BMEdge *e2;
+ BLI_array_staticdeclare(edges, 256);
+ int i, totedge;
+
+ e2 = vdata[BMINDEX_GET(v)].e;
+ do {
+ BLI_array_append(edges, e2);
+ e2 = rotsys_nextedge(e2, v, edata, vdata);
+ } while (e2 != vdata[BMINDEX_GET(v)].e);
+
+ totedge = BLI_array_count(edges);
+ for (i=0; i<totedge/2; i++) {
+ SWAP(BMEdge*, edges[i], edges[totedge-1-i]);
+ }
+
+ vdata[BMINDEX_GET(v)].e = NULL;
+ for (i=0; i<totedge; i++) {
+ rotsys_append_edge(edges[i], v, edata, vdata);
+ }
+
+ BLI_array_free(edges);
+
+ return 0;
+}
+
+int rotsys_count(struct BMVert *v, EdgeData *edata, VertData *vdata)
+{
+ BMEdge *e = vdata[BMINDEX_GET(v)].e;
+ int i=0;
+
+ if (!e)
+ return 0;
+
+ do {
+ if (!e)
+ return 0;
+ e = rotsys_nextedge(e, v, edata, vdata);
+
+ if (i >= (1<<20)) {
+ printf("bmesh error: infinite loop in disk cycle!\n");
+ return 0;
+ }
+
+ i += 1;
+ } while (e != vdata[BMINDEX_GET(v)].e);
+
+ return i;
+}
+
+int rotsys_fill_faces(BMesh *bm, EdgeData *edata, VertData *vdata)
+{
+ BMIter iter;
+ BMEdge *e, **edges = NULL;
+ BLI_array_declare(edges);
+ BMVert *v, **verts = NULL;
+ BMFace *f;
+ BLI_array_declare(verts);
+ SmallHash visithash, *hash=&visithash;
+ int i;
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ BMEdge *e2, *starte;
+ BMVert *startv;
+ int rad, ok;
+
+ rad = count_edge_faces(bm, e);
+
+ if (rad < 2)
+ starte = e;
+ else
+ continue;
+
+ /*do two passes, going forward then backward*/
+ for (i=0; i<2; i++) {
+ BLI_smallhash_init(hash);
+
+ BLI_array_empty(verts);
+ BLI_array_empty(edges);
+
+ startv = v = starte->v1;
+ e2 = starte;
+ ok = 1;
+ if (!v || !e2)
+ continue;
+
+ do {
+ if (BLI_smallhash_haskey(hash, (intptr_t)e2)
+ || BLI_smallhash_haskey(hash, (intptr_t)v)) {
+ ok = 0;
+ break;
+ }
+
+ BLI_array_append(verts, v);
+ BLI_array_append(edges, e2);
+
+ BLI_smallhash_insert(hash, (intptr_t)e2, NULL);
+
+ v = BM_OtherEdgeVert(e2, v);
+ e2 = i ? rotsys_prevedge(e2, v, edata, vdata) : rotsys_nextedge(e2, v, edata, vdata);
+ } while (e2 != starte && v != startv);
+
+ BLI_smallhash_release(hash);
+
+ if (!ok || BLI_array_count(edges) < 3)
+ continue;
+
+ f = BM_Make_Ngon(bm, verts[0], verts[1], edges, BLI_array_count(edges), 1);
+ if (!f)
+ continue;
+ }
+ }
+
+ return 0;
+}
+
+void rotsys_make_consistent(BMesh *bm, EdgeData *edata, VertData *vdata)
+{
+ BMIter iter;
+ BMEdge *e;
+ BMVert *v, **stack=NULL;
+ BLI_array_declare(stack);
+ int i;
+
+ for (i=0; i<bm->totvert; i++) {
+ vdata[i].tag = 0;
+ }
+
+ while (1) {
+ VertData *vd;
+ BMVert *startv = NULL;
+ float dis;
+
+ v = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; i<bm->totvert; i++, BMIter_Step(&iter)) {
+ vd = vdata + BMINDEX_GET(v);
+
+ if (vd->tag)
+ continue;
+
+ if (!startv || dot_v3v3(vd->offco, vd->offco) > dis) {
+ dis = dot_v3v3(vd->offco, vd->offco);
+ startv = v;
+ }
+ }
+
+ if (!startv)
+ break;
+
+ vd = vdata + BMINDEX_GET(startv);
+
+ BLI_array_empty(stack);
+ BLI_array_append(stack, startv);
+
+ vd->tag = 1;
+
+ while (BLI_array_count(stack)) {
+ v = BLI_array_pop(stack);
+ vd = vdata + BMINDEX_GET(v);
+
+ if (!vd->e)
+ continue;
+
+ e = vd->e;
+ do {
+ BMVert *v2 = BM_OtherEdgeVert(e, v);
+ VertData *vd2 = vdata + BMINDEX_GET(v2);
+
+ if (dot_v3v3(vd->no, vd2->no) < 0.0f+FLT_EPSILON*2) {
+ rotsys_reverse(e, v2, edata, vdata);
+ mul_v3_fl(vd2->no, -1.0f);
+ }
+
+ if (!vd2->tag) {
+ BLI_array_append(stack, v2);
+ vd2->tag = 1;
+ }
+
+ e = rotsys_nextedge(e, v, edata, vdata);
+ } while (e != vd->e);
+ }
+ }
+
+}
+
+void init_rotsys(BMesh *bm, EdgeData *edata, VertData *vdata)
+{
+ BMIter iter;
+ BMEdge *e;
+ BMEdge **edges = NULL;
+ BLI_array_staticdeclare(edges, 256);
+ BMVert *v, *lastv, **verts = NULL;
+ BLI_array_staticdeclare(verts, 256);
+ int i;
+
+ #define SIGN(n) ((n)<0.0f)
+
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BMIter eiter;
+ float no[3], cent[3];
+ int j, k=0, totedge=0;
+
+ if (BMINDEX_GET(v) == -1)
+ continue;
+
+ BLI_array_empty(edges);
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ if (BMO_TestFlag(bm, e, EDGE_MARK)) {
+ BLI_array_append(edges, e);
+ totedge++;
+ }
+ }
+
+ copy_v3_v3(cent, v->co);
+
+ zero_v3(no);
+ for (i=0; i<totedge; i++) {
+ BMEdge *e1, *e2;
+ float cno[3], vec1[3], vec2[3];
+
+ e1 = edges[i];
+ e2 = edges[(i+1)%totedge];
+
+ sub_v3_v3v3(vec1, (BM_OtherEdgeVert(e1, v))->co, v->co);
+ sub_v3_v3v3(vec2, (BM_OtherEdgeVert(e2, v))->co, v->co);
+
+ cross_v3_v3v3(cno, vec1, vec2);
+ normalize_v3(cno);
+
+ if (i && dot_v3v3(cno, no) < 0.0f+FLT_EPSILON*10)
+ mul_v3_fl(cno, -1.0f);
+
+ add_v3_v3(no, cno);
+ normalize_v3(no);
+ }
+
+ /*generate plane-flattened coordinates*/
+ for (i=0; i<totedge; i++) {
+ BMEdge *e1;
+ BMVert *v2;
+ float cvec[3], vec1[3];
+
+ e1 = edges[i];
+ v2 = BM_OtherEdgeVert(e1, v);
+
+ sub_v3_v3v3(vec1, v2->co, v->co);
+
+ cross_v3_v3v3(cvec, vec1, no);
+ cross_v3_v3v3(vec1, cvec, no);
+ normalize_v3(vec1);
+
+ mul_v3_fl(vec1, len_v3v3(v2->co, v->co));
+ add_v3_v3(vec1, v->co);
+
+ copy_v3_v3(vdata[BMINDEX_GET(v2)].sco, vec1);
+ }
+
+ BLI_srandom(0);
+
+ /*first, ensure no 0 or 180 angles between adjacent
+ (and that adjacent's adjacent) edges*/
+ for (i=0, k=0; i<totedge; i++) {
+ BMEdge *e1, *e2, *e3=NULL;
+ BMVert *v1, *v2, *v3;
+ VertData *vd1, *vd2, *vd3;
+ float vec1[3], vec2[3], vec3[3], size;
+ int s1, s2, s3;
+
+ if (totedge < 3)
+ continue;
+
+ e1 = edges[(i+totedge-1) % totedge];
+ e2 = edges[i];
+ e3 = edges[(i+1) % totedge];
+
+ v1 = BM_OtherEdgeVert(e1, v); v2 = BM_OtherEdgeVert(e2, v); v3 = BM_OtherEdgeVert(e3, v);
+ vd1 = vdata+BMINDEX_GET(v1); vd2 = vdata+BMINDEX_GET(v2); vd3 = vdata+BMINDEX_GET(v3);
+
+ sub_v3_v3v3(vec1, vd1->sco, cent);
+ sub_v3_v3v3(vec2, vd2->sco, cent);
+ sub_v3_v3v3(vec3, vd3->sco, cent);
+
+ size = (len_v3(vec1) + len_v3(vec3))*0.01;
+ normalize_v3(vec1); normalize_v3(vec2); normalize_v3(vec3);
+
+ #ifdef STRAIGHT
+ #undef STRAIGHT
+ #endif
+ #define STRAIGHT(vec11, vec22) (fabs(dot_v3v3((vec11), (vec22))) > 1.0-FLT_EPSILON*1000)
+
+ s1 = STRAIGHT(vec1, vec2); s2 = STRAIGHT(vec2, vec3); s3 = STRAIGHT(vec1, vec3);
+
+ if (s1 || s2 || s3) {
+ copy_v3_v3(cent, v->co);
+
+ for (j=0; j<3; j++) {
+ float fac = (BLI_frand()-0.5f)*size;
+ cent[j] += fac;
+ }
+
+ if (k < 2000) {
+ i = 0;
+ k++;
+ continue;
+ } else {
+ k++;
+ continue;
+ }
+
+ }
+ }
+
+ copy_v3_v3(vdata[BMINDEX_GET(v)].offco, cent);
+ //copy_v3_v3(v->co, cent);
+
+ /*now, sort edges so the triangle fan of all edges
+ has a consistent normal. this is the same as
+ sorting by polar coordinates along a group normal*/
+ for (j=0; j<totedge; j++) {
+ for (i=0; i<totedge; i++) {
+ BMEdge *e1, *e2, *e3=NULL;
+ BMVert *v1, *v2, *v3;
+ VertData *vd1, *vd2, *vd3;
+ float vec1[3], vec2[3], vec3[3], n1[3], n2[3], n3[3];
+ int s1, s2, s3;
+
+ e1 = edges[(i+totedge-1) % totedge];
+ e2 = edges[i];
+ e3 = edges[(i+1) % totedge];
+
+ v1 = BM_OtherEdgeVert(e1, v); v2 = BM_OtherEdgeVert(e2, v); v3 = BM_OtherEdgeVert(e3, v);
+ vd1 = vdata+BMINDEX_GET(v1); vd2 = vdata+BMINDEX_GET(v2); vd3 = vdata+BMINDEX_GET(v3);
+
+ sub_v3_v3v3(vec1, vd1->sco, cent);
+ sub_v3_v3v3(vec2, vd2->sco, cent);
+ sub_v3_v3v3(vec3, vd3->sco, cent);
+
+ cross_v3_v3v3(n1, vec1, vec2);
+ cross_v3_v3v3(n2, vec2, vec3);
+ cross_v3_v3v3(n3, vec1, vec3);
+
+ normalize_v3(n1); normalize_v3(n2); normalize_v3(n3);
+
+ s1 = STRAIGHT(vec1, vec2); s2 = STRAIGHT(vec2, vec3); s3 = STRAIGHT(vec1, vec3);
+
+ if (s1 || s2 || s3) {
+ printf("yeek! s1: %d, s2: %d, s3: %dx\n", s1, s2, s3);
+ }
+ if (dot_v3v3(n1, n2) < 0.0f) {
+ if (dot_v3v3(n1, n3) >= 0.0f + FLT_EPSILON*10) {
+ SWAP(BMEdge*, edges[i], edges[(i+1)%totedge]);
+ } else {
+ SWAP(BMEdge*, edges[(i+totedge-1)%totedge], edges[(i+1)%totedge])
+ SWAP(BMEdge*, edges[i], edges[(i+1)%totedge])
+ }
+ }
+ }
+ }
+
+ #undef STRAIGHT
+
+ zero_v3(no);
+
+ /*yay, edges is sorted*/
+ for (i=0; i<totedge; i++) {
+ BMEdge *e1 = edges[i], *e2 = edges[(i+1)%totedge];
+ float eno[3];
+
+ normal_tri_v3(eno, BM_OtherEdgeVert(e1, v)->co, v->co, BM_OtherEdgeVert(e2, v)->co);
+ add_v3_v3(no, eno);
+
+ rotsys_append_edge(edges[i], v, edata, vdata);
+ }
+
+ normalize_v3(no);
+ copy_v3_v3(vdata[BMINDEX_GET(v)].no, no);
+ }
+
+ /*now, make sure rotation system is topologically consistent
+ (e.g. vert normals consistently point either inside or outside)*/
+ rotsys_make_consistent(bm, edata, vdata);
+
+ //rotsys_fill_faces(bm, edata, vdata);
+
+#if 0
+ /*create visualizing geometry*/
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BMVert *v2;
+ BMFace *f;
+ int totedge = BM_Vert_EdgeCount(v);
+
+ if (BMINDEX_GET(v) == -1)
+ continue;
+
+ //cv = BM_Make_Vert(bm, cent, v);
+ //BMINDEX_SET(cv, -1);
+ i = 0;
+ e = vdata[BMINDEX_GET(v)].e;
+ lastv = NULL;
+ do {
+ BMEdge *e2;
+ BMVert *v2;
+ float f = ((float)i / (float)totedge)*0.35 + 0.05;
+ float co[3];
+
+ if (!e)
+ break;
+
+ if (!BM_OtherEdgeVert(e, v))
+ continue;
+
+ sub_v3_v3v3(co, (BM_OtherEdgeVert(e, v))->co, vdata[BMINDEX_GET(v)].offco);
+ mul_v3_fl(co, f);
+ add_v3_v3(co, vdata[BMINDEX_GET(v)].offco);
+
+ v2 = BM_Make_Vert(bm, co, NULL);
+ BMINDEX_SET(v2, -1);
+ //BM_Make_Edge(bm, cv, v2, NULL, 0);
+
+ BM_Select(bm, v2, 1);
+ if (lastv) {
+ e2 =
+ BM_Make_Edge(bm, lastv, v2, NULL, 0);
+ BM_Select(bm, e2, 1);
+ }
+
+ lastv = v2;
+
+ e = rotsys_nextedge(e, v, edata, vdata);
+ i++;
+ } while (e != vdata[BMINDEX_GET(v)].e);
+ }
+#endif
+
+ BLI_array_free(edges);
+}
+
+PathBase *edge_pathbase_new(void)
+{
+ PathBase *pb = MEM_callocN(sizeof(PathBase), "PathBase");
+
+ pb->nodepool = BLI_mempool_create(sizeof(EPathNode), 1, 512, 1, 0);
+ pb->pathpool = BLI_mempool_create(sizeof(EPath), 1, 512, 1, 0);
+
+ return pb;
+}
+
+void edge_pathbase_free(PathBase *pathbase)
+{
+ BLI_mempool_destroy(pathbase->nodepool);
+ BLI_mempool_destroy(pathbase->pathpool);
+ MEM_freeN(pathbase);
+}
+
+EPath *edge_copy_add_path(PathBase *pb, EPath *path, BMVert *appendv, BMEdge *e)
+{
+ EPath *path2;
+ EPathNode *node, *node2;
+
+ path2 = BLI_mempool_alloc(pb->pathpool);
+ path2->nodes.first = path2->nodes.last = NULL;
+ path2->weight = 0.0f;
+ path2->group = path->group;
+
+ for (node=path->nodes.first; node; node=node->next) {
+ node2 = BLI_mempool_alloc(pb->nodepool);
+ *node2 = *node;
+ BLI_addtail(&path2->nodes, node2);
+ }
+
+ node2 = BLI_mempool_alloc(pb->nodepool);
+ node2->v = appendv;
+ node2->e = e;
+ node2->cure = NULL;
+
+ BLI_addtail(&path2->nodes, node2);
+
+ return path2;
+}
+
+EPath *edge_path_new(PathBase *pb, BMVert *start, BMEdge *starte)
+{
+ EPath *path;
+ EPathNode *node;
+
+ path = BLI_mempool_alloc(pb->pathpool);
+ node = BLI_mempool_alloc(pb->nodepool);
+
+ path->nodes.first = path->nodes.last = NULL;
+
+ node->v = start;
+ node->e = starte;
+ node->cure = NULL;
+
+ BLI_addtail(&path->nodes, node);
+ path->weight = 0.0f;
+
+ return path;
+}
+
+float edge_weight_path(EPath *path, EdgeData *edata, VertData *vdata)
+{
+ EPathNode *node, *first=path->nodes.first;
+ float w = 0.0;
+
+ for (node=path->nodes.first; node; node=node->next) {
+ if (node->e && node != path->nodes.first) {
+ w += edata[BMINDEX_GET(node->e)].ftag;
+ if (node->prev) {
+ //w += len_v3v3(node->v->co, first->e->v1->co)*0.0001f;
+ //w += len_v3v3(node->v->co, first->e->v2->co)*0.0001f;
+ }
+ }
+
+ w += 1.0f;
+ }
+
+ return w;
+}
+
+
+void edge_free_path(PathBase *pathbase, EPath *path)
+{
+ EPathNode *node, *next;
+
+ for (node=path->nodes.first; node; node=next) {
+ next = node->next;
+ BLI_mempool_free(pathbase->nodepool, node);
+ }
+
+ BLI_mempool_free(pathbase->pathpool, path);
+}
+
+EPath *edge_find_shortest_path(BMesh *bm, BMOperator *op, BMEdge *edge, EdgeData *edata,
+ VertData *vdata, PathBase *pathbase, int group)
+{
+ BMEdge *e, *starte;
+ GHash *gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "createops find shortest path");
+ BMVert *v1, *v2;
+ BMVert **verts = NULL;
+ BLI_array_staticdeclare(verts, 1024);
+ Heap *heap = BLI_heap_new();
+ EPath *path = NULL, *path2;
+ BMVert *startv;
+ BMVert *endv;
+ EPathNode *node;
+ int i, use_restrict = BMO_Get_Int(op, "use_restrict");
+
+ startv = edata[BMINDEX_GET(edge)].ftag ? edge->v2 : edge->v1;
+ endv = edata[BMINDEX_GET(edge)].ftag ? edge->v1 : edge->v2;
+
+ path = edge_path_new(pathbase, startv, edge);
+ BLI_ghash_insert(gh, startv, NULL);
+ BLI_heap_insert(heap, path->weight, path);
+ path->group = group;
+
+ while (BLI_heap_size(heap)) {
+ VertData *vd;
+ EPathNode *last;
+ BMFace *f = NULL;
+
+ path = BLI_heap_popmin(heap);
+ last = path->nodes.last;
+ v1 = last->v;
+
+ if (v1 == endv) {
+ /*make sure this path loop doesn't already exist*/
+ i = 0;
+ BLI_array_empty(verts);
+ for (i=0, node = path->nodes.first; node; node=node->next, i++) {
+ BLI_array_growone(verts);
+ verts[i] = node->v;
+ }
+
+ if (BM_Face_Exists(bm, verts, i, &f)) {
+ if (!BMO_TestFlag(bm, f, FACE_IGNORE)) {
+ BLI_ghash_remove(gh, endv, NULL, NULL);
+ continue;
+ }
+ }
+ break;
+ }
+
+ vd = vdata + BMINDEX_GET(v1);
+ if (!vd->e)
+ continue;
+
+ v2 = NULL;
+ while (1) {
+ if (!last->cure) {
+ last->cure = e = vdata[BMINDEX_GET(last->v)].e;
+ } else {
+ last->cure = e = rotsys_nextedge(last->cure, last->v, edata, vdata);
+ if (last->cure == vdata[BMINDEX_GET(last->v)].e) {
+ v2 = NULL;
+ break;
+ }
+ }
+
+ if (e == edge || !BMO_TestFlag(bm, e, EDGE_MARK)) {
+ continue;
+ }
+
+ v2 = BM_OtherEdgeVert(e, last->v);
+
+ if (BLI_ghash_haskey(gh, v2)) {
+ v2 = NULL;
+ continue;
+ }
+
+ if (use_restrict && BMO_InMap(bm, op, "restrict", e)) {
+ int group = BMO_Get_MapInt(bm, op, "restrict", e);
+
+ if (!(group & path->group)) {
+ v2 = NULL;
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ if (!v2) {
+ if (path) {
+ edge_free_path(pathbase, path);
+ path = NULL;
+ }
+ continue;
+ }
+
+ /*add path back into heap*/
+ BLI_heap_insert(heap, path->weight, path);
+
+ /*put v2 in gh map*/
+ BLI_ghash_insert(gh, v2, NULL);
+
+ path2 = edge_copy_add_path(pathbase, path, v2, e);
+ path2->weight = edge_weight_path(path2, edata, vdata);
+
+ BLI_heap_insert(heap, path2->weight, path2);
+ }
+
+ if (path && ((EPathNode*)path->nodes.last)->v != endv) {
+ edge_free_path(pathbase, path);
+ path = NULL;
+ }
+
+ BLI_array_free(verts);
+ BLI_heap_free(heap, NULL);
+ BLI_ghash_free(gh, NULL, NULL);
+
+ return path;
+}
+
+static int count_edge_faces(BMesh *bm, BMEdge *e) {
+ int i=0;
+ BMLoop *l = e->l;
+
+ if (!l)
+ return 0;
+
+ do {
+ if (!BMO_TestFlag(bm, l->f, FACE_IGNORE))
+ i++;
+
+ l = l->radial_next;
+ } while (l != e->l);
+
+ return i;
+}
+
+void bmesh_edgenet_fill_exec(BMesh *bm, BMOperator *op)
+{
+ BMIter iter;
+ BMOIter siter;
+ BMFace *f;
+ BMEdge *e, *edge;
+ BMVert *v, **verts = NULL;
+ BLI_array_declare(verts);
+ EPath *path;
+ EPathNode *node;
+ EdgeData *edata;
+ VertData *vdata;
+ BMEdge **edges = NULL;
+ PathBase *pathbase = edge_pathbase_new();
+ BLI_array_declare(edges);
+ int use_restrict = BMO_Get_Int(op, "use_restrict");
+ int i, j, group = 0;
+
+ if (!bm->totvert || !bm->totedge)
+ return;
+
+ edata = MEM_callocN(sizeof(EdgeData)*bm->totedge, "EdgeData");
+ vdata = MEM_callocN(sizeof(VertData)*bm->totvert, "VertData");
+
+ BMO_Flag_Buffer(bm, op, "edges", EDGE_MARK, BM_EDGE);
+ BMO_Flag_Buffer(bm, op, "excludefaces", FACE_IGNORE, BM_FACE);
+
+ i = 0;
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(v, i);
+ i++;
+ }
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BMO_SetFlag(bm, f, ELE_ORIG);
+ }
+
+ i = 0;
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ BMINDEX_SET(e, i);
+
+ if (!BMO_TestFlag(bm, e, EDGE_MARK)) {
+ edata[i].tag = 2;
+ }
+
+ i += 1;
+ }
+
+ init_rotsys(bm, edata, vdata);
+
+ while (1) {
+ edge = NULL;
+ group = 0;
+
+ BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
+ /*if restrict is on, only start on faces in the restrict map*/
+ if (use_restrict && !BMO_InMap(bm, op, "restrict", e))
+ continue;
+
+ if (edata[BMINDEX_GET(e)].tag < 2) {
+ edge = e;
+
+ if (use_restrict) {
+ int i=0, j=0, gi=0;
+
+ group = BMO_Get_MapInt(bm, op, "restrict", e);
+
+ for (i=0; i<30; i++) {
+ if (group & (1<<i)) {
+ j++;
+ gi = i;
+
+ if (j-1 == edata[BMINDEX_GET(e)].tag)
+ break;
+ }
+ }
+
+ group = 1<<gi;
+ }
+
+ break;
+ }
+ }
+
+ if (!edge)
+ break;
+
+ edata[BMINDEX_GET(edge)].tag += 1;
+
+ path = edge_find_shortest_path(bm, op, edge, edata, vdata, pathbase, group);
+ if (!path)
+ continue;
+
+ BLI_array_empty(edges);
+ BLI_array_empty(verts);
+ i = 0;
+ for (node=path->nodes.first; node; node=node->next) {
+ if (!node->next)
+ continue;
+
+ e = BM_Edge_Exist(node->v, node->next->v);
+
+ /*this should never happen*/
+ if (!e)
+ break;
+
+ edata[BMINDEX_GET(e)].ftag++;
+ BLI_array_growone(edges);
+ edges[i++] = e;
+
+ BLI_array_append(verts, node->v);
+ }
+
+ BLI_array_growone(edges);
+ edges[i++] = edge;
+ edata[BMINDEX_GET(edge)].ftag++;
+
+ for (j=0; j<i; j++) {
+ if (count_edge_faces(bm, edges[j]) >= 2) {
+ edge_free_path(pathbase, path);
+ break;
+ }
+ }
+
+ if (j != i)
+ continue;
+
+ if (i) {
+ f = BM_Make_Ngon(bm, edge->v1, edge->v2, edges, i, 1);
+ if (f && !BMO_TestFlag(bm, f, ELE_ORIG)) {
+ BMO_SetFlag(bm, f, FACE_NEW);
+ }
+
+ if (use_restrict)
+ BMO_Insert_MapInt(bm, op, "faceout_groupmap", f, path->group);
+ }
+
+ edge_free_path(pathbase, path);
+ }
+
+ BMO_Flag_To_Slot(bm, op, "faceout", FACE_NEW, BM_FACE);
+
+ BLI_array_free(edges);
+ BLI_array_free(verts);
+ edge_pathbase_free(pathbase);
+ MEM_freeN(edata);
+ MEM_freeN(vdata);
+}
+
+/* evaluate if entire quad is a proper convex quad */
+static int convex(float *v1, float *v2, float *v3, float *v4)
+{
+ float nor[3], nor1[3], nor2[3], vec[4][2];
+
+ /* define projection, do both trias apart, quad is undefined! */
+ normal_tri_v3( nor1,v1, v2, v3);
+ normal_tri_v3( nor2,v1, v3, v4);
+ nor[0]= ABS(nor1[0]) + ABS(nor2[0]);
+ nor[1]= ABS(nor1[1]) + ABS(nor2[1]);
+ nor[2]= ABS(nor1[2]) + ABS(nor2[2]);
+
+ if(nor[2] >= nor[0] && nor[2] >= nor[1]) {
+ vec[0][0]= v1[0]; vec[0][1]= v1[1];
+ vec[1][0]= v2[0]; vec[1][1]= v2[1];
+ vec[2][0]= v3[0]; vec[2][1]= v3[1];
+ vec[3][0]= v4[0]; vec[3][1]= v4[1];
+ }
+ else if(nor[1] >= nor[0] && nor[1]>= nor[2]) {
+ vec[0][0]= v1[0]; vec[0][1]= v1[2];
+ vec[1][0]= v2[0]; vec[1][1]= v2[2];
+ vec[2][0]= v3[0]; vec[2][1]= v3[2];
+ vec[3][0]= v4[0]; vec[3][1]= v4[2];
+ }
+ else {
+ vec[0][0]= v1[1]; vec[0][1]= v1[2];
+ vec[1][0]= v2[1]; vec[1][1]= v2[2];
+ vec[2][0]= v3[1]; vec[2][1]= v3[2];
+ vec[3][0]= v4[1]; vec[3][1]= v4[2];
+ }
+
+ /* linetests, the 2 diagonals have to instersect to be convex */
+ if( isect_line_line_v2(vec[0], vec[2], vec[1], vec[3]) > 0 ) return 1;
+ return 0;
+}
+
+BMEdge *edge_next(BMesh *bm, BMEdge *e)
+{
+ BMIter iter;
+ BMEdge *e2;
+ int i;
+
+ for (i=0; i<2; i++) {
+ BM_ITER(e2, &iter, bm, BM_EDGES_OF_VERT, i?e->v2:e->v1) {
+ if (BMO_TestFlag(bm, e2, EDGE_MARK)
+ && !BMO_TestFlag(bm, e2, EDGE_VIS) && e2 != e)
+ {
+ return e2;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void bmesh_edgenet_prepare(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMIter iter;
+ BMEdge *e, *e2;
+ BMEdge **edges1 = NULL, **edges2 = NULL, **edges;
+ BLI_array_declare(edges1);
+ BLI_array_declare(edges2);
+ BLI_array_declare(edges);
+ int ok = 1;
+ int i, count;
+
+ BMO_Flag_Buffer(bm, op, "edges", EDGE_MARK, BM_EDGE);
+
+ /*validate that each edge has at most one other tagged edge in the
+ disk cycle around each of it's vertices*/
+ BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
+ for (i=0; i<2; i++) {
+ count = BMO_Vert_CountEdgeFlags(bm, i?e->v2:e->v1, EDGE_MARK);
+ if (count > 2) {
+ ok = 0;
+ break;
+ }
+ }
+
+ if (!ok) break;
+ }
+
+ /*we don't have valid edge layouts, return*/
+ if (!ok)
+ return;
+
+
+ /*find connected loops within the input edges*/
+ count = 0;
+ while (1) {
+ BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
+ if (!BMO_TestFlag(bm, e, EDGE_VIS)) {
+ if (BMO_Vert_CountEdgeFlags(bm, e->v1, EDGE_MARK)==1)
+ break;
+ if (BMO_Vert_CountEdgeFlags(bm, e->v2, EDGE_MARK)==1)
+ break;
+ }
+ }
+
+ if (!e) break;
+
+ if (!count)
+ edges = edges1;
+ else if (count==1)
+ edges = edges2;
+ else break;
+
+ i = 0;
+ while (e) {
+ BMO_SetFlag(bm, e, EDGE_VIS);
+ BLI_array_growone(edges);
+ edges[i] = e;
+
+ e = edge_next(bm, e);
+ i++;
+ }
+
+ if (!count) {
+ edges1 = edges;
+ BLI_array_set_length(edges1, BLI_array_count(edges));
+ } else {
+ edges2 = edges;
+ BLI_array_set_length(edges2, BLI_array_count(edges));
+ }
+
+ BLI_array_empty(edges);
+ count++;
+ }
+
+#define EDGECON(e1, e2) (e1->v1 == e2->v1 || e1->v2 == e2->v2 || e1->v1 == e2->v2)
+
+ if (edges1 && BLI_array_count(edges1) > 2 && EDGECON(edges1[0], edges1[BLI_array_count(edges1)-1])) {
+ if (edges2 && BLI_array_count(edges2) > 2 && EDGECON(edges2[0], edges2[BLI_array_count(edges2)-1])) {
+ BLI_array_free(edges1);
+ BLI_array_free(edges2);
+ return;
+ } else {
+ edges1 = edges2;
+ edges2 = NULL;
+ }
+ }
+
+ if (edges2 && BLI_array_count(edges2) > 2 && EDGECON(edges2[0], edges2[BLI_array_count(edges2)-1])) {
+ edges2 = NULL;
+ }
+
+ /*two unconnected loops, connect them*/
+ if (edges1 && edges2) {
+ BMVert *v1, *v2, *v3, *v4;
+
+ if (BLI_array_count(edges1)==1) {
+ v1 = edges1[0]->v1;
+ v2 = edges1[0]->v2;
+ } else {
+ if (BM_Vert_In_Edge(edges1[1], edges1[0]->v1))
+ v1 = edges1[0]->v2;
+ else v1 = edges1[0]->v1;
+
+ i = BLI_array_count(edges1)-1;
+ if (BM_Vert_In_Edge(edges1[i-1], edges1[i]->v1))
+ v2 = edges1[i]->v2;
+ else v2 = edges1[i]->v1;
+ }
+
+ if (BLI_array_count(edges2)==1) {
+ v3 = edges2[0]->v1;
+ v4 = edges2[0]->v2;
+ } else {
+ if (BM_Vert_In_Edge(edges2[1], edges2[0]->v1))
+ v3 = edges2[0]->v2;
+ else v3 = edges2[0]->v1;
+
+ i = BLI_array_count(edges2)-1;
+ if (BM_Vert_In_Edge(edges2[i-1], edges2[i]->v1))
+ v4 = edges2[i]->v2;
+ else v4 = edges2[i]->v1;
+ }
+
+ if (len_v3v3(v1->co, v3->co) > len_v3v3(v1->co, v4->co)) {
+ BMVert *v;
+ v = v3;
+ v3 = v4;
+ v4 = v;
+ }
+
+ e = BM_Make_Edge(bm, v1, v3, NULL, 1);
+ BMO_SetFlag(bm, e, ELE_NEW);
+ e = BM_Make_Edge(bm, v2, v4, NULL, 1);
+ BMO_SetFlag(bm, e, ELE_NEW);
+ } else if (edges1) {
+ BMVert *v1, *v2;
+
+ if (BLI_array_count(edges1) > 1) {
+ if (BM_Vert_In_Edge(edges1[1], edges1[0]->v1))
+ v1 = edges1[0]->v2;
+ else v1 = edges1[0]->v1;
+
+ i = BLI_array_count(edges1)-1;
+ if (BM_Vert_In_Edge(edges1[i-1], edges1[i]->v1))
+ v2 = edges1[i]->v2;
+ else v2 = edges1[i]->v1;
+
+ e = BM_Make_Edge(bm, v1, v2, NULL, 1);
+ BMO_SetFlag(bm, e, ELE_NEW);
+ }
+ }
+
+ BMO_Flag_To_Slot(bm, op, "edgeout", ELE_NEW, BM_EDGE);
+
+ BLI_array_free(edges1);
+ BLI_array_free(edges2);
+
+#undef EDGECON
+}
+
+/*this is essentially new fkey*/
+void bmesh_contextual_create_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator op2;
+ BMOIter oiter;
+ BMIter iter;
+ BMHeader *h;
+ BMVert *v, *verts[4];
+ BMEdge *e;
+ BMFace *f;
+ int totv=0, tote=0, totf=0, amount;
+
+ /*count number of each element type we were passed*/
+ BMO_ITER(h, &oiter, bm, op, "geom", BM_VERT|BM_EDGE|BM_FACE) {
+ switch (h->type) {
+ case BM_VERT: totv++; break;
+ case BM_EDGE: tote++; break;
+ case BM_FACE: totf++; break;
+ }
+
+ BMO_SetFlag(bm, h, ELE_NEW);
+ }
+
+ /*call edgenet create*/
+ /* call edgenet prepare op so additional face creation cases work*/
+ BMO_InitOpf(bm, &op2, "edgenet_prepare edges=%fe", ELE_NEW);
+ BMO_Exec_Op(bm, &op2);
+ BMO_Flag_Buffer(bm, &op2, "edgeout", ELE_NEW, BM_EDGE);
+ BMO_Finish_Op(bm, &op2);
+
+ BMO_InitOpf(bm, &op2, "edgenet_fill edges=%fe", ELE_NEW);
+ BMO_Exec_Op(bm, &op2);
+
+ /*return if edge net create did something*/
+ if (BMO_CountSlotBuf(bm, &op2, "faceout")) {
+ BMO_CopySlot(&op2, op, "faceout", "faceout");
+ BMO_Finish_Op(bm, &op2);
+ return;
+ }
+
+ BMO_Finish_Op(bm, &op2);
+
+ /*now call dissolve faces*/
+ BMO_InitOpf(bm, &op2, "dissolvefaces faces=%ff", ELE_NEW);
+ BMO_Exec_Op(bm, &op2);
+
+ /*if we dissolved anything, then return.*/
+ if (BMO_CountSlotBuf(bm, &op2, "regionout")) {
+ BMO_CopySlot(&op2, op, "regionout", "faceout");
+ BMO_Finish_Op(bm, &op2);
+ return;
+ }
+
+ BMO_Finish_Op(bm, &op2);
+
+ /*now, count how many verts we have*/
+ amount = 0;
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMO_TestFlag(bm, v, ELE_NEW)) {
+ verts[amount] = v;
+ amount++;
+
+ if (amount > 4) break;
+ }
+ }
+
+ if (amount == 2) {
+ /*create edge*/
+ e = BM_Make_Edge(bm, verts[0], verts[1], NULL, 1);
+ BMO_SetFlag(bm, e, ELE_OUT);
+ } else if (amount == 3) {
+ /*create triangle*/
+ BM_Make_QuadTri(bm, verts[0], verts[1], verts[2], NULL, NULL, 1);
+ } else if (amount == 4) {
+ f = NULL;
+
+ /* the order of vertices can be anything, 6 cases to check */
+ if( convex(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co) ) {
+ f= BM_Make_QuadTri(bm, verts[0], verts[1], verts[2], verts[3], NULL, 1);
+ }
+ else if( convex(verts[0]->co, verts[2]->co, verts[3]->co, verts[1]->co) ) {
+ f= BM_Make_QuadTri(bm, verts[0], verts[2], verts[3], verts[1], NULL, 1);
+ }
+ else if( convex(verts[0]->co, verts[2]->co, verts[1]->co, verts[3]->co) ) {
+ f= BM_Make_QuadTri(bm, verts[0], verts[2], verts[1], verts[3], NULL, 1);
+ }
+ else if( convex(verts[0]->co, verts[1]->co, verts[3]->co, verts[2]->co) ) {
+ f= BM_Make_QuadTri(bm, verts[0], verts[1], verts[3], verts[2], NULL, 1);
+ }
+ else if( convex(verts[0]->co, verts[3]->co, verts[2]->co, verts[1]->co) ) {
+ f= BM_Make_QuadTri(bm, verts[0], verts[3], verts[2], verts[1], NULL, 1);
+ }
+ else if( convex(verts[0]->co, verts[3]->co, verts[1]->co, verts[2]->co) ) {
+ f= BM_Make_QuadTri(bm, verts[0], verts[3], verts[1], verts[2], NULL, 1);
+ }
+ else {
+ printf("cannot find nice quad from concave set of vertices\n");
+ }
+
+ if (f) BMO_SetFlag(bm, f, ELE_OUT);
+ }
+}
diff --git a/source/blender/bmesh/operators/dissolveops.c b/source/blender/bmesh/operators/dissolveops.c
new file mode 100644
index 00000000000..ceffbaa56a1
--- /dev/null
+++ b/source/blender/bmesh/operators/dissolveops.c
@@ -0,0 +1,430 @@
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "bmesh.h"
+#include "mesh_intern.h"
+#include "bmesh_private.h"
+#include "BLI_math.h"
+#include "BLI_array.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define FACE_MARK 1
+#define FACE_ORIG 2
+#define FACE_NEW 4
+#define EDGE_MARK 1
+
+#define VERT_MARK 1
+
+static int check_hole_in_region(BMesh *bm, BMFace *f) {
+ BMWalker regwalker;
+ BMIter liter2;
+ BMLoop *l2, *l3;
+ BMFace *f2;
+
+ /*checks if there are any unmarked boundary edges in the face region*/
+
+ BMW_Init(&regwalker, bm, BMW_ISLAND, FACE_MARK, 0);
+ f2 = BMW_Begin(&regwalker, f);
+ for (; f2; f2=BMW_Step(&regwalker)) {
+ l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_FACE, f2);
+ for (; l2; l2=BMIter_Step(&liter2)) {
+ l3 = bmesh_radial_nextloop(l2);
+ if (BMO_TestFlag(bm, l3->f, FACE_MARK)
+ != BMO_TestFlag(bm, l2->f, FACE_MARK))
+ {
+ if (!BMO_TestFlag(bm, l2->e, EDGE_MARK)) {
+ return 0;
+ }
+ }
+ }
+ }
+ BMW_End(&regwalker);
+
+ return 1;
+}
+
+void dissolvefaces_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter oiter;
+ BMIter liter, liter2, liter3;
+ BMLoop *l, *l2, *l3;
+ BMFace *f, *f2, *nf = NULL;
+ BLI_array_declare(region);
+ BLI_array_declare(regions);
+ BMLoop ***regions = NULL;
+ BMLoop **region = NULL;
+ BMWalker regwalker;
+ int i, j, fcopied;
+
+ BMO_Flag_Buffer(bm, op, "faces", FACE_MARK, BM_FACE);
+
+ /*collect regions*/
+ f = BMO_IterNew(&oiter, bm, op, "faces", BM_FACE);
+ for (; f; f=BMO_IterStep(&oiter)) {
+ if (!BMO_TestFlag(bm, f, FACE_MARK)) continue;
+
+ BLI_array_empty(region);
+ region = NULL; /*forces different allocation*/
+
+ /*yay, walk!*/
+ BMW_Init(&regwalker, bm, BMW_ISLAND, FACE_MARK, 0);
+ f2 = BMW_Begin(&regwalker, f);
+ for (; f2; f2=BMW_Step(&regwalker)) {
+ l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_FACE, f2);
+ for (; l2; l2=BMIter_Step(&liter2)) {
+ l3 = BMIter_New(&liter3, bm, BM_LOOPS_OF_LOOP, l2);
+ for (; l3; l3=BMIter_Step(&liter3)) {
+ if (!BMO_TestFlag(bm, l3->f, FACE_MARK)) {
+ BLI_array_growone(region);
+ region[BLI_array_count(region)-1] = l2;
+ break;
+ }
+ }
+ if (bmesh_radial_nextloop(l2) == l2) {
+ BLI_array_growone(region);
+ region[BLI_array_count(region)-1] = l2;
+ }
+ }
+ }
+ BMW_End(&regwalker);
+
+ BMW_Init(&regwalker, bm, BMW_ISLAND, FACE_MARK, 0);
+ f2 = BMW_Begin(&regwalker, f);
+ for (; f2; f2=BMW_Step(&regwalker)) {
+ BMO_ClearFlag(bm, f2, FACE_MARK);
+ BMO_SetFlag(bm, f2, FACE_ORIG);
+ }
+
+ BMW_End(&regwalker);
+
+ if (BMO_HasError(bm)) {
+ BMO_ClearStack(bm);
+ BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED, NULL);
+ goto cleanup;
+ }
+
+ BLI_array_growone(region);
+ BLI_array_growone(regions);
+ regions[BLI_array_count(regions)-1] = region;
+ region[BLI_array_count(region)-1] = NULL;
+ }
+
+ for (i=0; i<BLI_array_count(regions); i++) {
+ BMEdge **edges = NULL;
+ BLI_array_declare(edges);
+
+ region = regions[i];
+ for (j=0; region[j]; j++) {
+ BLI_array_growone(edges);
+ edges[BLI_array_count(edges)-1] = region[j]->e;
+ }
+
+ if (!region[0]) {
+ BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED,
+ "Could not find boundary of dissolve region");
+ goto cleanup;
+ }
+
+ if (region[0]->e->v1 == region[0]->v)
+ f= BM_Make_Ngon(bm, region[0]->e->v1, region[0]->e->v2, edges, j, 1);
+ else
+ f= BM_Make_Ngon(bm, region[0]->e->v2, region[0]->e->v1, edges, j, 1);
+
+ BLI_array_free(edges);
+
+ if (!f) {
+ BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED,
+ "Could not create merged face");
+ goto cleanup;
+ }
+
+ /*if making the new face failed (e.g. overlapping test)
+ unmark the original faces for deletion.*/
+ BMO_ClearFlag(bm, f, FACE_ORIG);
+ BMO_SetFlag(bm, f, FACE_NEW);
+
+ fcopied = 0;
+ l=BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (; l; l=BMIter_Step(&liter)) {
+ /*ensure winding is identical*/
+ l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_LOOP, l);
+ for (; l2; l2=BMIter_Step(&liter2)) {
+ if (BMO_TestFlag(bm, l2->f, FACE_ORIG)) {
+ if (l2->v != l->v)
+ bmesh_loop_reverse(bm, l2->f);
+ break;
+ }
+ }
+
+ /*copy over attributes*/
+ l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_LOOP, l);
+ for (; l2; l2=BMIter_Step(&liter2)) {
+ if (BMO_TestFlag(bm, l2->f, FACE_ORIG)) {
+ if (!fcopied) {
+ BM_Copy_Attributes(bm, bm, l2->f, f);
+ fcopied = 1;
+ }
+ BM_Copy_Attributes(bm, bm, l2, l);
+ break;
+ }
+ }
+ }
+ }
+
+ BMO_CallOpf(bm, "del geom=%ff context=%d", FACE_ORIG, DEL_FACES);
+ if (BMO_HasError(bm)) goto cleanup;
+
+ BMO_Flag_To_Slot(bm, op, "regionout", FACE_NEW, BM_FACE);
+
+cleanup:
+ /*free/cleanup*/
+ for (i=0; i<BLI_array_count(regions); i++) {
+ if (regions[i]) MEM_freeN(regions[i]);
+ }
+
+ BLI_array_free(regions);
+}
+
+/*almost identical to dissolve edge, except it cleans up vertices*/
+void dissolve_edgeloop_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator fop;
+ BMOIter oiter;
+ BMIter iter;
+ BMVert *v, **verts = NULL;
+ BLI_array_declare(verts);
+ BMEdge *e;
+ BMFace *f;
+ int i;
+
+ BMO_ITER(e, &oiter, bm, op, "edges", BM_EDGE) {
+ if (BM_Edge_FaceCount(e) == 2) {
+ BMO_SetFlag(bm, e->v1, VERT_MARK);
+ BMO_SetFlag(bm, e->v2, VERT_MARK);
+
+ BM_Join_TwoFaces(bm, e->l->f,
+ ((BMLoop*)e->l->radial_next)->f,
+ e);
+ }
+ }
+
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMO_TestFlag(bm, v, VERT_MARK) &&
+ BM_Vert_EdgeCount(v) == 2)
+ {
+ BLI_array_growone(verts);
+ verts[BLI_array_count(verts)-1] = v;
+ }
+ }
+
+ /*clean up extreneous 2-valence vertices*/
+ for (i=0; i<BLI_array_count(verts); i++) {
+ if (verts[i]->e)
+ BM_Collapse_Vert(bm, verts[i]->e, verts[i], 1.0);
+ }
+
+ BLI_array_free(verts);
+
+ //BMO_InitOpf(bm, &fop, "dissolvefaces faces=%ff", FACE_MARK);
+ //BMO_Exec_Op(bm, &fop);
+
+ //BMO_CopySlot(op, &fop, "regionout", "regionout");
+
+ //BMO_Finish_Op(bm, &fop);
+}
+
+
+void dissolveedges_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator fop;
+ BMOIter oiter;
+ BMIter iter;
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+ int i;
+
+ BMO_ITER(e, &oiter, bm, op, "edges", BM_EDGE) {
+ if (BM_Edge_FaceCount(e) == 2) {
+ BM_Join_TwoFaces(bm, e->l->f,
+ ((BMLoop*)e->l->radial_next)->f,
+ e);
+ }
+ }
+}
+
+static int test_extra_verts(BMesh *bm, BMVert *v)
+{
+ BMIter iter, liter, iter2, iter3;
+ BMFace *f, *f2;
+ BMLoop *l;
+ BMEdge *e;
+ int found;
+
+ /*test faces around verts for verts that would be wronly killed
+ by dissolve faces.*/
+ f = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v);
+ for (; f; f=BMIter_Step(&iter)) {
+ l=BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (; l; l=BMIter_Step(&liter)) {
+ if (!BMO_TestFlag(bm, l->v, VERT_MARK)) {
+ /*if an edge around a vert is a boundary edge,
+ then dissolve faces won't destroy it.
+ also if it forms a boundary with one
+ of the face regions*/
+ found = 0;
+ e = BMIter_New(&iter2, bm, BM_EDGES_OF_VERT, l->v);
+ for (; e; e=BMIter_Step(&iter2)) {
+ if (BM_Edge_FaceCount(e)==1) found = 1;
+ f2 = BMIter_New(&iter3, bm, BM_FACES_OF_EDGE, e);
+ for (; f2; f2=BMIter_Step(&iter3)) {
+ if (!BMO_TestFlag(bm, f2, FACE_MARK)) {
+ found = 1;
+ break;
+ }
+ }
+ if (found) break;
+ }
+ if (!found) return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+void dissolveverts_exec(BMesh *bm, BMOperator *op)
+{
+ BMOpSlot *vinput;
+ BMIter iter, fiter;
+ BMVert *v;
+ BMFace *f;
+ int i;
+
+ vinput = BMO_GetSlot(op, "verts");
+ BMO_Flag_Buffer(bm, op, "verts", VERT_MARK, BM_VERT);
+
+ for (v=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v=BMIter_Step(&iter)) {
+ if (BMO_TestFlag(bm, v, VERT_MARK)) {
+ /*check if it's a two-valence vert*/
+ if (BM_Vert_EdgeCount(v) == 2) {
+
+ /*collapse the vert*/
+ BM_Collapse_Vert(bm, v->e, v, 0.5f);
+ continue;
+ }
+
+ f=BMIter_New(&fiter, bm, BM_FACES_OF_VERT, v);
+ for (; f; f=BMIter_Step(&fiter)) {
+ BMO_SetFlag(bm, f, FACE_ORIG);
+ BMO_SetFlag(bm, f, FACE_MARK);
+ }
+
+ /*check if our additions to the input to face dissolve
+ will destroy nonmarked vertices.*/
+ if (!test_extra_verts(bm, v)) {
+ f=BMIter_New(&fiter, bm, BM_FACES_OF_VERT, v);
+ for (; f; f=BMIter_Step(&fiter)) {
+ if (BMO_TestFlag(bm, f, FACE_ORIG)) {
+ BMO_ClearFlag(bm, f, FACE_MARK);
+ BMO_ClearFlag(bm, f, FACE_ORIG);
+ }
+ }
+ } else {
+ f=BMIter_New(&fiter, bm, BM_FACES_OF_VERT, v);
+ for (; f; f=BMIter_Step(&fiter)) {
+ BMO_ClearFlag(bm, f, FACE_ORIG);
+ }
+ }
+ }
+ }
+
+ BMO_CallOpf(bm, "dissolvefaces faces=%ff", FACE_MARK);
+ if (BMO_HasError(bm)) {
+ char *msg;
+
+ BMO_GetError(bm, &msg, NULL);
+ BMO_ClearStack(bm);
+ BMO_RaiseError(bm, op, BMERR_DISSOLVEVERTS_FAILED,msg);
+ }
+
+ /*clean up any remaining*/
+ for (v=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v=BMIter_Step(&iter)) {
+ if (BMO_TestFlag(bm, v, VERT_MARK)) {
+ if (!BM_Dissolve_Vert(bm, v)) {
+ BMO_RaiseError(bm, op,
+ BMERR_DISSOLVEVERTS_FAILED, NULL);
+ return;
+ }
+ }
+ }
+
+}
+
+/*this code is for cleaning up two-edged faces, it shall become
+ it's own function one day.*/
+#if 0
+ /*clean up two-edged faces*/
+ /*basic idea is to keep joining 2-edged faces until their
+ gone. this however relies on joining two 2-edged faces
+ together to work, which doesn't.*/
+ found3 = 1;
+ while (found3) {
+ found3 = 0;
+ for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); f; f=BMIter_Step(&iter)){
+ if (!BM_Validate_Face(bm, f, stderr)) {
+ printf("error.\n");
+ }
+
+ if (f->len == 2) {
+ //this design relies on join faces working
+ //with two-edged faces properly.
+ //commenting this line disables the
+ //outermost loop.
+ //found3 = 1;
+ found2 = 0;
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ fe = l->e;
+ for (; l; l=BMIter_Step(&liter)) {
+ f2 = BMIter_New(&fiter, bm,
+ BM_FACES_OF_EDGE, l->e);
+ for (; f2; f2=BMIter_Step(&fiter)) {
+ if (f2 != f) {
+ BM_Join_TwoFaces(bm, f, f2, l->e);
+ found2 = 1;
+ break;
+ }
+ }
+ if (found2) break;
+ }
+
+ if (!found2) {
+ bmesh_kf(bm, f);
+ bmesh_ke(bm, fe);
+ }
+ } /*else if (f->len == 3) {
+ BMEdge *ed[3];
+ BMVert *vt[3];
+ BMLoop *lp[3];
+ int i=0;
+
+ //check for duplicate edges
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (; l; l=BMIter_Step(&liter)) {
+ ed[i] = l->e;
+ lp[i] = l;
+ vt[i++] = l->v;
+ }
+ if (vt[0] == vt[1] || vt[0] == vt[2]) {
+ i += 1;
+ }
+ }*/
+ }
+ }
+ if (oldlen == len) break;
+ oldlen = len;
+
+#endif
diff --git a/source/blender/bmesh/operators/edgesplitop.c b/source/blender/bmesh/operators/edgesplitop.c
new file mode 100644
index 00000000000..41d407abc4b
--- /dev/null
+++ b/source/blender/bmesh/operators/edgesplitop.c
@@ -0,0 +1,360 @@
+/**
+ * $Id:
+ *
+ * ***** 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
+
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
+#include "BLI_array.h"
+
+#include "DNA_object_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "ED_mesh.h"
+
+#include "bmesh.h"
+#include "mesh_intern.h"
+#include "subdivideop.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+typedef struct EdgeTag {
+ BMVert *newv1, *newv2;
+ BMEdge *newe1, *newe2;
+ int tag;
+} EdgeTag;
+
+#define EDGE_SEAM 1
+#define EDGE_DEL 2
+#define EDGE_MARK 4
+#define EDGE_RET1 8
+#define EDGE_RET2 16
+
+#define FACE_DEL 1
+#define FACE_NEW 2
+
+static BMFace *remake_face(BMesh *bm, EdgeTag *etags, BMFace *f, BMVert **verts)
+{
+ BMIter liter1, liter2;
+ EdgeTag *et;
+ BMFace *f2;
+ BMLoop *l, *l2;
+ BMEdge **edges = (BMEdge**) verts; /*he he, can reuse this, sneaky! ;)*/
+ BMVert *lastv1, *lastv2, *v1, *v2;
+ int i;
+
+ /*we do final edge last*/
+ lastv1 = verts[f->len-1];
+ lastv2 = verts[0];
+ v1 = verts[0];
+ v2 = verts[1];
+ for (i=0; i<f->len-1; i++) {
+ edges[i] = BM_Make_Edge(bm, verts[i], verts[i+1], NULL, 1);
+
+ if (!edges[i])
+ return NULL;
+ }
+
+ edges[i] = BM_Make_Edge(bm, lastv1, lastv2, NULL, 1);
+
+ f2 = BM_Make_Ngon(bm, v1, v2, edges, f->len, 0);
+ if (!f2)
+ return NULL;
+
+ BM_Copy_Attributes(bm, bm, f, f2);
+
+ l = BMIter_New(&liter1, bm, BM_LOOPS_OF_FACE, f);
+ l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_FACE, f2);
+ for (; l && l2; l=BMIter_Step(&liter1), l2=BMIter_Step(&liter2)) {
+ BM_Copy_Attributes(bm, bm, l, l2);
+ if (l->e != l2->e) {
+ /*set up data for figuring out the two sides of
+ the splits*/
+ BMINDEX_SET(l2->e, BMINDEX_GET(l->e));
+ et = etags + BMINDEX_GET(l->e);
+
+ if (!et->newe1) et->newe1 = l2->e;
+ else et->newe2 = l2->e;
+
+ if (BMO_TestFlag(bm, l->e, EDGE_SEAM))
+ BMO_SetFlag(bm, l2->e, EDGE_SEAM);
+
+ BM_Copy_Attributes(bm, bm, l->e, l2->e);
+ }
+
+ BMO_SetFlag(bm, l->e, EDGE_MARK);
+ BMO_SetFlag(bm, l2->e, EDGE_MARK);
+ }
+
+ return f2;
+}
+
+void tag_out_edges(BMesh *bm, EdgeTag *etags, BMOperator *op)
+{
+ EdgeTag *et;
+ BMIter iter;
+ BMLoop *l, *startl;
+ BMEdge *e;
+ BMVert *v;
+ int i, ok;
+
+ ok=0;
+ while (ok++ < 100000) {
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BMO_TestFlag(bm, e, EDGE_SEAM))
+ continue;
+
+ et = etags + BMINDEX_GET(e);
+ if (!et->tag && e->l) {
+ break;
+ }
+ }
+
+ if (!e)
+ break;
+
+ /*ok we found an edge, part of a region of splits we need
+ to identify. now walk along it.*/
+ for (i=0; i<2; i++) {
+ l = e->l;
+
+ v = i ? ((BMLoop*)l->next)->v : l->v;
+
+ while (1) {
+ et = etags + BMINDEX_GET(l->e);
+ if (et->newe1 == l->e) {
+ if (et->newe1) {
+ BMO_SetFlag(bm, et->newe1, EDGE_RET1);
+ BMO_ClearFlag(bm, et->newe1, EDGE_SEAM);
+ }
+ if (et->newe2) {
+ BMO_SetFlag(bm, et->newe2, EDGE_RET2);
+ BMO_ClearFlag(bm, et->newe2, EDGE_SEAM);
+ }
+ } else {
+ if (et->newe1) {
+ BMO_SetFlag(bm, et->newe1, EDGE_RET2);
+ BMO_ClearFlag(bm, et->newe1, EDGE_SEAM);
+ }
+ if (et->newe2) {
+ BMO_SetFlag(bm, et->newe2, EDGE_RET1);
+ BMO_ClearFlag(bm, et->newe2, EDGE_SEAM);
+ }
+ }
+
+ startl = l;
+ do {
+ l = BM_OtherFaceLoop(l->e, l->f, v);
+ if (BM_Edge_FaceCount(l->e) != 2)
+ break;
+ l = (BMLoop*) l->radial_next;
+ } while (l != startl && !BMO_TestFlag(bm, l->e, EDGE_SEAM));
+
+ if (l == startl || !BMO_TestFlag(bm, l->e, EDGE_SEAM))
+ break;
+
+ if (l->v == v) {
+ v = ((BMLoop*)l->next)->v;
+ } else v = l->v;
+ }
+ }
+ }
+}
+
+void bmesh_edgesplitop_exec(BMesh *bm, BMOperator *op)
+{
+ EdgeTag *etags, *et;
+ BMIter iter, liter;
+ BMOIter siter;
+ BMFace *f, *f2;
+ BMLoop *l, *nextl, *prevl, *l2, *l3;
+ BMEdge *e, *e2;
+ BLI_array_declare(verts);
+ BMVert *v, *v2, **verts = NULL;
+ int i, j;
+
+ BMO_Flag_Buffer(bm, op, "edges", EDGE_SEAM, BM_EDGE);
+
+ /*single marked edges unconnected to any other marked edges
+ are illegal, go through and unmark them*/
+ BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
+ for (i=0; i<2; i++) {
+ BM_ITER(e2, &iter, bm, BM_EDGES_OF_VERT, i ? e->v2 : e->v1) {
+ if (e != e2 && BMO_TestFlag(bm, e2, EDGE_SEAM))
+ break;
+ }
+ if (e2)
+ break;
+ }
+ if (!e2)
+ BMO_ClearFlag(bm, e, EDGE_SEAM);
+ }
+
+ etags = MEM_callocN(sizeof(EdgeTag)*bm->totedge, "EdgeTag");
+
+ i = 0;
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ BMINDEX_SET(e, i);
+ i++;
+ }
+
+#ifdef ETV
+#undef ETV
+#endif
+#ifdef SETETV
+#undef SETETV
+#endif
+
+#define ETV(et, v, l) (l->e->v1 == v ? et->newv1 : et->newv2)
+#define SETETV(et, v, l, vs) l->e->v1 == v ? (et->newv1 = vs) : (et->newv2 = vs)
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (BMO_TestFlag(bm, f, FACE_NEW))
+ continue;
+
+ BLI_array_empty(verts);
+ BLI_array_growitems(verts, f->len);
+ memset(verts, 0, sizeof(BMVert*)*f->len);
+
+ i = 0;
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ if (!BMO_TestFlag(bm, l->e, EDGE_SEAM)) {
+ if (!verts[i]) {
+ et = etags + BMINDEX_GET(l->e);
+ if (ETV(et, l->v, l))
+ verts[i] = ETV(et, l->v, l);
+ else verts[i] = l->v;
+ }
+ i++;
+ continue;
+ }
+
+ BMO_SetFlag(bm, l->e, EDGE_DEL);
+
+ nextl = (BMLoop*) l->next;
+ prevl = (BMLoop*) l->prev;
+
+ for (j=0; j<2; j++) {
+ l2 = j ? nextl : prevl;
+ v = j ? l2->v : l->v;
+
+ if (BMO_TestFlag(bm, l2->e, EDGE_SEAM)) {
+ if (!verts[j ? (i+1) % f->len : i]) {
+ /*make unique vert here for this face only*/
+ v2 = BM_Make_Vert(bm, v->co, NULL);
+ copy_v3_v3(v2->no, v->no);
+ BM_Copy_Attributes(bm, bm, v, v2);
+
+ verts[j ? (i+1) % f->len : i] = v2;
+ } else v2 = verts[j ? (i+1) % f->len : i];
+ } else {
+ /*generate unique vert for non-seam edge(s)
+ around the manifold vert fan if necassary*/
+
+ /*first check that we have two seam edges
+ somewhere within this fan*/
+ l3 = l2;
+ do {
+ if (BM_Edge_FaceCount(l3->e) != 2) {
+ /*if we hit a boundary edge, tag
+ l3 as null so we know to disconnect
+ it*/
+ if (BM_Edge_FaceCount(l3->e) == 1)
+ l3 = NULL;
+ break;
+ }
+
+ l3 = (BMLoop*)l3->radial_next;
+ l3 = BM_OtherFaceLoop(l3->e, l3->f, v);
+ } while (l3 != l2 && !BMO_TestFlag(bm, l3->e, EDGE_SEAM));
+
+ if (l3 == NULL || (BMO_TestFlag(bm, l3->e, EDGE_SEAM) && l3->e != l->e)) {
+ et = etags + BMINDEX_GET(l2->e);
+ if (ETV(et, v, l2) == NULL) {
+ v2 = BM_Make_Vert(bm, v->co, NULL);
+ copy_v3_v3(v2->no, v->no);
+ BM_Copy_Attributes(bm, bm, v, v2);
+
+ l3 = l2;
+ do {
+ SETETV(et, v, l3, v2);
+ if (BM_Edge_FaceCount(l3->e) != 2)
+ break;
+
+ l3 = (BMLoop*)l3->radial_next;
+ l3 = BM_OtherFaceLoop(l3->e, l3->f, v);
+
+ et = etags + BMINDEX_GET(l3->e);
+ } while (l3 != l2 && !BMO_TestFlag(bm, l3->e, EDGE_SEAM));
+ } else v2 = ETV(et, v, l2);
+
+ verts[j ? (i+1) % f->len : i] = v2;
+ } else verts[j ? (i+1) % f->len : i] = v;
+ }
+ }
+
+ i++;
+ }
+
+ f2 = remake_face(bm, etags, f, verts);
+ if (!f2)
+ continue;
+
+ BMO_SetFlag(bm, f, FACE_DEL);
+ BMO_SetFlag(bm, f2, FACE_NEW);
+ }
+
+ BMO_CallOpf(bm, "del geom=%ff context=%i", FACE_DEL, DEL_ONLYFACES);
+
+ /*test EDGE_MARK'd edges if we need to delete them, EDGE_MARK
+ is set in remake_face*/
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (BMO_TestFlag(bm, e, EDGE_MARK)) {
+ if (!e->l)
+ BMO_SetFlag(bm, e, EDGE_DEL);
+ }
+ }
+
+ BMO_CallOpf(bm, "del geom=%fe context=%i", EDGE_DEL, DEL_EDGES);
+
+ tag_out_edges(bm, etags, op);
+ BMO_Flag_To_Slot(bm, op, "edgeout1", EDGE_RET1, BM_EDGE);
+ BMO_Flag_To_Slot(bm, op, "edgeout2", EDGE_RET2, BM_EDGE);
+
+ BLI_array_free(verts);
+ if (etags) MEM_freeN(etags);
+}
+
+#undef ETV
+#undef SETETV
diff --git a/source/blender/bmesh/operators/extrudeops.c b/source/blender/bmesh/operators/extrudeops.c
new file mode 100644
index 00000000000..5bd86eeb00e
--- /dev/null
+++ b/source/blender/bmesh/operators/extrudeops.c
@@ -0,0 +1,311 @@
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_array.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+#include "bmesh_operators_private.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define EXT_INPUT 1
+#define EXT_KEEP 2
+#define EXT_DEL 4
+
+void bmesh_extrude_face_indiv_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMIter liter, liter2;
+ BMFace *f, *f2, *f3;
+ BMLoop *l, *l2, *l3, *l4;
+ BMEdge **edges = NULL, *e, *laste;
+ BMVert *v, *lastv, *firstv;
+ BLI_array_declare(edges);
+ int i;
+
+ BMO_ITER(f, &siter, bm, op, "faces", BM_FACE) {
+ BLI_array_empty(edges);
+ i = 0;
+ firstv = lastv = NULL;
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ BLI_array_growone(edges);
+
+ v = BM_Make_Vert(bm, l->v->co, NULL);
+ BM_Copy_Attributes(bm, bm, l->v, v);
+
+ if (lastv) {
+ e = BM_Make_Edge(bm, lastv, v, l->e, 0);
+ edges[i++] = e;
+ }
+
+ lastv = v;
+ laste = l->e;
+ if (!firstv) firstv = v;
+ }
+
+ BLI_array_growone(edges);
+ e = BM_Make_Edge(bm, v, firstv, laste, 0);
+ edges[i++] = e;
+
+ BMO_SetFlag(bm, f, EXT_DEL);
+
+ f2 = BM_Make_Ngon(bm, edges[0]->v1, edges[0]->v2, edges, f->len, 0);
+ BMO_SetFlag(bm, f2, EXT_KEEP);
+ BM_Copy_Attributes(bm, bm, f, f2);
+
+ l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_FACE, f2);
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ BM_Copy_Attributes(bm, bm, l, l2);
+ l3 = l->next;
+ l4 = l2->next;
+
+ f3 = BM_Make_QuadTri(bm, l3->v, l4->v, l2->v, l->v, f, 0);
+
+ BM_Copy_Attributes(bm, bm, l->next, bm_firstfaceloop(f3));
+ BM_Copy_Attributes(bm, bm, l->next, bm_firstfaceloop(f3)->next);
+ BM_Copy_Attributes(bm, bm, l, bm_firstfaceloop(f3)->next->next);
+ BM_Copy_Attributes(bm, bm, l, bm_firstfaceloop(f3)->next->next->next);
+
+ l2 = BMIter_Step(&liter2);
+ }
+ }
+
+ BMO_CallOpf(bm, "del geom=%ff context=%d", EXT_DEL, DEL_ONLYFACES);
+
+ BMO_Flag_To_Slot(bm, op, "faceout", EXT_KEEP, BM_FACE);
+}
+
+void bmesh_extrude_onlyedge_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMOperator dupeop;
+ BMVert *v1, *v2, *v3, *v4;
+ BMEdge *e, *e2;
+ BMFace *f;
+
+ BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
+ BMO_SetFlag(bm, e, EXT_INPUT);
+ BMO_SetFlag(bm, e->v1, EXT_INPUT);
+ BMO_SetFlag(bm, e->v2, EXT_INPUT);
+ }
+
+ BMO_InitOpf(bm, &dupeop, "dupe geom=%fve", EXT_INPUT);
+ BMO_Exec_Op(bm, &dupeop);
+
+ e = BMO_IterNew(&siter, bm, &dupeop, "boundarymap", 0);
+ for (; e; e=BMO_IterStep(&siter)) {
+ e2 = BMO_IterMapVal(&siter);
+ e2 = *(BMEdge**)e2;
+
+ if (e->l && e->v1 != e->l->v) {
+ v1 = e->v1;
+ v2 = e->v2;
+ v3 = e2->v2;
+ v4 = e2->v1;
+ } else {
+ v1 = e2->v1;
+ v2 = e2->v2;
+ v3 = e->v2;
+ v4 = e->v1;
+ }
+ /*not sure what to do about example face, pass NULL for now.*/
+ f = BM_Make_QuadTri(bm, v1, v2, v3, v4, NULL, 0);
+
+ if (BMO_TestFlag(bm, e, EXT_INPUT))
+ e = e2;
+
+ BMO_SetFlag(bm, f, EXT_KEEP);
+ BMO_SetFlag(bm, e, EXT_KEEP);
+ BMO_SetFlag(bm, e->v1, EXT_KEEP);
+ BMO_SetFlag(bm, e->v2, EXT_KEEP);
+
+ }
+
+ BMO_Finish_Op(bm, &dupeop);
+
+ BMO_Flag_To_Slot(bm, op, "geomout", EXT_KEEP, BM_ALL);
+}
+
+void extrude_vert_indiv_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMVert *v, *dupev;
+ BMEdge *e;
+
+ v = BMO_IterNew(&siter, bm, op, "verts", BM_VERT);
+ for (; v; v=BMO_IterStep(&siter)) {
+ dupev = BM_Make_Vert(bm, v->co, NULL);
+ copy_v3_v3(dupev->no, v->no);
+ BM_Copy_Attributes(bm, bm, v, dupev);
+
+ e = BM_Make_Edge(bm, v, dupev, NULL, 0);
+
+ BMO_SetFlag(bm, e, EXT_KEEP);
+ BMO_SetFlag(bm, dupev, EXT_KEEP);
+ }
+
+ BMO_Flag_To_Slot(bm, op, "vertout", EXT_KEEP, BM_VERT);
+ BMO_Flag_To_Slot(bm, op, "edgeout", EXT_KEEP, BM_EDGE);
+}
+
+void extrude_edge_context_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator dupeop, delop;
+ BMOIter siter;
+ BMIter iter, fiter, viter;
+ BMEdge *e, *newedge, *e2, *ce;
+ BMLoop *l, *l2;
+ BMVert *verts[4], *v, *v2;
+ BMFace *f;
+ int rlen, found, delorig=0, i;
+
+ /*initialize our sub-operators*/
+ BMO_Init_Op(&dupeop, "dupe");
+
+ BMO_Flag_Buffer(bm, op, "edgefacein", EXT_INPUT, BM_EDGE|BM_FACE);
+
+ /*if one flagged face is bordered by an unflagged face, then we delete
+ original geometry.*/
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BMO_TestFlag(bm, e, EXT_INPUT)) continue;
+
+ found = 0;
+ f = BMIter_New(&fiter, bm, BM_FACES_OF_EDGE, e);
+ for (rlen=0; f; f=BMIter_Step(&fiter), rlen++) {
+ if (!BMO_TestFlag(bm, f, EXT_INPUT)) {
+ found = 1;
+ delorig = 1;
+ break;
+ }
+ }
+
+ if (!found && (rlen > 1)) BMO_SetFlag(bm, e, EXT_DEL);
+ }
+
+ /*calculate verts to delete*/
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ found = 0;
+
+ BM_ITER(e, &viter, bm, BM_EDGES_OF_VERT, v) {
+ if (!BMO_TestFlag(bm, e, EXT_INPUT)) {
+ found = 1;
+ break;
+ }
+ }
+
+ BM_ITER(f, &viter, bm, BM_FACES_OF_VERT, v) {
+ if (!BMO_TestFlag(bm, f, EXT_INPUT)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ BMO_SetFlag(bm, v, EXT_DEL);
+ }
+ }
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (BMO_TestFlag(bm, f, EXT_INPUT))
+ BMO_SetFlag(bm, f, EXT_DEL);
+ }
+ if (delorig) BMO_InitOpf(bm, &delop, "del geom=%fvef context=%d",
+ EXT_DEL, DEL_ONLYTAGGED);
+
+ BMO_CopySlot(op, &dupeop, "edgefacein", "geom");
+ BMO_Exec_Op(bm, &dupeop);
+
+ if (bm->act_face && BMO_TestFlag(bm, bm->act_face, EXT_INPUT))
+ bm->act_face = BMO_Get_MapPointer(bm, &dupeop, "facemap", bm->act_face);
+
+ if (delorig) BMO_Exec_Op(bm, &delop);
+
+ /*if not delorig, reverse loops of original faces*/
+ if (!delorig) {
+ for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); f; f=BMIter_Step(&iter)) {
+ if (BMO_TestFlag(bm, f, EXT_INPUT)) {
+ BM_flip_normal(bm, f);
+ }
+ }
+ }
+
+ BMO_CopySlot(&dupeop, op, "newout", "geomout");
+ e = BMO_IterNew(&siter, bm, &dupeop, "boundarymap", 0);
+ for (; e; e=BMO_IterStep(&siter)) {
+ if (BMO_InMap(bm, op, "exclude", e)) continue;
+
+ newedge = BMO_IterMapVal(&siter);
+ newedge = *(BMEdge**)newedge;
+ if (!newedge) continue;
+ if (!newedge->l) ce = e;
+ else ce = newedge;
+
+ if (ce->l && (ce->l->v == ce->v1)) {
+ verts[0] = e->v1;
+ verts[1] = e->v2;
+ verts[2] = newedge->v2;
+ verts[3] = newedge->v1;
+ } else {
+ verts[3] = e->v1;
+ verts[2] = e->v2;
+ verts[1] = newedge->v2;
+ verts[0] = newedge->v1;
+ }
+
+ /*not sure what to do about example face, pass NULL for now.*/
+ f = BM_Make_Quadtriangle(bm, verts, NULL, 4, NULL, 0);
+
+ /*copy attributes*/
+ l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f);
+ for (; l; l=BMIter_Step(&iter)) {
+ if (l->e != e && l->e != newedge) continue;
+ l2 = l->radial_next;
+
+ if (l2 == l) {
+ l2 = newedge->l;
+ BM_Copy_Attributes(bm, bm, l2->f, l->f);
+
+ BM_Copy_Attributes(bm, bm, l2, l);
+ l2 = (BMLoop*) l2->next;
+ l = (BMLoop*) l->next;
+ BM_Copy_Attributes(bm, bm, l2, l);
+ } else {
+ BM_Copy_Attributes(bm, bm, l2->f, l->f);
+
+ /*copy data*/
+ if (l2->v == l->v) {
+ BM_Copy_Attributes(bm, bm, l2, l);
+ l2 = (BMLoop*) l2->next;
+ l = (BMLoop*) l->next;
+ BM_Copy_Attributes(bm, bm, l2, l);
+ } else {
+ l2 = (BMLoop*) l2->next;
+ BM_Copy_Attributes(bm, bm, l2, l);
+ l2 = (BMLoop*) l2->prev;
+ l = (BMLoop*) l->next;
+ BM_Copy_Attributes(bm, bm, l2, l);
+ }
+ }
+ }
+ }
+
+ /*link isolated verts*/
+ v = BMO_IterNew(&siter, bm, &dupeop, "isovertmap", 0);
+ for (; v; v=BMO_IterStep(&siter)) {
+ v2 = *((void**)BMO_IterMapVal(&siter));
+ BM_Make_Edge(bm, v, v2, v->e, 1);
+ }
+
+ /*cleanup*/
+ if (delorig) BMO_Finish_Op(bm, &delop);
+ BMO_Finish_Op(bm, &dupeop);
+}
diff --git a/source/blender/bmesh/operators/join_triangles.c b/source/blender/bmesh/operators/join_triangles.c
new file mode 100644
index 00000000000..5b322489515
--- /dev/null
+++ b/source/blender/bmesh/operators/join_triangles.c
@@ -0,0 +1,358 @@
+#if 1
+#include "MEM_guardedalloc.h"
+#include "BKE_customdata.h"
+#include "DNA_listBase.h"
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include <string.h>
+#include "BKE_utildefines.h"
+#include "BKE_mesh.h"
+#include "BKE_global.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
+
+#include "BLI_editVert.h"
+#include "mesh_intern.h"
+#include "ED_mesh.h"
+
+#include "BLI_math.h"
+#include "BLI_array.h"
+#include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
+
+#include "BLI_heap.h"
+
+#include "bmesh.h"
+
+/*
+ * JOIN_TRIANGLES.C
+ *
+ * utility bmesh operators, e.g. transform,
+ * translate, rotate, scale, etc.
+ *
+*/
+
+/*Bitflags for edges.*/
+#define T2QDELETE 1
+#define T2QCOMPLEX 2
+#define T2QJOIN 4
+
+/*assumes edges are validated before reaching this point*/
+static float measure_facepair(BMesh *bm, BMVert *v1, BMVert *v2,
+ BMVert *v3, BMVert *v4, float limit)
+{
+ /*gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would make*/
+ /*Note: this is more complicated than it needs to be and should be cleaned up...*/
+ float n1[3], n2[3], measure = 0.0f, angle1, angle2, diff;
+ float edgeVec1[3], edgeVec2[3], edgeVec3[3], edgeVec4[3];
+ float minarea, maxarea, areaA, areaB;
+
+ /*First Test: Normal difference*/
+ normal_tri_v3(n1, v1->co, v2->co, v3->co);
+ normal_tri_v3(n2, v1->co, v3->co, v4->co);
+
+ if(n1[0] == n2[0] && n1[1] == n2[1] && n1[2] == n2[2]) angle1 = 0.0f;
+ else angle1 = angle_v3v3(n1, n2);
+
+ normal_tri_v3(n1, v2->co, v3->co, v4->co);
+ normal_tri_v3(n2, v4->co, v1->co, v2->co);
+
+ if(n1[0] == n2[0] && n1[1] == n2[1] && n1[2] == n2[2]) angle2 = 0.0f;
+ else angle2 = angle_v3v3(n1, n2);
+
+ measure += angle1 + angle2;
+ if(measure > limit) return measure;
+
+ /*Second test: Colinearity*/
+ sub_v3_v3v3(edgeVec1, v1->co, v2->co);
+ sub_v3_v3v3(edgeVec2, v2->co, v3->co);
+ sub_v3_v3v3(edgeVec3, v3->co, v4->co);
+ sub_v3_v3v3(edgeVec4, v4->co, v1->co);
+
+ diff = 0.0;
+
+ diff = (
+ fabs(angle_v3v3(edgeVec1, edgeVec2) - M_PI/2) +
+ fabs(angle_v3v3(edgeVec2, edgeVec3) - M_PI/2) +
+ fabs(angle_v3v3(edgeVec3, edgeVec4) - M_PI/2) +
+ fabs(angle_v3v3(edgeVec4, edgeVec1) - M_PI/2));
+ if(!diff) return 0.0;
+
+ measure += diff;
+ if(measure > limit) return measure;
+
+ /*Third test: Concavity*/
+ areaA = area_tri_v3(v1->co, v2->co, v3->co) + area_tri_v3(v1->co, v3->co, v4->co);
+ areaB = area_tri_v3(v2->co, v3->co, v4->co) + area_tri_v3(v4->co, v1->co, v2->co);
+
+ if(areaA <= areaB) minarea = areaA;
+ else minarea = areaB;
+
+ if(areaA >= areaB) maxarea = areaA;
+ else maxarea = areaB;
+
+ if(!maxarea) measure += 1;
+ else measure += (1 - (minarea / maxarea));
+
+ return measure;
+}
+
+#define T2QUV_LIMIT 0.005
+#define T2QCOL_LIMIT 3
+
+static int compareFaceAttribs(BMesh *bm, BMEdge *e, int douvs, int dovcols)
+{
+ MTexPoly *tp1, *tp2;
+ MLoopCol *lcol1, *lcol2, *lcol3, *lcol4;
+ MLoopUV *luv1, *luv2, *luv3, *luv4;
+ BMLoop *l1, *l2, *l3, *l4;
+ int mergeok_uvs=!douvs, mergeok_vcols=!dovcols;
+
+ l1 = e->l;
+ l3 = (BMLoop*)e->l->radial_next;
+
+ /*match up loops on each side of an edge corrusponding to each vert*/
+ if (l1->v == l3->v) {
+ l2 = (BMLoop*)l1->next;
+ l4 = (BMLoop*)l2->next;
+ } else {
+ l2 = (BMLoop*)l1->next;
+
+ l4 = l3;
+ l3 = (BMLoop*)l4->next;
+ }
+
+ lcol1 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPCOL);
+ lcol2 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPCOL);
+ lcol3 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPCOL);
+ lcol4 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPCOL);
+
+ luv1 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPUV);
+ luv2 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPUV);
+ luv3 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPUV);
+ luv4 = CustomData_bmesh_get(&bm->ldata, l1->head.data, CD_MLOOPUV);
+
+ tp1 = CustomData_bmesh_get(&bm->pdata, l1->f->head.data, CD_MTEXPOLY);
+ tp2 = CustomData_bmesh_get(&bm->pdata, l2->f->head.data, CD_MTEXPOLY);
+
+ if (!lcol1)
+ mergeok_vcols = 1;
+
+ if (!luv1)
+ mergeok_uvs = 1;
+
+ /*compare faceedges for each face attribute. Additional per face attributes can be added later*/
+
+ /*do VCOLs*/
+ if(lcol1 && dovcols){
+ char *cols[4] = {(char*)lcol1, (char*)lcol2, (char*)lcol3, (char*)lcol4};
+ int i;
+
+ for (i=0; i<3; i++) {
+ if (cols[0][i] + T2QCOL_LIMIT < cols[3][i] - T2QCOL_LIMIT)
+ break;
+ if (cols[1][i] + T2QCOL_LIMIT < cols[4][i] - T2QCOL_LIMIT)
+ break;
+ }
+
+ if (i == 3)
+ mergeok_vcols = 1;
+ }
+
+ /*do UVs*/
+ if (luv1 && douvs) {
+ if(tp1->tpage != tp2->tpage); /*do nothing*/
+ else {
+ int i;
+
+ for(i = 0; i < 2; i++) {
+ if(luv1->uv[0] + T2QUV_LIMIT > luv3->uv[0] && luv1->uv[0] - T2QUV_LIMIT < luv3->uv[0] &&
+ luv1->uv[1] + T2QUV_LIMIT > luv3->uv[1] && luv1->uv[1] - T2QUV_LIMIT < luv3->uv[1])
+ {
+ if(luv2->uv[0] + T2QUV_LIMIT > luv4->uv[0] && luv2->uv[0] - T2QUV_LIMIT < luv4->uv[0] &&
+ luv2->uv[1] + T2QUV_LIMIT > luv4->uv[1] && luv2->uv[1] - T2QUV_LIMIT < luv4->uv[1])
+ {
+ mergeok_uvs = 1;
+ }
+ }
+ }
+ }
+ }
+
+ if (douvs == mergeok_uvs && dovcols == mergeok_vcols)
+ return 1;
+ return 0;
+}
+
+typedef struct JoinEdge {
+ float weight;
+ BMEdge *e;
+} JoinEdge;
+
+#define EDGE_MARK 1
+#define EDGE_CHOSEN 2
+
+#define FACE_MARK 1
+#define FACE_INPUT 2
+
+static int fplcmp(const void *v1, const void *v2)
+{
+ const JoinEdge *e1= ((JoinEdge*)v1), *e2=((JoinEdge*)v2);
+
+ if( e1->weight > e2->weight) return 1;
+ else if( e1->weight < e2->weight) return -1;
+
+ return 0;
+}
+
+void bmesh_jointriangles_exec(BMesh *bm, BMOperator *op)
+{
+ BMIter iter, liter;
+ BMOIter siter;
+ BMFace *f1, *f2;
+ BMLoop *l;
+ BMEdge *e;
+ BLI_array_declare(jedges);
+ JoinEdge *jedges = NULL;
+ int dosharp = BMO_Get_Int(op, "compare_sharp"), douvs=BMO_Get_Int(op, "compare_uvs");
+ int dovcols = BMO_Get_Int(op, "compare_vcols"), domat=BMO_Get_Int(op, "compare_materials");
+ float limit = BMO_Get_Float(op, "limit")/180.0f*M_PI;
+ int i, totedge;
+
+ /*flag all edges of all input faces*/
+ BMO_ITER(f1, &siter, bm, op, "faces", BM_FACE) {
+ BMO_SetFlag(bm, f1, FACE_INPUT);
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f1) {
+ BMO_SetFlag(bm, l->e, EDGE_MARK);
+ }
+ }
+
+ /*unflag edges that are invalid; e.g. aren't surrounded by triangles*/
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BMO_TestFlag(bm, e, EDGE_MARK))
+ continue;
+
+ if (BM_Edge_FaceCount(e) < 2) {
+ BMO_ClearFlag(bm, e, EDGE_MARK);
+ continue;
+ }
+
+ f1 = e->l->f;
+ f2 = ((BMLoop*)e->l->radial_next)->f;
+
+ if (f1->len != 3 || f2->len != 3) {
+ BMO_ClearFlag(bm, e, EDGE_MARK);
+ continue;
+ }
+
+ if (!BMO_TestFlag(bm, f1, FACE_INPUT) || !BMO_TestFlag(bm, f2, FACE_INPUT)) {
+ BMO_ClearFlag(bm, e, EDGE_MARK);
+ continue;
+ }
+ }
+
+ i = 0;
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ BMVert *v1, *v2, *v3, *v4;
+ BMFace *f1, *f2;
+ float measure;
+
+ if (!BMO_TestFlag(bm, e, EDGE_MARK))
+ continue;
+
+ f1 = e->l->f;
+ f2 = ((BMLoop*)e->l->radial_next)->f;
+
+ v1 = e->l->v;
+ v2 = ((BMLoop*)e->l->prev)->v;
+ v3 = ((BMLoop*)e->l->next)->v;
+ v4 = ((BMLoop*)((BMLoop*)e->l->radial_next)->prev)->v;
+
+ if (dosharp && BM_TestHFlag(e, BM_SHARP))
+ continue;
+
+ if ((douvs || dovcols) && compareFaceAttribs(bm, e, douvs, dovcols))
+ continue;
+
+ if (domat && f1->mat_nr != f2->mat_nr)
+ continue;
+
+ measure = measure_facepair(bm, v1, v2, v3, v4, limit);
+ if(measure < limit) {
+ BLI_array_growone(jedges);
+
+ jedges[i].e = e;
+ jedges[i].weight = measure;
+
+ i++;
+ }
+ }
+
+ if (!jedges)
+ return;
+
+ qsort(jedges, BLI_array_count(jedges), sizeof(JoinEdge), fplcmp);
+
+ totedge = BLI_array_count(jedges);
+ for (i=0; i<totedge; i++) {
+ BMFace *f1, *f2;
+
+ e = jedges[i].e;
+ f1 = e->l->f;
+ f2 = ((BMLoop*)e->l->radial_next)->f;
+
+ if (BMO_TestFlag(bm, f1, FACE_MARK) || BMO_TestFlag(bm, f2, FACE_MARK))
+ continue;
+
+ BMO_SetFlag(bm, f1, FACE_MARK);
+ BMO_SetFlag(bm, f2, FACE_MARK);
+ BMO_SetFlag(bm, e, EDGE_CHOSEN);
+ }
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BMO_TestFlag(bm, e, EDGE_CHOSEN))
+ continue;
+
+ f1 = e->l->f;
+ f2 = ((BMLoop*)e->l->radial_next)->f;
+
+ BM_Join_TwoFaces(bm, f1, f2, e);
+ }
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (BMO_TestFlag(bm, e, EDGE_MARK)) {
+ /*ok, this edge wasn't merged, check if it's
+ in a 2-tri-pair island, and if so merge*/
+
+ f1 = e->l->f;
+ f2 = ((BMLoop*)e->l->radial_next)->f;
+
+ if (f1->len != 3 || f2->len != 3)
+ continue;
+
+ for (i=0; i<2; i++) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, i ? f2 : f1) {
+ if (l->e != e && BMO_TestFlag(bm, l->e, EDGE_MARK))
+ break;
+ }
+
+ /*if l isn't NULL, we broke out of the loop*/
+ if (l)
+ break;
+ }
+
+ /*if i isn't 2, we broke out of that loop*/
+ if (i != 2)
+ continue;
+
+ BM_Join_TwoFaces(bm, f1, f2, e);
+ }
+ }
+
+ BLI_array_free(jedges);
+}
+
+#endif
diff --git a/source/blender/bmesh/operators/mesh_conv.c b/source/blender/bmesh/operators/mesh_conv.c
new file mode 100644
index 00000000000..4cbb0b12b5c
--- /dev/null
+++ b/source/blender/bmesh/operators/mesh_conv.c
@@ -0,0 +1,754 @@
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_utildefines.h"
+#include "BKE_mesh.h"
+#include "BKE_global.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
+#include "BLI_editVert.h"
+#include "BLI_scanfill.h"
+#include "BLI_array.h"
+#include "BLI_utildefines.h"
+
+#include "ED_mesh.h"
+
+#include "mesh_intern.h"
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+/*
+ * MESH CONV.C
+ *
+ * This file contains functions
+ * for converting a Mesh
+ * into a Bmesh, and back again.
+ *
+*/
+
+void mesh_to_bmesh_exec(BMesh *bm, BMOperator *op) {
+ Object *ob = BMO_Get_Pnt(op, "object");
+ Mesh *me = BMO_Get_Pnt(op, "mesh");
+ MVert *mvert, **verts = NULL;
+ BLI_array_declare(verts);
+ MEdge *medge;
+ MLoop *ml;
+ MPoly *mpoly;
+ KeyBlock *actkey, *block;
+ BMVert *v, **vt=NULL;
+ BMEdge *e, **fedges=NULL, **et = NULL;
+ BMFace *f;
+ BLI_array_declare(fedges);
+ float (*keyco)[3]= NULL;
+ int *keyi;
+ int i, j, li, allocsize[4] = {512, 512, 2048, 512};
+
+ if (!me || !me->totvert) return; /*sanity check*/
+
+ mvert = me->mvert;
+ vt = MEM_mallocN(sizeof(void**)*me->totvert, "mesh to bmesh vtable");
+
+ CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+ CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0);
+
+ if (!CustomData_has_layer(&bm->edata, CD_CREASE))
+ CustomData_add_layer(&bm->edata, CD_CREASE, CD_ASSIGN, NULL, 0);
+
+ if (!CustomData_has_layer(&bm->edata, CD_BWEIGHT))
+ CustomData_add_layer(&bm->edata, CD_BWEIGHT, CD_ASSIGN, NULL, 0);
+
+ if (!CustomData_has_layer(&bm->vdata, CD_BWEIGHT))
+ CustomData_add_layer(&bm->vdata, CD_BWEIGHT, CD_ASSIGN, NULL, 0);
+
+
+ if (me->key && ob->shapenr > me->key->totkey) {
+ ob->shapenr = me->key->totkey-1;
+ }
+
+ actkey = ob_get_keyblock(ob);
+ if(actkey && actkey->totelem == me->totvert) {
+ /*check if we need to generate unique ids for the shapekeys.
+ this also exists in the file reading code, but is here for
+ a sanity check*/
+ if (!me->key->uidgen) {
+ printf("yeek! had to generate shape key uid's in a situation we shouldn't need to!\n");
+ me->key->uidgen = 1;
+ for (block=me->key->block.first; block; block=block->next) {
+ block->uid = me->key->uidgen++;
+ }
+ }
+
+ keyco= actkey->data;
+ bm->shapenr= ob->shapenr;
+ for (i=0, block=me->key->block.first; block; block=block->next, i++) {
+ CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY,
+ CD_ASSIGN, NULL, 0, block->name);
+
+ j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i);
+ bm->vdata.layers[j].uid = block->uid;
+ }
+ } else if (actkey) {
+ printf("shapekey<->mesh mismatch!\n");
+ }
+
+ CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
+
+ for (i=0; i<me->totvert; i++, mvert++) {
+ v = BM_Make_Vert(bm, keyco ? keyco[i] : mvert->co, NULL);
+ copy_v3_v3(v->no, mvert->no);
+
+ vt[i] = v;
+ BMINDEX_SET(v, i);
+
+ /*this is necassary for selection counts to work properly*/
+ if(v->head.flag & BM_SELECT) BM_Select_Vert(bm, v, 1);
+
+ /*transfer flags*/
+ v->head.flag = MEFlags_To_BMFlags(mvert->flag, BM_VERT);
+ BM_SetCDf(&bm->vdata, v, CD_BWEIGHT, (float)mvert->bweight / 255.0f);
+
+ /*Copy Custom Data*/
+ CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data);
+
+ /*set shape key original index*/
+ keyi = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_SHAPE_KEYINDEX);
+ *keyi = i;
+
+ /*set shapekey data*/
+ if (me->key) {
+ for (block=me->key->block.first, j=0; block; block=block->next, j++) {
+ float *co = CustomData_bmesh_get_n(&bm->vdata, v->head.data,
+ CD_SHAPEKEY, j);
+ VECCOPY(co, ((float*)block->data)+3*i);
+ }
+ }
+ }
+
+ if (!me->totedge) {
+ MEM_freeN(vt);
+ return;
+ }
+
+ et = MEM_mallocN(sizeof(void**)*me->totedge, "mesh to bmesh etable");
+
+ medge = me->medge;
+ for (i=0; i<me->totedge; i++, medge++) {
+ e = BM_Make_Edge(bm, vt[medge->v1], vt[medge->v2], NULL, 0);
+ et[i] = e;
+
+ /*Copy Custom Data*/
+ CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data);
+
+ BM_SetCDf(&bm->edata, e, CD_CREASE, (float)medge->crease / 255.0f);
+ BM_SetCDf(&bm->edata, e, CD_BWEIGHT, (float)medge->bweight / 255.0f);
+
+ /*this is necassary for selection counts to work properly*/
+ if (e->head.flag & BM_SELECT) BM_Select(bm, e, 1);
+
+ /*transfer flags*/
+ e->head.flag = MEFlags_To_BMFlags(medge->flag, BM_EDGE);
+ }
+
+ if (!me->totpoly) {
+ MEM_freeN(vt);
+ MEM_freeN(et);
+ return;
+ }
+
+ mpoly = me->mpoly;
+ li = 0;
+ for (i=0; i<me->totpoly; i++, mpoly++) {
+ BMVert *v1, *v2;
+ BMIter iter;
+ BMLoop *l;
+
+ BLI_array_empty(fedges);
+ BLI_array_empty(verts);
+ for (j=0; j<mpoly->totloop; j++) {
+ ml = &me->mloop[mpoly->loopstart+j];
+ v = vt[ml->v];
+ e = et[ml->e];
+
+ BLI_array_growone(fedges);
+ BLI_array_growone(verts);
+
+ fedges[j] = e;
+ verts[j] = v;
+ }
+
+ v1 = vt[me->mloop[mpoly->loopstart].v];
+ v2 = vt[me->mloop[mpoly->loopstart+1].v];
+
+ if (v1 == fedges[0]->v1) v2 = fedges[0]->v2;
+ else {
+ v1 = fedges[0]->v2;
+ v2 = fedges[0]->v1;
+ }
+
+ f = BM_Make_Face(bm, verts, fedges, mpoly->totloop);
+
+ if (!f) {
+ printf("Warning! Bad face in mesh"
+ " \"%s\" at index %d!\n", me->id.name+2, i);
+ continue;
+ }
+
+ /*this is necassary for selection counts to work properly*/
+ if (f->head.flag & BM_SELECT) BM_Select(bm, f, 1);
+
+ /*transfer flags*/
+ f->head.flag = MEFlags_To_BMFlags(mpoly->flag, BM_FACE);
+
+ f->mat_nr = mpoly->mat_nr;
+ if (i == me->act_face) bm->act_face = f;
+
+ /*Copy over loop customdata*/
+ j = 0;
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
+ CustomData_to_bmesh_block(&me->ldata, &bm->ldata, mpoly->loopstart+j, &l->head.data);
+ li++;
+ j++;
+ }
+
+ /*Copy Custom Data*/
+ CustomData_to_bmesh_block(&me->pdata, &bm->pdata, i, &f->head.data);
+ }
+
+ BLI_array_free(fedges);
+
+ MEM_freeN(vt);
+ MEM_freeN(et);
+}
+
+
+static void loops_to_corners(BMesh *bm, Mesh *me, int findex,
+ BMFace *f, BMLoop *ls[3], int numTex, int numCol)
+{
+ BMLoop *l;
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ int i, j;
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_get_n(&me->fdata, CD_MTFACE, findex, i);
+ texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
+
+ texface->tpage = texpoly->tpage;
+ texface->flag = texpoly->flag;
+ texface->transp = texpoly->transp;
+ texface->mode = texpoly->mode;
+ texface->tile = texpoly->tile;
+ texface->unwrap = texpoly->unwrap;
+
+ for (j=0; j<3; j++) {
+ l = ls[j];
+ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
+ texface->uv[j][0] = mloopuv->uv[0];
+ texface->uv[j][1] = mloopuv->uv[1];
+ }
+ }
+
+ for(i=0; i < numCol; i++){
+ mcol = CustomData_get_n(&me->fdata, CD_MCOL, findex, i);
+
+ for (j=0; j<3; j++) {
+ l = ls[j];
+ mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
+ mcol[j].r = mloopcol->r;
+ mcol[j].g = mloopcol->g;
+ mcol[j].b = mloopcol->b;
+ mcol[j].a = mloopcol->a;
+ }
+ }
+}
+
+void object_load_bmesh_exec(BMesh *bm, BMOperator *op) {
+ Object *ob = BMO_Get_Pnt(op, "object");
+ Scene *scene = BMO_Get_Pnt(op, "scene");
+ Mesh *me = ob->data;
+
+ BMO_CallOpf(bm, "bmesh_to_mesh mesh=%p object=%p", me, ob);
+
+ /*BMESH_TODO eventually we'll have to handle shapekeys here*/
+}
+
+void bmesh_to_mesh_exec(BMesh *bm, BMOperator *op) {
+ Mesh *me = BMO_Get_Pnt(op, "mesh");
+ Object *ob = BMO_Get_Pnt(op, "object");
+ MLoop *mloop;
+ KeyBlock *block;
+ MPoly *mpoly;
+ MVert *mvert, *oldverts;
+ MEdge *medge;
+ MFace *mface;
+ BMVert *v, *eve;
+ BMEdge *e;
+ BMLoop *l;
+ BMFace *f;
+ BMIter iter, liter;
+ float *facenors = NULL;
+ int i, j, *keyi, ototvert, totloop, totface, numTex, numCol;
+ int dotess = !BMO_Get_Int(op, "notesselation");
+
+ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
+
+ ototvert = me->totvert;
+
+ /* new Vertex block */
+ if(bm->totvert==0) mvert= NULL;
+ else mvert= MEM_callocN(bm->totvert*sizeof(MVert), "loadeditbMesh vert");
+
+ /* new Edge block */
+ if(bm->totedge==0) medge= NULL;
+ else medge= MEM_callocN(bm->totedge*sizeof(MEdge), "loadeditbMesh edge");
+
+ /*build ngon data*/
+ /* new Ngon Face block */
+ if(bm->totface==0) mpoly = NULL;
+ else mpoly= MEM_callocN(bm->totface*sizeof(MPoly), "loadeditbMesh poly");
+
+ /*find number of loops to allocate*/
+ totloop = 0;
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ totloop += f->len;
+ }
+
+ if (totloop==0) mloop = NULL;
+ else mloop = MEM_callocN(totloop*sizeof(MLoop), "loadeditbMesh loop");
+
+ /* lets save the old verts just in case we are actually working on
+ * a key ... we now do processing of the keys at the end */
+ oldverts= me->mvert;
+
+ /* don't free this yet */
+ CustomData_set_layer(&me->vdata, CD_MVERT, NULL);
+
+ /* free custom data */
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
+
+ /* add new custom data */
+ me->totvert= bm->totvert;
+ me->totedge= bm->totedge;
+ me->totloop= totloop;
+ me->totpoly= bm->totface;
+
+ CustomData_copy(&bm->vdata, &me->vdata, CD_MASK_MESH, CD_CALLOC, me->totvert);
+ CustomData_copy(&bm->edata, &me->edata, CD_MASK_MESH, CD_CALLOC, me->totedge);
+ CustomData_copy(&bm->ldata, &me->ldata, CD_MASK_MESH, CD_CALLOC, me->totloop);
+ CustomData_copy(&bm->pdata, &me->pdata, CD_MASK_MESH, CD_CALLOC, me->totpoly);
+
+ CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
+ CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
+ CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, mloop, me->totloop);
+ CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, mpoly, me->totpoly);
+
+ i = 0;
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ VECCOPY(mvert->co, v->co);
+
+ mvert->no[0] = (short) (v->no[0]*32767.0f);
+ mvert->no[1] = (short) (v->no[1]*32767.0f);
+ mvert->no[2] = (short) (v->no[2]*32767.0f);
+
+ mvert->flag = BMFlags_To_MEFlags(v);
+
+ BMINDEX_SET(v, i);
+
+ /*copy over customdata*/
+ CustomData_from_bmesh_block(&bm->vdata, &me->vdata, v->head.data, i);
+
+ i++;
+ mvert++;
+
+ CHECK_ELEMENT(bm, v);
+ }
+
+ i = 0;
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ medge->v1 = BMINDEX_GET(e->v1);
+ medge->v2 = BMINDEX_GET(e->v2);
+
+ medge->flag = BMFlags_To_MEFlags(e);
+
+ BMINDEX_SET(e, i);
+
+ /*copy over customdata*/
+ CustomData_from_bmesh_block(&bm->edata, &me->edata, e->head.data, i);
+
+ i++;
+ medge++;
+ CHECK_ELEMENT(bm, e);
+ }
+
+ /*new scanfill tesselation code*/
+ if (dotess) {
+ /*first counter number of faces we'll need*/
+ totface = 0;
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ EditVert *eve, *lasteve = NULL, *firsteve = NULL;
+ EditFace *efa;
+
+ i = 0;
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ eve = BLI_addfillvert(l->v->co);
+ eve->tmp.p = l;
+
+ BMINDEX_SET(l, i);
+
+ if (lasteve) {
+ BLI_addfilledge(lasteve, eve);
+ }
+
+ lasteve = eve;
+ if (!firsteve) firsteve = eve;
+
+ i++;
+ }
+
+ BLI_addfilledge(lasteve, firsteve);
+ BLI_edgefill(0);
+
+ for (efa=fillfacebase.first; efa; efa=efa->next)
+ totface++;
+
+ BLI_end_edgefill();
+ }
+
+ me->totface = totface;
+
+ /* new tess face block */
+ if(totface==0) mface= NULL;
+ else {
+ mface= MEM_callocN(totface*sizeof(MFace), "loadeditbMesh face");
+ facenors = MEM_callocN(totface*sizeof(float)*3, "facenors");
+ }
+
+ CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, mface, me->totface);
+ CustomData_add_layer(&me->fdata, CD_NORMAL, CD_ASSIGN, facenors, me->totface);
+ CustomData_from_bmeshpoly(&me->fdata, &bm->pdata, &bm->ldata, totface);
+
+ mesh_update_customdata_pointers(me);
+
+ i = 0;
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ EditVert *eve, *lasteve = NULL, *firsteve = NULL;
+ EditFace *efa;
+ BMLoop *ls[3];
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ eve = BLI_addfillvert(l->v->co);
+ eve->tmp.p = l;
+
+ if (lasteve) {
+ BLI_addfilledge(lasteve, eve);
+ }
+
+ lasteve = eve;
+ if (!firsteve) firsteve = eve;
+ }
+
+ BLI_addfilledge(lasteve, firsteve);
+ BLI_edgefill(0);
+
+ for (efa=fillfacebase.first; efa; efa=efa->next) {
+ ls[0] = efa->v1->tmp.p;
+ ls[1] = efa->v2->tmp.p;
+ ls[2] = efa->v3->tmp.p;
+
+ /*ensure correct winding. I believe this is
+ analogous to bubble sort on three elements.*/
+ if (BMINDEX_GET(ls[0]) > BMINDEX_GET(ls[1])) {
+ SWAP(BMLoop*, ls[0], ls[1]);
+ }
+ if (BMINDEX_GET(ls[1]) > BMINDEX_GET(ls[2])) {
+ SWAP(BMLoop*, ls[1], ls[2]);
+ }
+ if (BMINDEX_GET(ls[0]) > BMINDEX_GET(ls[1])) {
+ SWAP(BMLoop*, ls[0], ls[1]);
+ }
+
+ mface->mat_nr = f->mat_nr;
+ mface->flag = BMFlags_To_MEFlags(f);
+
+ mface->v1 = BMINDEX_GET(ls[0]->v);
+ mface->v2 = BMINDEX_GET(ls[1]->v);
+ mface->v3 = BMINDEX_GET(ls[2]->v);
+
+ test_index_face(mface, &me->fdata, i, 1);
+
+ loops_to_corners(bm, me, i, f, ls, numTex, numCol);
+ VECCOPY(facenors, ls[0]->f->no);
+
+ mface++;
+ facenors += 3;
+ i++;
+ }
+ BLI_end_edgefill();
+ }
+ }
+
+ i = 0;
+ j = 0;
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ mpoly->loopstart = j;
+ mpoly->totloop = f->len;
+ mpoly->mat_nr = f->mat_nr;
+ mpoly->flag = BMFlags_To_MEFlags(f);
+
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for ( ; l; l=BMIter_Step(&liter), j++, mloop++) {
+ mloop->e = BMINDEX_GET(l->e);
+ mloop->v = BMINDEX_GET(l->v);
+
+ /*copy over customdata*/
+ CustomData_from_bmesh_block(&bm->ldata, &me->ldata, l->head.data, j);
+ CHECK_ELEMENT(bm, l);
+ CHECK_ELEMENT(bm, l->e);
+ CHECK_ELEMENT(bm, l->v);
+ }
+
+ if (f == bm->act_face) me->act_face = i;
+
+ /*copy over customdata*/
+ CustomData_from_bmesh_block(&bm->pdata, &me->pdata, f->head.data, i);
+
+ i++;
+ mpoly++;
+ CHECK_ELEMENT(bm, f);
+ }
+
+ /* patch hook indices and vertex parents */
+ {
+ Object *ob;
+ ModifierData *md;
+ BMVert **vertMap = NULL;
+ int i,j;
+
+ for (ob=G.main->object.first; ob; ob=ob->id.next) {
+ if (ob->parent==ob && ELEM(ob->partype, PARVERT1,PARVERT3)) {
+
+ /* duplicate code from below, make it function later...? */
+ if (!vertMap) {
+ vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap");
+
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ keyi = CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_SHAPE_KEYINDEX);
+ if (*keyi != ORIGINDEX_NONE)
+ vertMap[*keyi] = eve;
+ }
+ }
+ if(ob->par1 < ototvert) {
+ eve = vertMap[ob->par1];
+ if(eve) ob->par1= BMINDEX_GET(eve);
+ }
+ if(ob->par2 < ototvert) {
+ eve = vertMap[ob->par2];
+ if(eve) ob->par2= BMINDEX_GET(eve);
+ }
+ if(ob->par3 < ototvert) {
+ eve = vertMap[ob->par3];
+ if(eve) ob->par3= BMINDEX_GET(eve);
+ }
+
+ }
+ if (ob->data==me) {
+ for (md=ob->modifiers.first; md; md=md->next) {
+ if (md->type==eModifierType_Hook) {
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ if (!vertMap) {
+ vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap");
+
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ keyi = CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_SHAPE_KEYINDEX);
+ if (*keyi != ORIGINDEX_NONE)
+ vertMap[*keyi] = eve;
+ }
+ }
+
+ for (i=j=0; i<hmd->totindex; i++) {
+ if(hmd->indexar[i] < ototvert) {
+ eve = vertMap[hmd->indexar[i]];
+
+ if (eve) {
+ hmd->indexar[j++] = BMINDEX_GET(eve);
+ }
+ }
+ else j++;
+ }
+
+ hmd->totindex = j;
+ }
+ }
+ }
+ }
+
+ if (vertMap) MEM_freeN(vertMap);
+ }
+
+ mesh_update_customdata_pointers(me);
+
+ if (me->key) {
+ KeyBlock *actkey= BLI_findlink(&me->key->block, bm->shapenr-1);
+
+ /*go through and find any shapekey customdata layers
+ that might not have corrusponding KeyBlocks, and add them if
+ necassary.*/
+ j = 0;
+ for (i=0; i<bm->vdata.totlayer; i++) {
+ if (bm->vdata.layers[i].type != CD_SHAPEKEY)
+ continue;
+
+ for (block=me->key->block.first; block; block=block->next) {
+ if (block->uid == bm->vdata.layers[i].uid)
+ break;
+ }
+
+ if (!block) {
+ block = MEM_callocN(sizeof(KeyBlock), "KeyBlock mesh_conv.c");
+ block->type = KEY_LINEAR;
+ block->slidermin = 0.0f;
+ block->slidermax = 1.0f;
+
+ BLI_addtail(&me->key->block, block);
+ me->key->totkey++;
+ }
+
+ j++;
+ }
+
+ for (block=me->key->block.first; block; block=block->next) {
+ j = 0;
+
+ for (i=0; i<bm->vdata.totlayer; i++) {
+ if (bm->vdata.layers[i].type != CD_SHAPEKEY)
+ continue;
+
+ if (block->uid == bm->vdata.layers[i].uid) {
+ float *fp, *co;
+
+ if (block->data)
+ MEM_freeN(block->data);
+ block->data = fp = MEM_mallocN(sizeof(float)*3*bm->totvert, "shape key data");
+ block->totelem = bm->totvert;
+
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ co = block==actkey ? eve->co : CustomData_bmesh_get_n(&bm->vdata, eve->head.data, CD_SHAPEKEY, j);
+
+ VECCOPY(fp, co);
+ fp += 3;
+ }
+ break;
+ }
+
+ j++;
+ }
+
+ /*if we didn't find a shapekey, tag the block to be reconstructed
+ via the old method below*/
+ if (j == CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY)) {
+ block->flag |= KEYBLOCK_MISSING;
+ }
+ }
+ }
+
+ /* old method of reconstructing keys via vertice's original key indices,
+ currently used if the new method above fails (which is theoretically
+ possible in certain cases of undo).*/
+ if(me->key) {
+ float *fp, *newkey, *oldkey;
+ KeyBlock *currkey;
+ KeyBlock *actkey= BLI_findlink(&me->key->block, bm->shapenr-1);
+
+ /* Lets reorder the key data so that things line up roughly
+ * with the way things were before editmode */
+ currkey = me->key->block.first;
+ while(currkey) {
+ if (!(currkey->flag & KEYBLOCK_MISSING)) {
+ currkey = currkey->next;
+ continue;
+ }
+
+ printf("warning: had to hackishly reconstruct shape key \"%s\","
+ " it may not be correct anymore.\n", currkey->name);
+
+ currkey->flag &= ~KEYBLOCK_MISSING;
+
+ fp= newkey= MEM_callocN(me->key->elemsize*bm->totvert, "currkey->data");
+ oldkey = currkey->data;
+
+ eve= BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+
+ i = 0;
+ mvert = me->mvert;
+ while(eve) {
+ keyi = CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_SHAPE_KEYINDEX);
+ if (*keyi >= 0 && *keyi < currkey->totelem) { // valid old vertex
+ if(currkey == actkey) {
+ if(actkey == me->key->refkey) {
+ VECCOPY(fp, mvert->co);
+ }
+ else {
+ VECCOPY(fp, mvert->co);
+ if(oldverts) {
+ VECCOPY(mvert->co, oldverts[*keyi].co);
+ }
+ }
+ }
+ else {
+ if(oldkey) {
+ VECCOPY(fp, oldkey + 3 * *keyi);
+ }
+ }
+ }
+ else {
+ VECCOPY(fp, mvert->co);
+ }
+ fp+= 3;
+ ++i;
+ ++mvert;
+ eve= BMIter_Step(&iter);
+ }
+ currkey->totelem= bm->totvert;
+ if(currkey->data) MEM_freeN(currkey->data);
+ currkey->data = newkey;
+
+ currkey= currkey->next;
+ }
+ }
+
+ if(oldverts) MEM_freeN(oldverts);
+}
diff --git a/source/blender/bmesh/operators/mirror.c b/source/blender/bmesh/operators/mirror.c
new file mode 100644
index 00000000000..f53d8b7b762
--- /dev/null
+++ b/source/blender/bmesh/operators/mirror.c
@@ -0,0 +1,127 @@
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include <string.h>
+
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+#include "BKE_global.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_editVert.h"
+#include "mesh_intern.h"
+#include "ED_mesh.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
+#include "BLI_array.h"
+#include "BLI_utildefines.h"
+
+#include "bmesh.h"
+
+/*
+ * MIRROR.C
+ *
+ * mirror bmop.
+ *
+*/
+
+#define ELE_NEW 1
+
+void bmesh_mirror_exec(BMesh *bm, BMOperator *op) {
+ BMOperator dupeop, weldop;
+ BMOIter siter;
+ BMIter iter;
+ BMVert *v, *v2, **vmap = NULL;
+ BLI_array_declare(vmap);
+ BMEdge *e, **emap = NULL;
+ BLI_array_declare(emap);
+ float mtx[4][4];
+ float imtx[4][4];
+ float scale[3] = {1.0f, 1.0f, 1.0f};
+ float dist = BMO_Get_Float(op, "mergedist");
+ int i, ototvert, ototedge, axis = BMO_Get_Int(op, "axis");
+ int mirroru = BMO_Get_Int(op, "mirror_u");
+ int mirrorv = BMO_Get_Int(op, "mirror_v");
+
+ ototvert = bm->totvert;
+ ototedge = bm->totedge;
+
+ BMO_Get_Mat4(op, "mat", mtx);
+ invert_m4_m4(imtx, mtx);
+
+ BMO_InitOpf(bm, &dupeop, "dupe geom=%s", op, "geom");
+ BMO_Exec_Op(bm, &dupeop);
+
+ BMO_Flag_Buffer(bm, &dupeop, "newout", ELE_NEW, BM_ALL);
+
+ /*create old -> new mapping*/
+ i = 0;
+ v2 = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ BMO_ITER(v, &siter, bm, &dupeop, "newout", BM_VERT) {
+ BLI_array_growone(vmap);
+ vmap[i] = v;
+
+ BMINDEX_SET(v2, i);
+ v2 = BMIter_Step(&iter);
+
+ i += 1;
+ }
+
+ /*feed old data to transform bmop*/
+ scale[axis] = -1.0f;
+ BMO_CallOpf(bm, "transform verts=%fv mat=%m4", ELE_NEW, mtx);
+ BMO_CallOpf(bm, "scale verts=%fv vec=%v", ELE_NEW, scale);
+ BMO_CallOpf(bm, "transform verts=%fv mat=%m4", ELE_NEW, imtx);
+
+ BMO_Init_Op(&weldop, "weldverts");
+
+ v = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; i<ototvert; i++) {
+ if (ABS(v->co[axis]) <= dist) {
+ BMO_Insert_MapPointer(bm, &weldop, "targetmap", vmap[i], v);
+ }
+ v = BMIter_Step(&iter);
+ }
+
+ if (mirroru || mirrorv) {
+ BMFace *f;
+ BMLoop *l;
+ MLoopUV *luv;
+ int totlayer;
+ BMIter liter;
+
+ BMO_ITER(f, &siter, bm, &dupeop, "newout", BM_FACE) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ totlayer = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
+ for (i=0; i<totlayer; i++) {
+ luv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
+ if (mirroru)
+ luv->uv[0] = 1.0 - luv->uv[0];
+ if (mirrorv)
+ luv->uv[1] = 1.0 - luv->uv[1];
+ }
+ }
+ }
+ }
+
+ BMO_Exec_Op(bm, &weldop);
+
+ BMO_Finish_Op(bm, &weldop);
+ BMO_Finish_Op(bm, &dupeop);
+
+ BMO_Flag_To_Slot(bm, op, "newout", ELE_NEW, BM_ALL);
+
+ BLI_array_free(vmap);
+ BLI_array_free(emap);
+}
+
diff --git a/source/blender/bmesh/operators/primitiveops.c b/source/blender/bmesh/operators/primitiveops.c
new file mode 100644
index 00000000000..5f2409cbbc8
--- /dev/null
+++ b/source/blender/bmesh/operators/primitiveops.c
@@ -0,0 +1,594 @@
+#include "MEM_guardedalloc.h"-
+
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_utildefines.h"
+
+#include "BLI_math.h"
+#include "BLI_ghash.h"
+#include "BLI_blenlib.h"
+#include "BLI_array.h"
+
+#include "ED_mesh.h"
+
+#include "bmesh.h"
+#include "mesh_intern.h"
+#include "bmesh_private.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/* ************************ primitives ******************* */
+
+static float icovert[12][3] = {
+ {0.0f,0.0f,-200.0f},
+ {144.72f, -105.144f,-89.443f},
+ {-55.277f, -170.128,-89.443f},
+ {-178.885f,0.0f,-89.443f},
+ {-55.277f,170.128f,-89.443f},
+ {144.72f,105.144f,-89.443f},
+ {55.277f,-170.128f,89.443f},
+ {-144.72f,-105.144f,89.443f},
+ {-144.72f,105.144f,89.443f},
+ {55.277f,170.128f,89.443f},
+ {178.885f,0.0f,89.443f},
+ {0.0f,0.0f,200.0f}
+};
+
+static short icoface[20][3] = {
+ {1,0,2},
+ {1,0,5},
+ {2,0,3},
+ {3,0,4},
+ {4,0,5},
+ {1,5,10},
+ {2,1,6},
+ {3,2,7},
+ {4,3,8},
+ {5,4,9},
+ {10,1,6},
+ {6,2,7},
+ {7,3,8},
+ {8,4,9},
+ {9,5,10},
+ {6,10,11},
+ {7,6,11},
+ {8,7,11},
+ {9,8,11},
+ {10,9,11}
+};
+
+// HACK: these can also be found in cmoview.tga.c, but are here so that they can be found by linker
+// this hack is only used so that scons+mingw + split-sources hack works
+ // ------------------------------- start copied code
+/* these are not the monkeys you are looking for */
+int monkeyo= 4;
+int monkeynv= 271;
+int monkeynf= 250;
+signed char monkeyv[271][3]= {
+{-71,21,98},{-63,12,88},{-57,7,74},{-82,-3,79},{-82,4,92},
+{-82,17,100},{-92,21,102},{-101,12,95},{-107,7,83},
+{-117,31,84},{-109,31,95},{-96,31,102},{-92,42,102},
+{-101,50,95},{-107,56,83},{-82,66,79},{-82,58,92},
+{-82,46,100},{-71,42,98},{-63,50,88},{-57,56,74},
+{-47,31,72},{-55,31,86},{-67,31,97},{-66,31,99},
+{-70,43,100},{-82,48,103},{-93,43,105},{-98,31,105},
+{-93,20,105},{-82,31,106},{-82,15,103},{-70,20,100},
+{-127,55,95},{-127,45,105},{-127,-87,94},{-127,-41,100},
+{-127,-24,102},{-127,-99,92},{-127,52,77},{-127,73,73},
+{-127,115,-70},{-127,72,-109},{-127,9,-106},{-127,-49,-45},
+{-101,-24,72},{-87,-56,73},{-82,-89,73},{-80,-114,68},
+{-85,-121,67},{-104,-124,71},{-127,-126,74},{-71,-18,68},
+{-46,-5,69},{-21,19,57},{-17,55,76},{-36,62,80},
+{-64,77,88},{-86,97,94},{-107,92,97},{-119,63,96},
+{-106,53,99},{-111,39,98},{-101,12,95},{-79,2,90},
+{-64,8,86},{-47,24,83},{-45,38,83},{-50,48,85},
+{-72,56,92},{-95,60,97},{-127,-98,94},{-113,-92,94},
+{-112,-107,91},{-119,-113,89},{-127,-114,88},{-127,-25,96},
+{-127,-18,95},{-114,-19,95},{-111,-29,96},{-116,-37,95},
+{-76,-6,86},{-48,7,80},{-34,26,77},{-32,48,84},
+{-39,53,93},{-71,70,102},{-87,82,107},{-101,79,109},
+{-114,55,108},{-111,-13,104},{-100,-57,91},{-95,-90,88},
+{-93,-105,85},{-97,-117,81},{-106,-119,81},{-127,-121,82},
+{-127,6,93},{-127,27,98},{-85,61,95},{-106,18,96},
+{-110,27,97},{-112,-88,94},{-117,-57,96},{-127,-57,96},
+{-127,-42,95},{-115,-35,100},{-110,-29,102},{-113,-17,100},
+{-122,-16,100},{-127,-26,106},{-121,-19,104},{-115,-20,104},
+{-113,-29,106},{-117,-32,103},{-127,-37,103},{-94,-40,71},
+{-106,-31,91},{-104,-40,91},{-97,-32,71},{-127,-112,88},
+{-121,-111,88},{-115,-105,91},{-115,-95,93},{-127,-100,84},
+{-115,-96,85},{-115,-104,82},{-121,-109,81},{-127,-110,81},
+{-105,28,100},{-103,20,99},{-84,55,97},{-92,54,99},
+{-73,51,99},{-55,45,89},{-52,37,88},{-53,25,87},
+{-66,13,92},{-79,8,95},{-98,14,100},{-104,38,100},
+{-100,48,100},{-97,46,97},{-102,38,97},{-96,16,97},
+{-79,11,93},{-68,15,90},{-57,27,86},{-56,36,86},
+{-59,43,87},{-74,50,96},{-91,51,98},{-84,52,96},
+{-101,22,96},{-102,29,96},{-113,59,78},{-102,85,79},
+{-84,88,76},{-65,71,71},{-40,58,63},{-25,52,59},
+{-28,21,48},{-50,0,53},{-71,-12,60},{-127,115,37},
+{-127,126,-10},{-127,-25,-86},{-127,-59,24},{-127,-125,59},
+{-127,-103,44},{-127,-73,41},{-127,-62,36},{-18,30,7},
+{-17,41,-6},{-28,34,-56},{-68,56,-90},{-33,-6,9},
+{-51,-16,-21},{-45,-1,-55},{-84,7,-85},{-97,-45,52},
+{-104,-53,33},{-90,-91,49},{-95,-64,50},{-85,-117,51},
+{-109,-97,47},{-111,-69,46},{-106,-121,56},{-99,-36,55},
+{-100,-29,60},{-101,-22,64},{-100,-50,21},{-89,-40,-34},
+{-83,-19,-69},{-69,111,-49},{-69,119,-9},{-69,109,30},
+{-68,67,55},{-34,52,43},{-46,58,36},{-45,90,7},
+{-25,72,16},{-25,79,-15},{-45,96,-25},{-45,87,-57},
+{-25,69,-46},{-48,42,-75},{-65,3,-70},{-22,42,-26},
+{-75,-22,19},{-72,-25,-27},{-13,52,-30},{-28,-18,-16},
+{6,-13,-42},{37,7,-55},{46,41,-54},{31,65,-54},
+{4,61,-40},{3,53,-37},{25,56,-50},{35,37,-52},
+{28,10,-52},{5,-5,-39},{-21,-9,-17},{-9,46,-28},
+{-6,39,-37},{-14,-3,-27},{6,0,-47},{25,12,-57},
+{31,32,-57},{23,46,-56},{4,44,-46},{-19,37,-27},
+{-20,22,-35},{-30,12,-35},{-22,11,-35},{-19,2,-35},
+{-23,-2,-35},{-34,0,-9},{-35,-3,-22},{-35,5,-24},
+{-25,26,-27},{-13,31,-34},{-13,30,-41},{-23,-2,-41},
+{-18,2,-41},{-21,10,-41},{-29,12,-41},{-19,22,-41},
+{6,42,-53},{25,44,-62},{34,31,-63},{28,11,-62},
+{7,0,-54},{-14,-2,-34},{-5,37,-44},{-13,14,-42},
+{-7,8,-43},{1,16,-47},{-4,22,-45},{3,30,-48},
+{8,24,-49},{15,27,-50},{12,35,-50},{4,56,-62},
+{33,60,-70},{48,38,-64},{41,7,-68},{6,-11,-63},
+{-26,-16,-42},{-17,49,-49},
+};
+
+signed char monkeyf[250][4]= {
+{27,4,5,26}, {25,4,5,24}, {3,6,5,4}, {1,6,5,2}, {5,6,7,4},
+{3,6,7,2}, {5,8,7,6}, {3,8,7,4}, {7,8,9,6},
+{5,8,9,4}, {7,10,9,8}, {5,10,9,6}, {9,10,11,8},
+{7,10,11,6}, {9,12,11,10}, {7,12,11,8}, {11,6,13,12},
+{5,4,13,12}, {3,-2,13,12}, {-3,-4,13,12}, {-5,-10,13,12},
+{-11,-12,14,12}, {-13,-18,14,13}, {-19,4,5,13}, {10,12,4,4},
+{10,11,9,9}, {8,7,9,9}, {7,5,6,6}, {6,3,4,4},
+{5,1,2,2}, {4,-1,0,0}, {3,-3,-2,-2}, {22,67,68,23},
+{20,65,66,21}, {18,63,64,19}, {16,61,62,17}, {14,59,60,15},
+{12,19,48,57}, {18,19,48,47}, {18,19,48,47}, {18,19,48,47},
+{18,19,48,47}, {18,19,48,47}, {18,19,48,47}, {18,19,48,47},
+{18,19,48,47}, {18,-9,-8,47}, {18,27,45,46}, {26,55,43,44},
+{24,41,42,54}, {22,39,40,23}, {20,37,38,21}, {18,35,36,19},
+{16,33,34,17}, {14,31,32,15}, {12,39,30,13}, {11,48,45,38},
+{8,36,-19,9}, {8,-20,44,47}, {42,45,46,43}, {18,19,40,39},
+{16,17,38,37}, {14,15,36,35}, {32,44,43,33}, {12,33,32,42},
+{19,44,43,42}, {40,41,42,-27}, {8,9,39,-28}, {15,43,42,16},
+{13,43,42,14}, {11,43,42,12}, {9,-30,42,10}, {37,12,38,-32},
+{-33,37,45,46}, {-33,40,41,39}, {38,40,41,37}, {36,40,41,35},
+{34,40,41,33}, {36,39,38,37}, {35,40,39,38}, {1,2,14,21},
+{1,2,40,13}, {1,2,40,39}, {1,24,12,39}, {-34,36,38,11},
+{35,38,36,37}, {-37,8,35,37}, {-11,-12,-45,40}, {-11,-12,39,38},
+{-11,-12,37,36}, {-11,-12,35,34}, {33,34,40,41}, {33,34,38,39},
+{33,34,36,37}, {33,-52,34,35}, {33,37,36,34}, {33,35,34,34},
+{8,7,37,36}, {-32,7,35,46}, {-34,-33,45,46}, {4,-33,43,34},
+{-34,-33,41,42}, {-34,-33,39,40}, {-34,-33,37,38}, {-34,-33,35,36},
+{-34,-33,33,34}, {-34,-33,31,32}, {-34,-4,28,30}, {-5,-34,28,27},
+{-35,-44,36,27}, {26,35,36,45}, {24,25,44,45}, {25,23,44,42},
+{25,24,41,40}, {25,24,39,38}, {25,24,37,36}, {25,24,35,34},
+{25,24,33,32}, {25,24,31,30}, {15,24,29,38}, {25,24,27,26},
+{23,12,37,26}, {11,12,35,36}, {-86,-59,36,-80}, {-60,-61,36,35},
+{-62,-63,36,35}, {-64,-65,36,35}, {-66,-67,36,35}, {-68,-69,36,35},
+{-70,-71,36,35}, {-72,-73,36,35}, {-74,-75,36,35}, {42,43,53,58},
+{40,41,57,56}, {38,39,55,57}, {-81,-80,37,56}, {-83,-82,55,52},
+{-85,-84,51,49}, {-87,-86,48,49}, {47,50,51,48}, {46,48,51,49},
+{43,46,49,44}, {-92,-91,45,42}, {-23,49,50,-20}, {-94,40,48,-24},
+{-96,-22,48,49}, {-97,48,21,-90}, {-100,36,50,23}, {22,49,48,-100},
+{-101,47,46,22}, {21,45,35,25}, {33,34,44,41}, {13,14,28,24},
+{-107,26,30,-106}, {14,46,45,15}, {14,44,43,-110}, {-111,42,23,-110},
+{6,7,45,46}, {45,44,47,46}, {45,46,47,48}, {47,46,49,48},
+{17,49,47,48}, {17,36,46,48}, {35,36,44,45}, {35,36,40,43},
+{35,36,38,39}, {-4,-3,37,35}, {-123,34,33,1}, {-9,-8,-7,-6},
+{-10,-7,32,-125}, {-127,-11,-126,-126}, {-7,-6,5,31}, {4,5,33,30},
+{4,39,33,32}, {4,35,32,38}, {20,21,39,38}, {4,37,38,5},
+{-11,-10,36,3}, {-11,15,14,35}, {13,16,34,34}, {-13,14,13,13},
+{-3,1,30,29}, {-3,28,29,1}, {-2,31,28,-1}, {12,13,27,30},
+{-2,26,12,12}, {35,29,42,36}, {34,35,36,33}, {32,35,36,31},
+{30,35,36,29}, {28,35,36,27}, {26,35,36,25}, {34,39,38,35},
+{32,39,38,33}, {30,39,38,31}, {28,39,38,29}, {26,39,38,27},
+{25,31,32,38}, {-18,-17,45,44}, {-18,17,28,44}, {-24,-20,42,-23},
+{11,35,27,14}, {25,28,39,41}, {37,41,40,38}, {34,40,36,35},
+{32,40,39,33}, {30,39,31,40}, {21,29,39,22}, {-31,37,28,4},
+{-32,33,35,36}, {32,33,34,34}, {18,35,36,48}, {34,25,40,35},
+{24,25,38,39}, {24,25,36,37}, {24,25,34,35}, {24,25,32,33},
+{24,13,41,31}, {17,11,41,35}, {15,16,34,35}, {13,14,34,35},
+{11,12,34,35}, {9,10,34,35}, {7,8,34,35}, {26,25,37,36},
+{35,36,37,38}, {37,36,39,38}, {37,38,39,40}, {25,31,36,39},
+{18,34,35,30}, {17,22,30,33}, {19,29,21,20}, {16,26,29,17},
+{24,29,28,25}, {22,31,28,23}, {20,31,30,21}, {18,31,30,19},
+{16,30,17,17}, {-21,-22,35,34}, {-21,-22,33,32}, {-21,-22,31,30},
+{-21,-22,29,28}, {-21,-22,27,26}, {-28,-22,25,31}, {24,28,29,30},
+{23,24,26,27}, {23,24,25,25}, {-69,-35,-32,27}, {-70,26,25,-66},
+{-68,-67,24,-33},
+};
+
+#define VERT_MARK 1
+
+#define EDGE_ORIG 1
+#define EDGE_MARK 2
+
+#define FACE_MARK 1
+
+void bmesh_create_grid_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator bmop, prevop;
+ BMVert *eve, *preveve;
+ BMEdge *e;
+ float vec[3], mat[4][4], phi, phid, dia=BMO_Get_Float(op, "size");
+ int a, tot=BMO_Get_Int(op, "xsegments"), seg=BMO_Get_Int(op, "ysegments");
+
+ if (tot < 2) tot = 2;
+ if (seg < 2) seg = 2;
+
+ BMO_Get_Mat4(op, "mat", mat);
+
+ /* one segment first: the X axis */
+ phi= 1.0;
+ phid= 2.0/((float)tot-1);
+ for(a=0;a<tot;a++) {
+ vec[0]= dia*phi;
+ vec[1]= - dia;
+ vec[2]= 0.0f;
+ mul_m4_v3(mat,vec);
+
+ eve= BM_Make_Vert(bm, vec, NULL);
+ BM_Select(bm, eve, 1);
+
+ if (a) {
+ e = BM_Make_Edge(bm, preveve, eve, NULL, 1);
+ BMO_SetFlag(bm, e, EDGE_ORIG);
+ }
+
+ preveve = eve;
+ phi-=phid;
+ }
+
+ /* extrude and translate */
+ vec[0]= vec[2]= 0.0;
+ vec[1]= dia*phid;
+ mul_mat3_m4_v3(mat, vec);
+
+ for(a=0;a<seg-1;a++) {
+ if (a) {
+ BMO_InitOpf(bm, &bmop, "extrude_edge_only edges=%s", &prevop, "geomout");
+ BMO_Exec_Op(bm, &bmop);
+ BMO_Finish_Op(bm, &prevop);
+
+ BMO_Flag_Buffer(bm, &bmop, "geomout", VERT_MARK, BM_VERT);
+ } else {
+ BMO_InitOpf(bm, &bmop, "extrude_edge_only edges=%fe", EDGE_ORIG);
+ BMO_Exec_Op(bm, &bmop);
+ BMO_Flag_Buffer(bm, &bmop, "geomout", VERT_MARK, BM_VERT);
+ }
+
+ BMO_CallOpf(bm, "translate vec=%v verts=%s", vec, &bmop, "geomout");
+ prevop = bmop;
+ }
+
+ if (a)
+ BMO_Finish_Op(bm, &bmop);
+
+ BMO_Flag_To_Slot(bm, op, "vertout", VERT_MARK, BM_VERT);
+}
+
+void bmesh_create_uvsphere_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator bmop, prevop;
+ BMVert *eve, *preveve, *v1;
+ BMEdge *e;
+ BMIter iter;
+ float vec[3], mat[4][4], cmat[3][3], phi, q[4];
+ float phid, dia=BMO_Get_Float(op, "diameter");
+ int a, seg=BMO_Get_Int(op, "segments"), tot=BMO_Get_Int(op, "revolutions");
+
+ BMO_Get_Mat4(op, "mat", mat);
+
+ phid= 2.0f*(float)M_PI/tot;
+ phi= .25f*(float)M_PI;
+
+ /* one segment first */
+ phi= 0;
+ phid/=2;
+ for(a=0; a<=tot; a++) {
+ vec[0]= dia*sin(phi);
+ vec[1]= 0.0;
+ vec[2]= dia*cos(phi);
+ eve= BM_Make_Vert(bm, vec, NULL);
+ BMO_SetFlag(bm, eve, VERT_MARK);
+
+ if(a==0) v1= eve;
+ else {
+ e = BM_Make_Edge(bm, preveve, eve, NULL, 0);
+ BMO_SetFlag(bm, e, EDGE_ORIG);
+ }
+
+ phi+= phid;
+ preveve = eve;
+ }
+
+ /* extrude and rotate */
+ phi= M_PI/seg;
+ q[0]= cos(phi);
+ q[3]= sin(phi);
+ q[1]=q[2]= 0;
+ quat_to_mat3(cmat, q);
+
+ for(a=0; a<seg; a++) {
+ if (a) {
+ BMO_InitOpf(bm, &bmop, "extrude_edge_only edges=%s", &prevop, "geomout");
+ BMO_Exec_Op(bm, &bmop);
+ BMO_Finish_Op(bm, &prevop);
+ } else {
+ BMO_InitOpf(bm, &bmop, "extrude_edge_only edges=%fe", EDGE_ORIG);
+ BMO_Exec_Op(bm, &bmop);
+ }
+
+ BMO_Flag_Buffer(bm, &bmop, "geomout", VERT_MARK, BM_VERT);
+ BMO_CallOpf(bm, "rotate cent=%v mat=%m3 verts=%s", vec, cmat, &bmop, "geomout");
+
+ prevop = bmop;
+ }
+
+ if (a)
+ BMO_Finish_Op(bm, &bmop);
+
+ BMO_CallOpf(bm, "removedoubles verts=%fv dist=%f", VERT_MARK, 0.001f);
+
+ /* and now do imat */
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(BMO_TestFlag(bm, eve, VERT_MARK)) {
+ mul_m4_v3(mat, eve->co);
+ }
+ }
+
+ BMO_Flag_To_Slot(bm, op, "vertout", VERT_MARK, BM_VERT);
+}
+
+void bmesh_create_icosphere_exec(BMesh *bm, BMOperator *op)
+{
+ BMVert *eva[12];
+ BMIter liter;
+ BMLoop *l;
+ float vec[3], mat[4][4], phi, phid;
+ float dia = BMO_Get_Float(op, "diameter");
+ int a, subdiv = BMO_Get_Int(op, "subdivisions");
+
+ BMO_Get_Mat4(op, "mat", mat);
+
+ phid= 2.0f*(float)M_PI/subdiv;
+ phi= .25f*(float)M_PI;
+
+ dia/=200;
+ for(a=0;a<12;a++) {
+ vec[0]= dia*icovert[a][0];
+ vec[1]= dia*icovert[a][1];
+ vec[2]= dia*icovert[a][2];
+ eva[a]= BM_Make_Vert(bm, vec, NULL);
+
+ mul_m4_v3(mat, eva[a]->co);
+ BM_Select(bm, eva[a], 1);
+ }
+
+ for(a=0;a<20;a++) {
+ BMFace *eftemp;
+ BMVert *v1, *v2, *v3;
+
+ v1= eva[ icoface[a][0] ];
+ v2= eva[ icoface[a][1] ];
+ v3= eva[ icoface[a][2] ];
+
+ eftemp = BM_Make_QuadTri(bm, v1, v2, v3, NULL, NULL, 0);
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, eftemp) {
+ BMO_SetFlag(bm, l->e, EDGE_MARK);
+ }
+
+ BMO_SetFlag(bm, eftemp, FACE_MARK);
+ }
+
+ dia*=200;
+
+ for(a=1; a<subdiv; a++) {
+ BMOperator bmop;
+
+ BMO_InitOpf(bm, &bmop,
+ "esubd edges=%fe smooth=%f numcuts=%i gridfill=%i beauty=%i",
+ EDGE_MARK, dia, 1, 1, B_SPHERE);
+ BMO_Exec_Op(bm, &bmop);
+ BMO_Flag_Buffer(bm, &bmop, "geomout", VERT_MARK, BM_VERT);
+ BMO_Flag_Buffer(bm, &bmop, "geomout", EDGE_MARK, BM_EDGE);
+ BMO_Finish_Op(bm, &bmop);
+ }
+
+ BMO_Flag_To_Slot(bm, op, "vertout", VERT_MARK, BM_VERT);
+}
+
+void bmesh_create_monkey_exec(BMesh *bm, BMOperator *op)
+{
+ BMVert *eve;
+ BMVert **tv= MEM_mallocN(sizeof(*tv)*monkeynv*2, "tv");
+ float mat[4][4];
+ int i;
+
+ BMO_Get_Mat4(op, "mat", mat);
+
+ for (i=0; i<monkeynv; i++) {
+ float v[3];
+
+ v[0]= (monkeyv[i][0]+127)/128.0, v[1]= monkeyv[i][1]/128.0, v[2]= monkeyv[i][2]/128.0;
+
+ tv[i]= BM_Make_Vert(bm, v, NULL);
+ BMO_SetFlag(bm, tv[i], VERT_MARK);
+
+ tv[monkeynv+i]= (fabs(v[0]= -v[0])<0.001)?tv[i]: (eve=BM_Make_Vert(bm, v, NULL), mul_m4_v3(mat, eve->co), eve);
+ BMO_SetFlag(bm, tv[monkeynv+i], VERT_MARK);
+
+ mul_m4_v3(mat, tv[i]->co);
+ }
+
+ for (i=0; i<monkeynf; i++) {
+ BM_Make_QuadTri(bm, tv[monkeyf[i][0]+i-monkeyo], tv[monkeyf[i][1]+i-monkeyo], tv[monkeyf[i][2]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeyf[i][3]+i-monkeyo]:NULL, NULL, 0);
+ BM_Make_QuadTri(bm, tv[monkeynv+monkeyf[i][2]+i-monkeyo], tv[monkeynv+monkeyf[i][1]+i-monkeyo], tv[monkeynv+monkeyf[i][0]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeynv+monkeyf[i][3]+i-monkeyo]:NULL, NULL, 0);
+ }
+
+ MEM_freeN(tv);
+
+ BMO_Flag_To_Slot(bm, op, "vertout", VERT_MARK, BM_VERT);
+}
+
+void bmesh_create_cone_exec(BMesh *bm, BMOperator *op)
+{
+ BMVert *v1, *v2, *lastv1=NULL, *lastv2=NULL, *cent1, *cent2, *firstv1, *firstv2;
+ float vec[3], mat[4][4], phi, phid;
+ float dia1 = BMO_Get_Float(op, "diameter1");
+ float dia2 = BMO_Get_Float(op, "diameter2");
+ float depth = BMO_Get_Float(op, "depth");
+ int cap_ends = BMO_Get_Int(op, "cap_ends"), segs=BMO_Get_Int(op, "segments");
+ int a;
+
+ BMO_Get_Mat4(op, "mat", mat);
+
+ phid= 2.0f*(float)M_PI/segs;
+ phi= .25f*(float)M_PI;
+
+ depth *= 0.5f;
+ if (cap_ends) {
+ vec[0] = vec[1] = 0.0f;
+ vec[2] = -depth;
+
+ cent1 = BM_Make_Vert(bm, vec, NULL);
+
+ vec[0] = vec[1] = 0.0f;
+ vec[2] = depth;
+ cent2 = BM_Make_Vert(bm, vec, NULL);
+
+ BMO_SetFlag(bm, cent1, VERT_MARK);
+ BMO_SetFlag(bm, cent2, VERT_MARK);
+ }
+
+ for (a=0; a<segs; a++, phi+=phid) {
+ vec[0]= dia1*sin(phi);
+ vec[1]= dia1*cos(phi);
+ vec[2]= -depth;
+ mul_m4_v3(mat, vec);
+ v1 = BM_Make_Vert(bm, vec, NULL);
+
+ vec[0]= dia2*sin(phi);
+ vec[1]= dia2*cos(phi);
+ vec[2]= depth;
+ mul_m4_v3(mat, vec);
+ v2 = BM_Make_Vert(bm, vec, NULL);
+
+ BMO_SetFlag(bm, v1, VERT_MARK);
+ BMO_SetFlag(bm, v2, VERT_MARK);
+
+ if (a) {
+ if (cap_ends) {
+ BM_Make_QuadTri(bm, cent1, lastv1, v1, NULL, NULL, 0);
+ }
+ BM_Make_QuadTri(bm, lastv1, lastv2, v2, v1, NULL, 0);
+ } else {
+ firstv1 = v1;
+ firstv2 = v2;
+ }
+
+ lastv1 = v1;
+ lastv2 = v2;
+ }
+
+ if (!a)
+ return;
+
+ if (cap_ends) {
+ BM_Make_QuadTri(bm, cent1, firstv1, v1, NULL, NULL, 0);
+ }
+
+ BM_Make_QuadTri(bm, firstv1, firstv2, v2, v1, NULL, 0);
+
+ BMO_CallOpf(bm, "removedoubles verts=%fv dist=%f", VERT_MARK, 0.000001);
+ BMO_Flag_To_Slot(bm, op, "vertout", VERT_MARK, BM_VERT);
+}
+
+void bmesh_create_cube_exec(BMesh *bm, BMOperator *op)
+{
+ BMVert *v1, *v2, *v3, *v4, *v5, *v6, *v7, *v8;
+ float vec[3], mat[4][4], off = BMO_Get_Float(op, "size") / 2.0f;
+
+ BMO_Get_Mat4(op, "mat", mat);
+
+ if (!off) off = 0.5f;
+
+ vec[0] = -off;
+ vec[1] = -off;
+ vec[2] = -off;
+ mul_m4_v3(mat, vec);
+ v1 = BM_Make_Vert(bm, vec, NULL);
+ BMO_SetFlag(bm, v1, VERT_MARK);
+
+ vec[0] = -off;
+ vec[1] = off;
+ vec[2] = -off;
+ mul_m4_v3(mat, vec);
+ v2 = BM_Make_Vert(bm, vec, NULL);
+ BMO_SetFlag(bm, v2, VERT_MARK);
+
+ vec[0] = off;
+ vec[1] = off;
+ vec[2] = -off;
+ mul_m4_v3(mat, vec);
+ v3 = BM_Make_Vert(bm, vec, NULL);
+ BMO_SetFlag(bm, v3, VERT_MARK);
+
+ vec[0] = off;
+ vec[1] = -off;
+ vec[2] = -off;
+ mul_m4_v3(mat, vec);
+ v4 = BM_Make_Vert(bm, vec, NULL);
+ BMO_SetFlag(bm, v4, VERT_MARK);
+
+ vec[0] = -off;
+ vec[1] = -off;
+ vec[2] = off;
+ mul_m4_v3(mat, vec);
+ v5 = BM_Make_Vert(bm, vec, NULL);
+ BMO_SetFlag(bm, v5, VERT_MARK);
+
+ vec[0] = -off;
+ vec[1] = off;
+ vec[2] = off;
+ mul_m4_v3(mat, vec);
+ v6 = BM_Make_Vert(bm, vec, NULL);
+ BMO_SetFlag(bm, v6, VERT_MARK);
+
+ vec[0] = off;
+ vec[1] = off;
+ vec[2] = off;
+ mul_m4_v3(mat, vec);
+ v7 = BM_Make_Vert(bm, vec, NULL);
+ BMO_SetFlag(bm, v7, VERT_MARK);
+
+ vec[0] = off;
+ vec[1] = -off;
+ vec[2] = off;
+ mul_m4_v3(mat, vec);
+ v8 = BM_Make_Vert(bm, vec, NULL);
+ BMO_SetFlag(bm, v8, VERT_MARK);
+
+ /*the four sides*/
+ BM_Make_QuadTri(bm, v5, v6, v2, v1, NULL, 0);
+ BM_Make_QuadTri(bm, v6, v7, v3, v2, NULL, 0);
+ BM_Make_QuadTri(bm, v7, v8, v4, v3, NULL, 0);
+ BM_Make_QuadTri(bm, v8, v5, v1, v4, NULL, 0);
+
+ /*top/bottom*/
+ BM_Make_QuadTri(bm, v1, v2, v3, v4, NULL, 0);
+ BM_Make_QuadTri(bm, v8, v7, v6, v5, NULL, 0);
+
+ BMO_Flag_To_Slot(bm, op, "vertout", VERT_MARK, BM_VERT);
+}
diff --git a/source/blender/bmesh/operators/removedoubles.c b/source/blender/bmesh/operators/removedoubles.c
new file mode 100644
index 00000000000..f806fd33a6b
--- /dev/null
+++ b/source/blender/bmesh/operators/removedoubles.c
@@ -0,0 +1,610 @@
+#include "MEM_guardedalloc.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_utildefines.h"
+
+#include "BLI_math.h"
+#include "BLI_ghash.h"
+#include "BLI_blenlib.h"
+#include "BLI_array.h"
+#include "BLI_utildefines.h"
+
+#include "bmesh.h"
+#include "mesh_intern.h"
+#include "bmesh_private.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BL(ptr) ((BMLoop*)(ptr))
+
+void remdoubles_splitface(BMFace *f, BMesh *bm, BMOperator *op)
+{
+ BMIter liter;
+ BMLoop *l;
+ BMVert *v2, *doub;
+ int split=0;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ v2 = BMO_Get_MapPointer(bm, op, "targetmap", l->v);
+ /*ok: if v2 is NULL (e.g. not in the map) then it's
+ a target vert, otherwise it's a double*/
+ if (v2 && BM_Vert_In_Face(f, v2) && v2 != BL(l->prev)->v
+ && v2 != BL(l->next)->v)
+ {
+ doub = l->v;
+ split = 1;
+ break;
+ }
+ }
+
+ if (split && doub != v2) {
+ BMLoop *nl;
+ BMFace *f2 = BM_Split_Face(bm, f, doub, v2, &nl, NULL);
+
+ remdoubles_splitface(f, bm, op);
+ remdoubles_splitface(f2, bm, op);
+ }
+}
+
+#define ELE_DEL 1
+#define EDGE_COL 2
+#define FACE_MARK 2
+
+#if 0
+int remdoubles_face_overlaps(BMesh *bm, BMVert **varr,
+ int len, BMFace *exclude,
+ BMFace **overlapface)
+{
+ BMIter vertfaces;
+ BMFace *f;
+ int i, amount;
+
+ if (overlapface) *overlapface = NULL;
+
+ for(i=0; i < len; i++){
+ f = BMIter_New(&vertfaces, bm, BM_FACES_OF_VERT, varr[i] );
+ while(f){
+ amount = BM_Verts_In_Face(bm, f, varr, len);
+ if(amount >= len){
+ if (overlapface) *overlapface = f;
+ return 1;
+ }
+ f = BMIter_Step(&vertfaces);
+ }
+ }
+ return 0;
+}
+#endif
+
+void bmesh_weldverts_exec(BMesh *bm, BMOperator *op)
+{
+ BMIter iter, liter;
+ BMVert *v, *v2;
+ BMEdge *e, *e2, **edges = NULL;
+ BLI_array_declare(edges);
+ BMLoop *l, *l2, **loops = NULL;
+ BLI_array_declare(loops);
+ BMFace *f, *f2;
+ int a, b;
+
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMO_Get_MapPointer(bm, op, "targetmap", v))
+ BMO_SetFlag(bm, v, ELE_DEL);
+ }
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ remdoubles_splitface(f, bm, op);
+ }
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (BMO_TestFlag(bm, e->v1, ELE_DEL) || BMO_TestFlag(bm, e->v2, ELE_DEL)) {
+ v = BMO_Get_MapPointer(bm, op, "targetmap", e->v1);
+ v2 = BMO_Get_MapPointer(bm, op, "targetmap", e->v2);
+
+ if (!v) v = e->v1;
+ if (!v2) v2 = e->v2;
+
+ if (v == v2)
+ BMO_SetFlag(bm, e, EDGE_COL);
+ else if (!BM_Edge_Exist(v, v2))
+ BM_Make_Edge(bm, v, v2, e, 1);
+
+ BMO_SetFlag(bm, e, ELE_DEL);
+ }
+ }
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BMINDEX_SET(f, 0);
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ if (BMO_TestFlag(bm, l->v, ELE_DEL))
+ BMO_SetFlag(bm, f, FACE_MARK|ELE_DEL);
+ if (BMO_TestFlag(bm, l->e, EDGE_COL))
+ BMINDEX_SET(f, BMINDEX_GET(f)+1);
+ }
+ }
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMO_TestFlag(bm, f, FACE_MARK))
+ continue;
+
+ if (f->len - BMINDEX_GET(f) < 3) {
+ BMO_SetFlag(bm, f, ELE_DEL);
+ continue;
+ }
+
+ BLI_array_empty(edges);
+ BLI_array_empty(loops);
+ a = 0;
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ v = l->v;
+ v2 = BL(l->next)->v;
+ if (BMO_TestFlag(bm, v, ELE_DEL))
+ v = BMO_Get_MapPointer(bm, op, "targetmap", v);
+ if (BMO_TestFlag(bm, v2, ELE_DEL))
+ v2 = BMO_Get_MapPointer(bm, op, "targetmap", v2);
+
+ e2 = v != v2 ? BM_Edge_Exist(v, v2) : NULL;
+ if (e2) {
+ for (b=0; b<a; b++) {
+ if (edges[b] == e2)
+ break;
+ }
+ if (b != a)
+ continue;
+
+ BLI_array_growone(edges);
+ BLI_array_growone(loops);
+
+ edges[a] = e2;
+ loops[a] = l;
+
+ a++;
+ }
+ }
+
+ if (BLI_array_count(loops) < 3)
+ continue;
+
+ v = loops[0]->v;
+ v2 = loops[1]->v;
+
+ if (BMO_TestFlag(bm, v, ELE_DEL))
+ v = BMO_Get_MapPointer(bm, op, "targetmap", v);
+ if (BMO_TestFlag(bm, v2, ELE_DEL))
+ v2 = BMO_Get_MapPointer(bm, op, "targetmap", v2);
+
+ f2 = BM_Make_Ngon(bm, v2, v, edges, a, 0);
+ if (f2) {
+ BM_Copy_Attributes(bm, bm, f, f2);
+
+ a = 0;
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f2) {
+ l2 = loops[a];
+ BM_Copy_Attributes(bm, bm, l2, l);
+
+ a++;
+ }
+ }
+ }
+
+ BMO_CallOpf(bm, "del geom=%fvef context=%i", ELE_DEL, DEL_ONLYTAGGED);
+
+ BLI_array_free(edges);
+ BLI_array_free(loops);
+}
+
+static int vergaverco(const void *e1, const void *e2)
+{
+ const BMVert *v1 = *(void**)e1, *v2 = *(void**)e2;
+ float x1 = v1->co[0] + v1->co[1] + v1->co[2];
+ float x2 = v2->co[0] + v2->co[1] + v2->co[2];
+
+ if (x1 > x2) return 1;
+ else if (x1 < x2) return -1;
+ else return 0;
+}
+
+#define VERT_TESTED 1
+#define VERT_DOUBLE 2
+#define VERT_TARGET 4
+#define VERT_KEEP 8
+#define VERT_MARK 16
+#define VERT_IN 32
+
+#define EDGE_MARK 1
+
+void bmesh_pointmerge_facedata_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMIter iter;
+ BMVert *v, *snapv;
+ BMLoop *l, *firstl = NULL;
+ float fac;
+ int i, tot;
+
+ snapv = BMO_IterNew(&siter, bm, op, "snapv", BM_VERT);
+ tot = BM_Vert_FaceCount(snapv);
+
+ if (!tot)
+ return;
+
+ fac = 1.0f / tot;
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_VERT, snapv) {
+ if (!firstl) {
+ firstl = l;
+ }
+
+ for (i=0; i<bm->ldata.totlayer; i++) {
+ if (CustomData_layer_has_math(&bm->ldata, i)) {
+ int type = bm->ldata.layers[i].type;
+ void *e1, *e2;
+
+ e1 = CustomData_bmesh_get_layer_n(&bm->ldata, firstl->head.data, i);
+ e2 = CustomData_bmesh_get_layer_n(&bm->ldata, l->head.data, i);
+
+ CustomData_data_multiply(type, e2, fac);
+
+ if (l != firstl)
+ CustomData_data_add(type, e1, e2);
+ }
+ }
+ }
+
+ BMO_ITER(v, &siter, bm, op, "verts", BM_VERT) {
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_VERT, v) {
+ if (l == firstl)
+ continue;
+
+ CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, firstl->head.data, &l->head.data);
+ }
+ }
+}
+
+void bmesh_vert_average_facedata_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMIter iter;
+ BMVert *v;
+ BMLoop *l, *firstl = NULL;
+ CDBlockBytes min, max;
+ void *block;
+ int i, type;
+
+ for (i=0; i<bm->ldata.totlayer; i++) {
+ if (!CustomData_layer_has_math(&bm->ldata, i))
+ continue;
+
+ type = bm->ldata.layers[i].type;
+ CustomData_data_initminmax(type, &min, &max);
+
+ BMO_ITER(v, &siter, bm, op, "verts", BM_VERT) {
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_VERT, v) {
+ block = CustomData_bmesh_get_layer_n(&bm->ldata, l->head.data, i);
+ CustomData_data_dominmax(type, block, &min, &max);
+ }
+ }
+
+ CustomData_data_multiply(type, &min, 0.5f);
+ CustomData_data_multiply(type, &max, 0.5f);
+ CustomData_data_add(type, &min, &max);
+
+ BMO_ITER(v, &siter, bm, op, "verts", BM_VERT) {
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_VERT, v) {
+ block = CustomData_bmesh_get_layer_n(&bm->ldata, l->head.data, i);
+ CustomData_data_copy_value(type, &min, block);
+ }
+ }
+ }
+}
+
+void bmesh_pointmerge_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator weldop;
+ BMOIter siter;
+ BMVert *v, *snapv = NULL;
+ float vec[3];
+
+ BMO_Get_Vec(op, "mergeco", vec);
+
+ //BMO_CallOpf(bm, "collapse_uvs edges=%s", op, "edges");
+ BMO_Init_Op(&weldop, "weldverts");
+
+ BMO_ITER(v, &siter, bm, op, "verts", BM_VERT) {
+ if (!snapv) {
+ snapv = v;
+ copy_v3_v3(snapv->co, vec);
+ } else {
+ BMO_Insert_MapPointer(bm, &weldop, "targetmap", v, snapv);
+ }
+ }
+
+ BMO_Exec_Op(bm, &weldop);
+ BMO_Finish_Op(bm, &weldop);
+}
+
+void bmesh_collapse_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator weldop;
+ BMWalker walker;
+ BMIter iter;
+ BMEdge *e, **edges = NULL;
+ BLI_array_declare(edges);
+ float min[3], max[3];
+ int i, tot;
+
+ BMO_CallOpf(bm, "collapse_uvs edges=%s", op, "edges");
+ BMO_Init_Op(&weldop, "weldverts");
+
+ BMO_Flag_Buffer(bm, op, "edges", EDGE_MARK, BM_EDGE);
+ BMW_Init(&walker, bm, BMW_SHELL, EDGE_MARK, 0);
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BMO_TestFlag(bm, e, EDGE_MARK))
+ continue;
+
+ e = BMW_Begin(&walker, e->v1);
+ BLI_array_empty(edges);
+
+ INIT_MINMAX(min, max);
+ for (tot=0; e; tot++, e=BMW_Step(&walker)) {
+ BLI_array_growone(edges);
+ edges[tot] = e;
+
+ DO_MINMAX(e->v1->co, min, max);
+ DO_MINMAX(e->v2->co, min, max);
+ }
+
+ add_v3_v3v3(min, min, max);
+ mul_v3_fl(min, 0.5f);
+
+ /*snap edges to a point. for initial testing purposes anyway.*/
+ for (i=0; i<tot; i++) {
+ VECCOPY(edges[i]->v1->co, min);
+ VECCOPY(edges[i]->v2->co, min);
+
+ if (edges[i]->v1 != edges[0]->v1)
+ BMO_Insert_MapPointer(bm, &weldop, "targetmap", edges[i]->v1, edges[0]->v1);
+ if (edges[i]->v2 != edges[0]->v1)
+ BMO_Insert_MapPointer(bm, &weldop, "targetmap", edges[i]->v2, edges[0]->v1);
+ }
+ }
+
+ BMO_Exec_Op(bm, &weldop);
+ BMO_Finish_Op(bm, &weldop);
+
+ BMW_End(&walker);
+ BLI_array_free(edges);
+}
+
+/*uv collapse function*/
+void bmesh_collapsecon_do_layer(BMesh *bm, BMOperator *op, int layer)
+{
+ BMIter iter, liter;
+ BMFace *f;
+ BMLoop *l, *l2;
+ BMWalker walker;
+ void **blocks = NULL;
+ BLI_array_declare(blocks);
+ CDBlockBytes min, max;
+ int i, tot, type = bm->ldata.layers[layer].type;
+
+ BMO_Clear_Flag_All(bm, op, BM_ALL, 65535);
+
+ BMO_Flag_Buffer(bm, op, "edges", EDGE_MARK, BM_EDGE);
+ BMW_Init(&walker, bm, BMW_LOOPDATA_ISLAND, EDGE_MARK, layer);
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ if (BMO_TestFlag(bm, l->e, EDGE_MARK)) {
+ /*walk*/
+ BLI_array_empty(blocks);
+ tot = 0;
+ l2 = BMW_Begin(&walker, l);
+
+ CustomData_data_initminmax(type, &min, &max);
+ for (tot=0; l2; tot++, l2=BMW_Step(&walker)) {
+ BLI_array_growone(blocks);
+ blocks[tot] = CustomData_bmesh_get_layer_n(&bm->ldata, l2->head.data, layer);
+ CustomData_data_dominmax(type, blocks[tot], &min, &max);
+ }
+
+ if (tot) {
+ CustomData_data_multiply(type, &min, 0.5f);
+ CustomData_data_multiply(type, &max, 0.5f);
+ CustomData_data_add(type, &min, &max);
+
+ /*snap CD (uv, vcol) points to their centroid*/
+ for (i=0; i<tot; i++) {
+ CustomData_data_copy_value(type, &min, blocks[i]);
+ }
+ }
+ }
+ }
+ }
+
+ BMW_End(&walker);
+ BLI_array_free(blocks);
+}
+
+void bmesh_collapsecon_exec(BMesh *bm, BMOperator *op)
+{
+ int i;
+
+ for (i=0; i<bm->ldata.totlayer; i++) {
+ if (CustomData_layer_has_math(&bm->ldata, i))
+ bmesh_collapsecon_do_layer(bm, op, i);
+ }
+}
+
+void bmesh_removedoubles_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator weldop;
+ BMOIter oiter;
+ BMVert *v, *v2;
+ BMVert **verts=NULL;
+ BLI_array_declare(verts);
+ float dist, distsqr;
+ int i, j, len;
+
+ dist = BMO_Get_Float(op, "dist");
+ distsqr = dist*dist;
+
+ BMO_Init_Op(&weldop, "weldverts");
+
+ i = 0;
+ BMO_ITER(v, &oiter, bm, op, "verts", BM_VERT) {
+ BLI_array_growone(verts);
+ verts[i++] = v;
+ }
+
+ /*sort by vertex coordinates added together*/
+ qsort(verts, BLI_array_count(verts), sizeof(void*), vergaverco);
+
+ len = BLI_array_count(verts);
+ for (i=0; i<len; i++) {
+ v = verts[i];
+ if (BMO_TestFlag(bm, v, VERT_TESTED)) continue;
+
+ BMO_SetFlag(bm, v, VERT_TESTED);
+ for (j=i+1; j<len; j++) {
+ float vec[3];
+
+ v2 = verts[j];
+ //if ((v2->co[0]+v2->co[1]+v2->co[2]) - (v->co[0]+v->co[1]+v->co[2])
+ // > distsqr) break;
+ if ((v2->co[0]-v->co[0]) + (v2->co[1]-v->co[1]) + (v2->co[2]-v->co[2]) > distsqr*4.0f)
+ break;
+
+ vec[0] = v->co[0] - v2->co[0];
+ vec[1] = v->co[1] - v2->co[1];
+ vec[2] = v->co[2] - v2->co[2];
+
+ if (INPR(vec, vec) < distsqr) {
+ BMO_SetFlag(bm, v2, VERT_TESTED);
+ BMO_SetFlag(bm, v2, VERT_DOUBLE);
+ BMO_SetFlag(bm, v, VERT_TARGET);
+
+ BMO_Insert_MapPointer(bm, &weldop, "targetmap", v2, v);
+ }
+ }
+ }
+
+ BLI_array_free(verts);
+
+ BMO_Exec_Op(bm, &weldop);
+ BMO_Finish_Op(bm, &weldop);
+}
+
+
+void bmesh_finddoubles_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter oiter;
+ BMVert *v, *v2;
+ BMVert **verts=NULL;
+ BLI_array_declare(verts);
+ float dist, distsqr;
+ int i, j, len, keepvert;
+
+ dist = BMO_Get_Float(op, "dist");
+ distsqr = dist*dist;
+
+ i = 0;
+ BMO_ITER(v, &oiter, bm, op, "verts", BM_VERT) {
+ BLI_array_growone(verts);
+ verts[i++] = v;
+ }
+
+ keepvert = BMO_IterNew(&oiter, bm, op, "keepverts", BM_VERT) != NULL;
+
+ /*sort by vertex coordinates added together*/
+ qsort(verts, BLI_array_count(verts), sizeof(void*), vergaverco);
+
+ BMO_Flag_Buffer(bm, op, "keepverts", VERT_KEEP, BM_VERT);
+
+ len = BLI_array_count(verts);
+ for (i=0; i<len; i++) {
+ v = verts[i];
+ if (BMO_TestFlag(bm, v, VERT_DOUBLE)) continue;
+
+ for (j=i+1; j<len; j++) {
+ v2 = verts[j];
+ if ((v2->co[0]+v2->co[1]+v2->co[2]) - (v->co[0]+v->co[1]+v->co[2])
+ > distsqr) break;
+
+ if (keepvert) {
+ if (BMO_TestFlag(bm, v2, VERT_KEEP) == BMO_TestFlag(bm, v, VERT_KEEP))
+ continue;
+ }
+
+ if (compare_len_v3v3(v->co, v2->co, dist)) {
+ BMO_SetFlag(bm, v2, VERT_DOUBLE);
+ BMO_SetFlag(bm, v, VERT_TARGET);
+
+ BMO_Insert_MapPointer(bm, op, "targetmapout", v2, v);
+ }
+ }
+ }
+
+ BLI_array_free(verts);
+}
+
+void bmesh_automerge_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter oiter;
+ BMOperator weldop;
+ BMVert *v, *v2;
+ BMVert **verts=NULL;
+ BLI_array_declare(verts);
+ float dist, distsqr;
+ int i, j, len, keepvert;
+
+ dist = BMO_Get_Float(op, "dist");
+ distsqr = dist*dist;
+
+ i = 0;
+ BMO_ITER(v, &oiter, bm, op, "verts", BM_VERT) {
+ BLI_array_growone(verts);
+ verts[i++] = v;
+ }
+
+ BMO_Init_Op(&weldop, "weldverts");
+
+ /*sort by vertex coordinates added together*/
+ qsort(verts, BLI_array_count(verts), sizeof(void*), vergaverco);
+
+ BMO_Flag_Buffer(bm, op, "verts", VERT_KEEP, BM_VERT);
+
+ len = BLI_array_count(verts);
+ for (i=0; i<len; i++) {
+ v = verts[i];
+ if (BMO_TestFlag(bm, v, VERT_DOUBLE)) continue;
+
+ for (j=i+1; j<len; j++) {
+ v2 = verts[j];
+ if ((v2->co[0]+v2->co[1]+v2->co[2]) - (v->co[0]+v->co[1]+v->co[2])
+ > distsqr) break;
+
+ /* only allow unselected -> selected */
+ if (BMO_TestFlag(bm, v2, VERT_IN))
+ continue;
+
+ if (compare_len_v3v3(v->co, v2->co, dist)) {
+ BMO_SetFlag(bm, v2, VERT_DOUBLE);
+ BMO_SetFlag(bm, v, VERT_TARGET);
+
+ BMO_Insert_MapPointer(bm, &weldop, "targetmap", v2, v);
+ }
+ }
+ }
+
+ BMO_Exec_Op(bm, &weldop);
+ BMO_Finish_Op(bm, &weldop);
+
+ BLI_array_free(verts);
+}
diff --git a/source/blender/bmesh/operators/subdivideop.c b/source/blender/bmesh/operators/subdivideop.c
new file mode 100644
index 00000000000..f6833f8727b
--- /dev/null
+++ b/source/blender/bmesh/operators/subdivideop.c
@@ -0,0 +1,1075 @@
+/**
+ * $Id:
+ *
+ * ***** 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
+
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
+#include "BLI_array.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_object_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "ED_mesh.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include "mesh_intern.h"
+#include "subdivideop.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+/*flags for all elements share a common bitfield space*/
+#define SUBD_SPLIT 1
+
+#define EDGE_PERCENT 2
+
+/*I don't think new faces are flagged, currently, but
+ better safe than sorry.*/
+#define FACE_NEW 4
+#define FACE_CUSTOMFILL 8
+#define ELE_INNER 16
+#define ELE_SPLIT 32
+#define ELE_CONNECT 64
+
+/*stuff for the flag paramter. note that
+ what used to live in "beauty" and
+ in "seltype" live here. still have to
+ convert the beauty flags over, which
+ is why it starts at 128 (to avoid
+ collision).*/
+#define SELTYPE_INNER 128
+
+/*
+NOTE: beauty has been renamed to flag!
+*/
+
+/*generic subdivision rules:
+
+ * two selected edges in a face should make a link
+ between them.
+
+ * one edge should do, what? make pretty topology, or just
+ split the edge only?
+*/
+
+/*connects face with smallest len, which I think should always be correct for
+ edge subdivision*/
+BMEdge *connect_smallest_face(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf) {
+ BMIter iter, iter2;
+ BMVert *v;
+ BMLoop *nl;
+ BMFace *face, *curf = NULL;
+
+ /*this isn't the best thing in the world. it doesn't handle cases where there's
+ multiple faces yet. that might require a convexity test to figure out which
+ face is "best," and who knows what for non-manifold conditions.*/
+ for (face = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v1); face; face=BMIter_Step(&iter)) {
+ for (v=BMIter_New(&iter2, bm, BM_VERTS_OF_FACE, face); v; v=BMIter_Step(&iter2)) {
+ if (v == v2) {
+ if (!curf || face->len < curf->len) curf = face;
+ }
+ }
+ }
+
+ if (curf) {
+ face = BM_Split_Face(bm, curf, v1, v2, &nl, NULL);
+
+ if (nf) *nf = face;
+ return nl ? nl->e : NULL;
+ }
+
+ return NULL;
+}
+/* calculates offset for co, based on fractal, sphere or smooth settings */
+static void alter_co(float *co, BMEdge *edge, subdparams *params, float perc,
+ BMVert *vsta, BMVert *vend)
+{
+ float vec1[3], fac;
+
+ if(params->beauty & B_SMOOTH) {
+ /* we calculate an offset vector vec1[], to be added to *co */
+ float len, fac, nor[3], nor1[3], nor2[3], smooth=params->smooth;
+
+ sub_v3_v3v3(nor, vsta->co, vend->co);
+ len= 0.5f*normalize_v3(nor);
+
+ copy_v3_v3(nor1, vsta->no);
+ copy_v3_v3(nor2, vend->no);
+
+ /* cosine angle */
+ fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ;
+
+ vec1[0]= fac*nor1[0];
+ vec1[1]= fac*nor1[1];
+ vec1[2]= fac*nor1[2];
+
+ /* cosine angle */
+ fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ;
+
+ vec1[0]+= fac*nor2[0];
+ vec1[1]+= fac*nor2[1];
+ vec1[2]+= fac*nor2[2];
+
+ /* falloff for multi subdivide */
+ smooth *= sqrt(fabs(1.0f - 2.0f*fabs(perc)));
+
+ vec1[0]*= smooth*len;
+ vec1[1]*= smooth*len;
+ vec1[2]*= smooth*len;
+
+ co[0] += vec1[0];
+ co[1] += vec1[1];
+ co[2] += vec1[2];
+ }
+ else if(params->beauty & B_SPHERE) { /* subdivide sphere */
+ normalize_v3(co);
+ co[0]*= params->smooth;
+ co[1]*= params->smooth;
+ co[2]*= params->smooth;
+ }
+
+ if(params->beauty & B_FRACTAL) {
+ fac= params->fractal*len_v3v3(vsta->co, vend->co);
+ vec1[0]= fac*(float)(0.5-BLI_drand());
+ vec1[1]= fac*(float)(0.5-BLI_drand());
+ vec1[2]= fac*(float)(0.5-BLI_drand());
+ add_v3_v3v3(co, co, vec1);
+ }
+}
+
+/* assumes in the edge is the correct interpolated vertices already */
+/* percent defines the interpolation, rad and flag are for special options */
+/* results in new vertex with correct coordinate, vertex normal and weight group info */
+static BMVert *bm_subdivide_edge_addvert(BMesh *bm, BMEdge *edge,BMEdge *oedge,
+ subdparams *params, float percent,
+ float percent2,
+ BMEdge **out,BMVert *vsta,BMVert *vend)
+{
+ BMVert *ev;
+// float co[3];
+
+ ev = BM_Split_Edge(bm, edge->v1, edge, out, percent);
+ BM_Vert_UpdateNormal(bm, ev);
+
+ BMO_SetFlag(bm, ev, ELE_INNER);
+
+ /* offset for smooth or sphere or fractal */
+ alter_co(ev->co, oedge, params, percent2, vsta, vend);
+
+#if 0 //TODO
+ /* clip if needed by mirror modifier */
+ if (edge->v1->f2) {
+ if ( edge->v1->f2 & edge->v2->f2 & 1) {
+ co[0]= 0.0f;
+ }
+ if ( edge->v1->f2 & edge->v2->f2 & 2) {
+ co[1]= 0.0f;
+ }
+ if ( edge->v1->f2 & edge->v2->f2 & 4) {
+ co[2]= 0.0f;
+ }
+ }
+#endif
+
+ return ev;
+}
+
+static BMVert *subdivideedgenum(BMesh *bm, BMEdge *edge, BMEdge *oedge,
+ int curpoint, int totpoint, subdparams *params,
+ BMEdge **newe, BMVert *vsta, BMVert *vend)
+{
+ BMVert *ev;
+ float percent, percent2 = 0.0f;
+
+ if (BMO_TestFlag(bm, edge, EDGE_PERCENT) && totpoint == 1)
+ percent = BMO_Get_MapFloat(bm, params->op,
+ "edgepercents", edge);
+ else {
+ percent= 1.0f/(float)(totpoint+1-curpoint);
+ percent2 = (float)curpoint / (float)(totpoint + 1);
+
+ }
+
+ ev= bm_subdivide_edge_addvert(bm, edge, oedge, params, percent,
+ percent2, newe, vsta, vend);
+ return ev;
+}
+
+static void bm_subdivide_multicut(BMesh *bm, BMEdge *edge, subdparams *params,
+ BMVert *vsta, BMVert *vend) {
+ BMEdge *eed = edge, *newe, temp = *edge;
+ BMVert *v;
+ int i, numcuts = params->numcuts;
+
+ for(i=0;i<numcuts;i++) {
+ v = subdivideedgenum(bm, eed, &temp, i, params->numcuts, params,
+ &newe, vsta, vend);
+ BMO_SetFlag(bm, v, SUBD_SPLIT);
+ BMO_SetFlag(bm, eed, SUBD_SPLIT);
+ BMO_SetFlag(bm, newe, SUBD_SPLIT);
+
+ BMO_SetFlag(bm, v, ELE_SPLIT);
+ BMO_SetFlag(bm, eed, ELE_SPLIT);
+ BMO_SetFlag(bm, newe, SUBD_SPLIT);
+
+ CHECK_ELEMENT(bm, v);
+ if (v->e) CHECK_ELEMENT(bm, v->e);
+ if (v->e && v->e->l) CHECK_ELEMENT(bm, v->e->l->f);
+ }
+}
+
+/*note: the patterns are rotated as necassary to
+ match the input geometry. they're based on the
+ pre-split state of the face*/
+
+/*
+
+v3---------v2
+| |
+| |
+| |
+| |
+v4---v0---v1
+
+*/
+static void quad_1edge_split(BMesh *bm, BMFace *UNUSED(face),
+ BMVert **verts, subdparams *params) {
+ BMFace *nf;
+ int i, add, numcuts = params->numcuts;
+
+ /*if it's odd, the middle face is a quad, otherwise it's a triangle*/
+ if (numcuts % 2==0) {
+ add = 2;
+ for (i=0; i<numcuts; i++) {
+ if (i == numcuts/2) add -= 1;
+ connect_smallest_face(bm, verts[i], verts[numcuts+add],
+ &nf);
+ }
+ } else {
+ add = 2;
+ for (i=0; i<numcuts; i++) {
+ connect_smallest_face(bm, verts[i], verts[numcuts+add],
+ &nf);
+ if (i == numcuts/2) {
+ add -= 1;
+ connect_smallest_face(bm, verts[i],
+ verts[numcuts+add],
+ &nf);
+ }
+ }
+
+ }
+}
+
+subdpattern quad_1edge = {
+ {1, 0, 0, 0},
+ quad_1edge_split,
+ 4,
+};
+
+
+/*
+v6--------v5
+| |
+| |v4s
+| |v3s
+| s s |
+v7-v0--v1-v2
+
+*/
+static void quad_2edge_split_path(BMesh *bm, BMFace *UNUSED(face), BMVert **verts,
+ subdparams *params)
+{
+ BMFace *nf;
+ int i, numcuts = params->numcuts;
+
+ for (i=0; i<numcuts; i++) {
+ connect_smallest_face(bm, verts[i], verts[numcuts+(numcuts-i)],
+ &nf);
+ }
+ connect_smallest_face(bm, verts[numcuts*2+3], verts[numcuts*2+1], &nf);
+}
+
+subdpattern quad_2edge_path = {
+ {1, 1, 0, 0},
+ quad_2edge_split_path,
+ 4,
+};
+
+/*
+v6--------v5
+| |
+| |v4s
+| |v3s
+| s s |
+v7-v0--v1-v2
+
+*/
+static void quad_2edge_split_innervert(BMesh *bm, BMFace *UNUSED(face), BMVert **verts,
+ subdparams *params)
+{
+ BMFace *nf;
+ BMVert *v, *lastv;
+ BMEdge *e, *ne;
+ int i, numcuts = params->numcuts;
+
+ lastv = verts[numcuts];
+
+ for (i=numcuts-1; i>=0; i--) {
+ e = connect_smallest_face(bm, verts[i], verts[numcuts+(numcuts-i)],
+ &nf);
+
+ v = BM_Split_Edge(bm, e->v1, e, &ne, 0.5f);
+ connect_smallest_face(bm, lastv, v, &nf);
+ lastv = v;
+ }
+
+ connect_smallest_face(bm, lastv, verts[numcuts*2+2], &nf);
+}
+
+subdpattern quad_2edge_innervert = {
+ {1, 1, 0, 0},
+ quad_2edge_split_innervert,
+ 4,
+};
+
+/*
+v6--------v5
+| |
+| |v4s
+| |v3s
+| s s |
+v7-v0--v1-v2
+
+*/
+static void quad_2edge_split_fan(BMesh *bm, BMFace *face, BMVert **verts,
+ subdparams *params)
+{
+ BMFace *nf;
+ BMVert *v, *lastv;
+ BMEdge *e, *ne;
+ int i, numcuts = params->numcuts;
+
+ lastv = verts[2];
+
+ for (i=0; i<numcuts; i++) {
+ connect_smallest_face(bm, verts[i], verts[numcuts*2+2], &nf);
+ connect_smallest_face(bm, verts[numcuts+(numcuts-i)],
+ verts[numcuts*2+2], &nf);
+ }
+}
+
+subdpattern quad_2edge_fan = {
+ {1, 1, 0, 0},
+ quad_2edge_split_fan,
+ 4,
+};
+
+/* s s
+v8--v7--v6-v5
+| |
+| v4 s
+| |
+| v3 s
+| s s |
+v9-v0--v1-v2
+
+*/
+static void quad_3edge_split(BMesh *bm, BMFace *face, BMVert **verts,
+ subdparams *params)
+{
+ BMFace *nf;
+ int i, add=0, numcuts = params->numcuts;
+
+ for (i=0; i<numcuts; i++) {
+ if (i == numcuts/2) {
+ if (numcuts % 2 != 0) {
+ connect_smallest_face(bm, verts[numcuts-i-1+add],
+ verts[i+numcuts+1], &nf);
+ }
+ add = numcuts*2+2;
+ }
+ connect_smallest_face(bm, verts[numcuts-i-1+add],
+ verts[i+numcuts+1], &nf);
+ }
+
+ for (i=0; i<numcuts/2+1; i++) {
+ connect_smallest_face(bm, verts[i],verts[(numcuts-i)+numcuts*2+1],
+ &nf);
+ }
+}
+
+subdpattern quad_3edge = {
+ {1, 1, 1, 0},
+ quad_3edge_split,
+ 4,
+};
+
+/*
+
+ v8--v7-v6--v5
+ | s |
+ |v9 s s|v4
+first line | | last line
+ |v10s s s|v3
+ v11-v0--v1-v2
+
+ it goes from bottom up
+*/
+static void quad_4edge_subdivide(BMesh *bm, BMFace *face, BMVert **verts,
+ subdparams *params)
+{
+ BMFace *nf;
+ BMVert *v, *v1, *v2;
+ BMEdge *e, *ne, temp;
+ BMVert **lines;
+ int numcuts = params->numcuts;
+ int i, j, a, b, s=numcuts+2, totv=numcuts*4+4;
+
+ lines = MEM_callocN(sizeof(BMVert*)*(numcuts+2)*(numcuts+2),
+ "q_4edge_split");
+ /*build a 2-dimensional array of verts,
+ containing every vert (and all new ones)
+ in the face.*/
+
+ /*first line*/
+ for (i=0; i<numcuts+2; i++) {
+ lines[i] = verts[numcuts*3+2+(numcuts-i+1)];
+ }
+
+ /*last line*/
+ for (i=0; i<numcuts+2; i++) {
+ lines[(s-1)*s+i] = verts[numcuts+i];
+ }
+
+ /*first and last members of middle lines*/
+ for (i=0; i<numcuts; i++) {
+ a = i;
+ b = numcuts + 1 + numcuts + 1 + (numcuts - i - 1);
+
+ e = connect_smallest_face(bm, verts[a], verts[b], &nf);
+ if (!e)
+ continue;
+
+ BMO_SetFlag(bm, e, ELE_INNER);
+ BMO_SetFlag(bm, nf, ELE_INNER);
+
+
+ v1 = lines[(i+1)*s] = verts[a];
+ v2 = lines[(i+1)*s + s-1] = verts[b];
+
+ temp = *e;
+ for (a=0; a<numcuts; a++) {
+ v = subdivideedgenum(bm, e, &temp, a, numcuts, params, &ne,
+ v1, v2);
+ if (!v)
+ bmesh_error();
+
+ BMO_SetFlag(bm, ne, ELE_INNER);
+ lines[(i+1)*s+a+1] = v;
+ }
+ }
+
+ for (i=1; i<numcuts+2; i++) {
+ for (j=1; j<numcuts+1; j++) {
+ a = i*s + j;
+ b = (i-1)*s + j;
+ e = connect_smallest_face(bm, lines[a], lines[b], &nf);
+ if (!e)
+ continue;
+
+ BMO_SetFlag(bm, e, ELE_INNER);
+ BMO_SetFlag(bm, nf, ELE_INNER);
+ }
+ }
+
+ MEM_freeN(lines);
+}
+
+/* v3
+ / \
+ / \
+ / \
+ / \
+ / \
+v4--v0--v1--v2
+ s s
+*/
+static void tri_1edge_split(BMesh *bm, BMFace *face, BMVert **verts,
+ subdparams *params)
+{
+ BMFace *nf;
+ int i, numcuts = params->numcuts;
+
+ for (i=0; i<numcuts; i++) {
+ connect_smallest_face(bm, verts[i], verts[numcuts+1], &nf);
+ }
+}
+
+subdpattern tri_1edge = {
+ {1, 0, 0},
+ tri_1edge_split,
+ 3,
+};
+
+/* v5
+ / \
+ s v6/---\ v4 s
+ / \ / \
+sv7/---v---\ v3 s
+ / \/ \/ \
+ v8--v0--v1--v2
+ s s
+*/
+static void tri_3edge_subdivide(BMesh *bm, BMFace *face, BMVert **verts,
+ subdparams *params)
+{
+ BMFace *nf;
+ BMEdge *e, *ne, temp;
+ BMVert ***lines, *v;
+ void *stackarr[1];
+ int i, j, a, b, numcuts = params->numcuts;
+
+ /*number of verts in each line*/
+ lines = MEM_callocN(sizeof(void*)*(numcuts+2), "triangle vert table");
+
+ lines[0] = (BMVert**) stackarr;
+ lines[0][0] = verts[numcuts*2+1];
+
+ lines[1+numcuts] = MEM_callocN(sizeof(void*)*(numcuts+2),
+ "triangle vert table 2");
+ for (i=0; i<numcuts; i++) {
+ lines[1+numcuts][1+i] = verts[i];
+ }
+ lines[1+numcuts][0] = verts[numcuts*3+2];
+ lines[1+numcuts][1+numcuts] = verts[numcuts];
+
+ for (i=0; i<numcuts; i++) {
+ lines[i+1] = MEM_callocN(sizeof(void*)*(2+i),
+ "triangle vert table row");
+ a = numcuts*2 + 2 + i;
+ b = numcuts + numcuts - i;
+ e = connect_smallest_face(bm, verts[a], verts[b], &nf);
+ if (!e) goto cleanup;
+
+ BMO_SetFlag(bm, e, ELE_INNER);
+ BMO_SetFlag(bm, nf, ELE_INNER);
+
+ lines[i+1][0] = verts[a];
+ lines[i+1][1+i] = verts[b];
+
+ temp = *e;
+ for (j=0; j<i; j++) {
+ v = subdivideedgenum(bm, e, &temp, j, i, params, &ne,
+ verts[a], verts[b]);
+ lines[i+1][j+1] = v;
+
+ BMO_SetFlag(bm, ne, ELE_INNER);
+ }
+ }
+
+
+/* v5
+ / \
+ s v6/---\ v4 s
+ / \ / \
+sv7/---v---\ v3 s
+ / \/ \/ \
+ v8--v0--v1--v2
+ s s
+*/
+ for (i=1; i<numcuts+1; i++) {
+ for (j=0; j<i; j++) {
+ e= connect_smallest_face(bm, lines[i][j], lines[i+1][j+1],
+ &nf);
+
+ BMO_SetFlag(bm, e, ELE_INNER);
+ BMO_SetFlag(bm, nf, ELE_INNER);
+
+ e= connect_smallest_face(bm,lines[i][j+1],lines[i+1][j+1],
+ &nf);
+
+ BMO_SetFlag(bm, e, ELE_INNER);
+ BMO_SetFlag(bm, nf, ELE_INNER);
+ }
+ }
+
+cleanup:
+ for (i=1; i<numcuts+2; i++) {
+ if (lines[i]) MEM_freeN(lines[i]);
+ }
+
+ MEM_freeN(lines);
+}
+
+subdpattern tri_3edge = {
+ {1, 1, 1},
+ tri_3edge_subdivide,
+ 3,
+};
+
+
+subdpattern quad_4edge = {
+ {1, 1, 1, 1},
+ quad_4edge_subdivide,
+ 4,
+};
+
+subdpattern *patterns[] = {
+ NULL, //quad single edge pattern is inserted here
+ NULL, //quad corner vert pattern is inserted here
+ NULL, //tri single edge pattern is inserted here
+ NULL,
+ &quad_3edge,
+ NULL,
+};
+
+#define PLEN (sizeof(patterns) / sizeof(void*))
+
+typedef struct subd_facedata {
+ BMVert *start; subdpattern *pat;
+ int totedgesel; //only used if pat was NULL, e.g. no pattern was found
+ BMFace *face;
+} subd_facedata;
+
+void esubdivide_exec(BMesh *bmesh, BMOperator *op)
+{
+ BMOpSlot *einput;
+ BMEdge *edge, **edges = NULL;
+ BLI_array_declare(edges);
+ BMFace *face;
+ BMLoop *nl;
+ BMVert **verts = NULL;
+ BLI_array_declare(verts);
+ BMIter fiter, liter;
+ subdpattern *pat;
+ subdparams params;
+ subd_facedata *facedata = NULL;
+ BLI_array_declare(facedata);
+ BMLoop *l, **splits = NULL, **loops = NULL;
+ BLI_array_declare(splits);
+ BLI_array_declare(loops);
+ float smooth, fractal;
+ int beauty, cornertype, singleedge, gridfill;
+ int i, j, matched, a, b, numcuts, totesel;
+
+ BMO_Flag_Buffer(bmesh, op, "edges", SUBD_SPLIT, BM_EDGE);
+
+ numcuts = BMO_Get_Int(op, "numcuts");
+ smooth = BMO_Get_Float(op, "smooth");
+ fractal = BMO_Get_Float(op, "fractal");
+ beauty = BMO_Get_Int(op, "beauty");
+ cornertype = BMO_Get_Int(op, "quadcornertype");
+ singleedge = BMO_Get_Int(op, "singleedge");
+ gridfill = BMO_Get_Int(op, "gridfill");
+
+ patterns[1] = NULL;
+ //straight cut is patterns[1] == NULL
+ switch (cornertype) {
+ case SUBD_PATH:
+ patterns[1] = &quad_2edge_path;
+ break;
+ case SUBD_INNERVERT:
+ patterns[1] = &quad_2edge_innervert;
+ break;
+ case SUBD_FAN:
+ patterns[1] = &quad_2edge_fan;
+ break;
+ }
+
+ if (singleedge) {
+ patterns[0] = &quad_1edge;
+ patterns[2] = &tri_1edge;
+ } else {
+ patterns[0] = NULL;
+ patterns[2] = NULL;
+ }
+
+ if (gridfill) {
+ patterns[3] = &quad_4edge;
+ patterns[5] = &tri_3edge;
+ } else {
+ patterns[3] = NULL;
+ patterns[5] = NULL;
+ }
+
+ /*first go through and tag edges*/
+ BMO_Flag_To_Slot(bmesh, op, "edges",
+ SUBD_SPLIT, BM_EDGE);
+
+ params.numcuts = numcuts;
+ params.op = op;
+ params.smooth = smooth;
+ params.fractal = fractal;
+ params.beauty = beauty;
+
+ BMO_Mapping_To_Flag(bmesh, op, "custompatterns",
+ FACE_CUSTOMFILL);
+
+ BMO_Mapping_To_Flag(bmesh, op, "edgepercents",
+ EDGE_PERCENT);
+
+ for (face=BMIter_New(&fiter, bmesh, BM_FACES_OF_MESH, NULL);
+ face; face=BMIter_Step(&fiter)) {
+ BMEdge *e1 = NULL, *e2 = NULL;
+ float vec1[3], vec2[3];
+
+ /*figure out which pattern to use*/
+
+ BLI_array_empty(edges);
+ BLI_array_empty(verts);
+ matched = 0;
+
+ i = 0;
+ totesel = 0;
+ for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
+ nl; nl=BMIter_Step(&liter)) {
+ BLI_array_growone(edges);
+ BLI_array_growone(verts);
+ edges[i] = nl->e;
+ verts[i] = nl->v;
+
+ if (BMO_TestFlag(bmesh, edges[i], SUBD_SPLIT)) {
+ if (!e1) e1 = edges[i];
+ else e2 = edges[i];
+
+ totesel++;
+ }
+
+ i++;
+ }
+
+ /*make sure the two edges have a valid angle to each other*/
+ if (totesel == 2 && (e1->v1 == e2->v1 || e1->v1 == e2->v2
+ || e1->v2 == e2->v1 || e1->v2 == e2->v1)) {
+ float angle;
+
+ sub_v3_v3v3(vec1, e1->v2->co, e1->v1->co);
+ sub_v3_v3v3(vec2, e2->v2->co, e2->v1->co);
+ normalize_v3(vec1);
+ normalize_v3(vec2);
+
+ angle = INPR(vec1, vec2);
+ angle = ABS(angle);
+ if (ABS(angle-1.0) < 0.01)
+ totesel = 0;
+ }
+
+ if (BMO_TestFlag(bmesh, face, FACE_CUSTOMFILL)) {
+ pat = BMO_Get_MapData(bmesh, op,
+ "custompatterns", face);
+ for (i=0; i<pat->len; i++) {
+ matched = 1;
+ for (j=0; j<pat->len; j++) {
+ a = (j + i) % pat->len;
+ if ((!!BMO_TestFlag(bmesh, edges[a], SUBD_SPLIT))
+ != (!!pat->seledges[j])) {
+ matched = 0;
+ break;
+ }
+ }
+ if (matched) {
+ BLI_array_growone(facedata);
+ b = BLI_array_count(facedata)-1;
+ facedata[b].pat = pat;
+ facedata[b].start = verts[i];
+ facedata[b].face = face;
+ facedata[b].totedgesel = totesel;
+ BMO_SetFlag(bmesh, face, SUBD_SPLIT);
+ break;
+ }
+ }
+
+ /*obvously don't test for other patterns matching*/
+ continue;
+ }
+
+ for (i=0; i<PLEN; i++) {
+ pat = patterns[i];
+ if (!pat) continue;
+
+ if (pat->len == face->len) {
+ for (a=0; a<pat->len; a++) {
+ matched = 1;
+ for (b=0; b<pat->len; b++) {
+ j = (b + a) % pat->len;
+ if ((!!BMO_TestFlag(bmesh, edges[j], SUBD_SPLIT))
+ != (!!pat->seledges[b])) {
+ matched = 0;
+ break;
+ }
+ }
+ if (matched) break;
+ }
+ if (matched) {
+ BLI_array_growone(facedata);
+ j = BLI_array_count(facedata) - 1;
+
+ BMO_SetFlag(bmesh, face, SUBD_SPLIT);
+
+ facedata[j].pat = pat;
+ facedata[j].start = verts[a];
+ facedata[j].face = face;
+ facedata[j].totedgesel = totesel;
+ break;
+ }
+ }
+
+ }
+
+ if (!matched && totesel) {
+ BLI_array_growone(facedata);
+ j = BLI_array_count(facedata) - 1;
+
+ BMO_SetFlag(bmesh, face, SUBD_SPLIT);
+ facedata[j].totedgesel = totesel;
+ facedata[j].face = face;
+ }
+ }
+
+ einput = BMO_GetSlot(op, "edges");
+
+ /*go through and split edges*/
+ for (i=0; i<einput->len; i++) {
+ edge = ((BMEdge**)einput->data.p)[i];
+ bm_subdivide_multicut(bmesh, edge, &params, edge->v1, edge->v2);
+ }
+
+ i = 0;
+ for (i=0; i<BLI_array_count(facedata); i++) {
+ face = facedata[i].face;
+
+ /*figure out which pattern to use*/
+ BLI_array_empty(verts);
+
+ pat = facedata[i].pat;
+
+ if (!pat && facedata[i].totedgesel == 2) {
+ int vlen;
+
+ /*ok, no pattern. we still may be able to do something.*/
+ BLI_array_empty(loops);
+ BLI_array_empty(splits);
+
+ /*for case of two edges, connecting them shouldn't be too hard*/
+ BM_ITER(l, &liter, bmesh, BM_LOOPS_OF_FACE, face) {
+ BLI_array_growone(loops);
+ loops[BLI_array_count(loops)-1] = l;
+ }
+
+ vlen = BLI_array_count(loops);
+
+ /*find the boundary of one of the split edges*/
+ for (a=1; a<vlen; a++) {
+ if (!BMO_TestFlag(bmesh, loops[a-1]->v, ELE_INNER)
+ && BMO_TestFlag(bmesh, loops[a]->v, ELE_INNER))
+ break;
+ }
+
+ if (BMO_TestFlag(bmesh, loops[(a+numcuts+1)%vlen]->v, ELE_INNER)) {
+ b = (a+numcuts+1)%vlen;
+ } else {
+ /*find the boundary of the other edge.*/
+ for (j=0; j<vlen; j++) {
+ b = (j + a + numcuts + 1) % vlen;
+ if (!BMO_TestFlag(bmesh, loops[b==0 ? vlen-1 : b-1]->v, ELE_INNER)
+ && BMO_TestFlag(bmesh, loops[b]->v, ELE_INNER))
+ break;
+ }
+ }
+
+ b += numcuts - 1;
+
+ for (j=0; j<numcuts; j++) {
+ BLI_array_growone(splits);
+ splits[BLI_array_count(splits)-1] = loops[a];
+
+ BLI_array_growone(splits);
+ splits[BLI_array_count(splits)-1] = loops[b];
+
+ b = (b-1) % vlen;
+ a = (a+1) % vlen;
+ }
+
+ //BM_LegalSplits(bmesh, face, splits, BLI_array_count(splits)/2);
+
+ for (j=0; j<BLI_array_count(splits)/2; j++) {
+ if (splits[j*2]) {
+ BMFace *nf;
+
+ nf = BM_Split_Face(bmesh, face, splits[j*2]->v, splits[j*2+1]->v, &nl, NULL);
+ }
+ }
+
+ continue;
+ } else if (!pat) {
+ continue;
+ }
+
+ j = a = 0;
+ for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
+ nl; nl=BMIter_Step(&liter)) {
+ if (nl->v == facedata[i].start) {
+ a = j+1;
+ break;
+ }
+ j++;
+ }
+
+ for (j=0; j<face->len; j++) {
+ BLI_array_growone(verts);
+ }
+
+ j = 0;
+ for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
+ nl; nl=BMIter_Step(&liter)) {
+ b = (j-a+face->len) % face->len;
+ verts[b] = nl->v;
+ j += 1;
+ }
+
+ CHECK_ELEMENT(bmesh, face);
+ pat->connectexec(bmesh, face, verts, &params);
+ }
+
+ if (facedata) BLI_array_free(facedata);
+ if (edges) BLI_array_free(edges);
+ if (verts) BLI_array_free(verts);
+ BLI_array_free(splits);
+ BLI_array_free(loops);
+
+ BMO_Flag_To_Slot(bmesh, op, "outinner",
+ ELE_INNER, BM_ALL);
+ BMO_Flag_To_Slot(bmesh, op, "outsplit",
+ ELE_SPLIT, BM_ALL);
+
+ BMO_Flag_To_Slot(bmesh, op, "geomout",
+ ELE_INNER|ELE_SPLIT|SUBD_SPLIT, BM_ALL);
+}
+
+/*editmesh-emulating function*/
+void BM_esubdivideflag(Object *obedit, BMesh *bm, int flag, float smooth,
+ float fractal, int beauty, int numcuts,
+ int seltype, int cornertype, int singleedge, int gridfill)
+{
+ BMOperator op;
+
+ BMO_InitOpf(bm, &op, "esubd edges=%he smooth=%f fractal=%f "
+ "beauty=%d numcuts=%d quadcornertype=%d singleedge=%d "
+ "gridfill=%d",
+ flag, smooth, fractal, beauty, numcuts,
+ cornertype, singleedge, gridfill);
+
+ BMO_Exec_Op(bm, &op);
+
+ if (seltype == SUBDIV_SELECT_INNER) {
+ BMOIter iter;
+ BMHeader *ele;
+ int i;
+
+ ele = BMO_IterNew(&iter, bm, &op, "outinner", BM_EDGE|BM_VERT);
+ for (; ele; ele=BMO_IterStep(&iter)) {
+ BM_Select(bm, ele, 1);
+ }
+ } else if (seltype == SUBDIV_SELECT_LOOPCUT) {
+ BMOIter iter;
+ BMHeader *ele;
+ int i;
+
+ /*deselect input*/
+ BM_clear_flag_all(bm, BM_SELECT);
+
+ ele = BMO_IterNew(&iter, bm, &op, "outinner", BM_EDGE|BM_VERT);
+ for (; ele; ele=BMO_IterStep(&iter)) {
+ BM_Select(bm, ele, 1);
+
+ if (ele->type == BM_VERT) {
+ BMEdge *e;
+ BMIter eiter;
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, ele) {
+ if (!BM_TestHFlag(e, BM_SELECT) && BM_TestHFlag(e->v1, BM_SELECT)
+ && BM_TestHFlag(e->v2, BM_SELECT)) {
+ BM_SetHFlag(e, BM_SELECT);
+ bm->totedgesel += 1;
+ } else if (BM_TestHFlag(e, BM_SELECT) && (!BM_TestHFlag(e->v1, BM_SELECT)
+ || !BM_TestHFlag(e->v2, BM_SELECT))) {
+ BM_ClearHFlag(e, BM_SELECT);
+ bm->totedgesel -= 1;
+ }
+ }
+ }
+ }
+ }
+
+ BMO_Finish_Op(bm, &op);
+}
+
+#if 0
+void BM_esubdivideflag_conv(Object *obedit,EditMesh *em,int selflag, float rad,
+ int flag, int numcuts, int seltype) {
+ BMesh *bm = editmesh_to_bmesh(em);
+ EditMesh *em2;
+
+ BM_esubdivideflag(obedit, bm, selflag, rad, flag, numcuts, seltype);
+ em2 = bmesh_to_editmesh(bm);
+
+ free_editMesh(em);
+ *em = *em2;
+ MEM_freeN(em2);
+ BM_Free_Mesh(bm);
+}
+#endif
+
+void esplit_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMEdge *e;
+ subdparams params;
+
+ params.numcuts = BMO_GetSlot(op, "numcuts")->data.i;
+ params.op = op;
+
+ /*go through and split edges*/
+ BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
+ bm_subdivide_multicut(bm, e, &params, e->v1, e->v2);
+ }
+
+ BMO_Flag_To_Slot(bm, op, "outsplit",
+ ELE_SPLIT, BM_ALL);
+}
+
diff --git a/source/blender/bmesh/operators/subdivideop.h b/source/blender/bmesh/operators/subdivideop.h
new file mode 100644
index 00000000000..7bb471117d8
--- /dev/null
+++ b/source/blender/bmesh/operators/subdivideop.h
@@ -0,0 +1,38 @@
+#ifndef _SUBDIVIDEOP_H
+#define _SUBDIVIDEOP_H
+
+typedef struct subdparams {
+ int numcuts;
+ float smooth;
+ float fractal;
+ int beauty;
+ BMOperator *op;
+} subdparams;
+
+typedef void (*subd_pattern_fill_fp)(BMesh *bm, BMFace *face, BMVert **verts,
+ subdparams *params);
+
+/*
+note: this is a pattern-based edge subdivider.
+it tries to match a pattern to edge selections on faces,
+then executes functions to cut them.
+*/
+typedef struct subdpattern {
+ int seledges[20]; //selected edges mask, for splitting
+
+ /*verts starts at the first new vert cut, not the first vert in the
+ face*/
+ subd_pattern_fill_fp connectexec;
+ int len; /*total number of verts, before any subdivision*/
+} subdpattern;
+
+/*generic subdivision rules:
+
+ * two selected edges in a face should make a link
+ between them.
+
+ * one edge should do, what? make pretty topology, or just
+ split the edge only?
+*/
+
+#endif /* _SUBDIVIDEOP_H */ \ No newline at end of file
diff --git a/source/blender/bmesh/operators/triangulateop.c b/source/blender/bmesh/operators/triangulateop.c
new file mode 100644
index 00000000000..c4755b38d29
--- /dev/null
+++ b/source/blender/bmesh/operators/triangulateop.c
@@ -0,0 +1,56 @@
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+#include "BLI_math.h"
+#include "BLI_array.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define EDGE_NEW 1
+#define FACE_NEW 1
+
+void triangulate_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMFace *face, **newfaces = NULL;
+ BLI_array_declare(newfaces);
+ float (*projectverts)[3] = NULL;
+ BLI_array_declare(projectverts);
+ int i, lastlen=0, count = 0;
+
+ face = BMO_IterNew(&siter, bm, op, "faces", BM_FACE);
+ for (; face; face=BMO_IterStep(&siter)) {
+ if (lastlen < face->len) {
+ BLI_array_empty(projectverts);
+ BLI_array_empty(newfaces);
+ for (lastlen=0; lastlen<face->len; lastlen++) {
+ BLI_array_growone(projectverts);
+ BLI_array_growone(projectverts);
+ BLI_array_growone(projectverts);
+ BLI_array_growone(newfaces);
+ }
+ }
+
+ BM_Triangulate_Face(bm, face, projectverts, EDGE_NEW,
+ FACE_NEW, newfaces);
+
+ BMO_Insert_MapPointer(bm, op, "facemap",
+ face, face);
+ for (i=0; newfaces[i]; i++) {
+ BMO_Insert_MapPointer(bm, op, "facemap",
+ newfaces[i], face);
+
+ }
+ }
+
+ BMO_Flag_To_Slot(bm, op, "edgeout", EDGE_NEW, BM_EDGE);
+ BMO_Flag_To_Slot(bm, op, "faceout", FACE_NEW, BM_FACE);
+
+ BLI_array_free(projectverts);
+ BLI_array_free(newfaces);
+} \ No newline at end of file
diff --git a/source/blender/bmesh/operators/utils.c b/source/blender/bmesh/operators/utils.c
new file mode 100644
index 00000000000..83d97280ef0
--- /dev/null
+++ b/source/blender/bmesh/operators/utils.c
@@ -0,0 +1,1300 @@
+#include "MEM_guardedalloc.h"
+#include "BKE_customdata.h"
+#include "DNA_listBase.h"
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include <string.h>
+#include "BKE_utildefines.h"
+#include "BKE_mesh.h"
+#include "BKE_global.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
+
+#include "BLI_editVert.h"
+#include "mesh_intern.h"
+#include "ED_mesh.h"
+
+#include "BLI_math.h"
+#include "BLI_array.h"
+#include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
+
+#include "BLI_heap.h"
+
+#include "bmesh.h"
+
+/*
+ * UTILS.C
+ *
+ * utility bmesh operators, e.g. transform,
+ * translate, rotate, scale, etc.
+ *
+*/
+
+void bmesh_makevert_exec(BMesh *bm, BMOperator *op)
+{
+ float vec[3];
+
+ BMO_Get_Vec(op, "co", vec);
+
+ BMO_SetFlag(bm, BM_Make_Vert(bm, vec, NULL), 1);
+ BMO_Flag_To_Slot(bm, op, "newvertout", 1, BM_VERT);
+}
+
+void bmesh_transform_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter iter;
+ BMVert *v;
+ float mat[4][4];
+
+ BMO_Get_Mat4(op, "mat", mat);
+
+ BMO_ITER(v, &iter, bm, op, "verts", BM_VERT) {
+ mul_m4_v3(mat, v->co);
+ }
+}
+
+void bmesh_translate_exec(BMesh *bm, BMOperator *op)
+{
+ float mat[4][4], vec[3];
+
+ BMO_Get_Vec(op, "vec", vec);
+
+ unit_m4(mat);
+ copy_v3_v3(mat[3], vec);
+
+ BMO_CallOpf(bm, "transform mat=%m4 verts=%s", mat, op, "verts");
+}
+
+void bmesh_scale_exec(BMesh *bm, BMOperator *op)
+{
+ float mat[3][3], vec[3];
+
+ BMO_Get_Vec(op, "vec", vec);
+
+ unit_m3(mat);
+ mat[0][0] = vec[0];
+ mat[1][1] = vec[1];
+ mat[2][2] = vec[2];
+
+ BMO_CallOpf(bm, "transform mat=%m3 verts=%s", mat, op, "verts");
+}
+
+void bmesh_rotate_exec(BMesh *bm, BMOperator *op)
+{
+ float vec[3];
+
+ BMO_Get_Vec(op, "cent", vec);
+
+ /*there has to be a proper matrix way to do this, but
+ this is how editmesh did it and I'm too tired to think
+ through the math right now.*/
+ mul_v3_fl(vec, -1);
+ BMO_CallOpf(bm, "translate verts=%s vec=%v", op, "verts", vec);
+
+ BMO_CallOpf(bm, "transform mat=%s verts=%s", op, "mat", op, "verts");
+
+ mul_v3_fl(vec, -1);
+ BMO_CallOpf(bm, "translate verts=%s vec=%v", op, "verts", vec);
+}
+
+void bmesh_reversefaces_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMFace *f;
+
+ BMO_ITER(f, &siter, bm, op, "faces", BM_FACE) {
+ BM_flip_normal(bm, f);
+ }
+}
+
+void bmesh_edgerotate_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMEdge *e, *e2;
+ int ccw = BMO_Get_Int(op, "ccw");
+
+ BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
+ if (!(e2 = BM_Rotate_Edge(bm, e, ccw))) {
+ BMO_RaiseError(bm, op, BMERR_INVALID_SELECTION, "Could not rotate edge");
+ return;
+ }
+
+ BMO_SetFlag(bm, e2, 1);
+ }
+
+ BMO_Flag_To_Slot(bm, op, "edgeout", 1, BM_EDGE);
+}
+
+#define SEL_FLAG 1
+#define SEL_ORIG 2
+
+static void bmesh_regionextend_extend(BMesh *bm, BMOperator *op, int usefaces)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMIter eiter;
+ BMOIter siter;
+
+ if (!usefaces) {
+ BMO_ITER(v, &siter, bm, op, "geom", BM_VERT) {
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ if (!BMO_TestFlag(bm, e, SEL_ORIG))
+ break;
+ }
+
+ if (e) {
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ BMO_SetFlag(bm, e, SEL_FLAG);
+ BMO_SetFlag(bm, BM_OtherEdgeVert(e, v), SEL_FLAG);
+ }
+ }
+ }
+ } else {
+ BMIter liter, fiter;
+ BMFace *f, *f2;
+ BMLoop *l;
+
+ BMO_ITER(f, &siter, bm, op, "geom", BM_FACE) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ BM_ITER(f2, &fiter, bm, BM_FACES_OF_EDGE, l->e) {
+ if (!BMO_TestFlag(bm, f2, SEL_ORIG))
+ BMO_SetFlag(bm, f2, SEL_FLAG);
+ }
+ }
+ }
+ }
+}
+
+static void bmesh_regionextend_constrict(BMesh *bm, BMOperator *op, int usefaces)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMIter eiter;
+ BMOIter siter;
+
+ if (!usefaces) {
+ BMO_ITER(v, &siter, bm, op, "geom", BM_VERT) {
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ if (!BMO_TestFlag(bm, e, SEL_ORIG))
+ break;
+ }
+
+ if (e) {
+ BMO_SetFlag(bm, v, SEL_FLAG);
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ BMO_SetFlag(bm, e, SEL_FLAG);
+ }
+ }
+ }
+ } else {
+ BMIter liter, fiter;
+ BMFace *f, *f2;
+ BMLoop *l;
+
+ BMO_ITER(f, &siter, bm, op, "geom", BM_FACE) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ BM_ITER(f2, &fiter, bm, BM_FACES_OF_EDGE, l->e) {
+ if (!BMO_TestFlag(bm, f2, SEL_ORIG)) {
+ BMO_SetFlag(bm, f, SEL_FLAG);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+void bmesh_regionextend_exec(BMesh *bm, BMOperator *op)
+{
+ int usefaces = BMO_Get_Int(op, "usefaces");
+ int constrict = BMO_Get_Int(op, "constrict");
+
+ BMO_Flag_Buffer(bm, op, "geom", SEL_ORIG, BM_ALL);
+
+ if (constrict)
+ bmesh_regionextend_constrict(bm, op, usefaces);
+ else
+ bmesh_regionextend_extend(bm, op, usefaces);
+
+ BMO_Flag_To_Slot(bm, op, "geomout", SEL_FLAG, BM_ALL);
+}
+
+/********* righthand faces implementation ********/
+
+#define FACE_VIS 1
+#define FACE_FLAG 2
+#define FACE_MARK 4
+
+/* NOTE: these are the original righthandfaces comment in editmesh_mods.c,
+ copied here for reference.
+*/
+ /* based at a select-connected to witness loose objects */
+
+ /* count per edge the amount of faces */
+
+ /* find the ultimate left, front, upper face (not manhattan dist!!) */
+ /* also evaluate both triangle cases in quad, since these can be non-flat */
+
+ /* put normal to the outside, and set the first direction flags in edges */
+
+ /* then check the object, and set directions / direction-flags: but only for edges with 1 or 2 faces */
+ /* this is in fact the 'select connected' */
+
+ /* in case (selected) faces were not done: start over with 'find the ultimate ...' */
+
+/*note: this function uses recursion, which is a little unusual for a bmop
+ function, but acceptable I think.*/
+void bmesh_righthandfaces_exec(BMesh *bm, BMOperator *op)
+{
+ BMIter liter, liter2;
+ BMOIter siter;
+ BMFace *f, *startf, **fstack = NULL;
+ BLI_array_declare(fstack);
+ BMLoop *l, *l2;
+ float maxx, cent[3];
+ int i, maxi;
+
+ startf= NULL;
+ maxx= -1.0e10;
+
+ BMO_Flag_Buffer(bm, op, "faces", FACE_FLAG, BM_FACE);
+
+ /*find a starting face*/
+ BMO_ITER(f, &siter, bm, op, "faces", BM_FACE) {
+ if (BMO_TestFlag(bm, f, FACE_VIS))
+ continue;
+
+ if (!startf) startf = f;
+
+ BM_Compute_Face_Center(bm, f, cent);
+
+ cent[0] = cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2];
+ if (cent[0] > maxx) {
+ maxx = cent[0];
+ startf = f;
+ }
+ }
+
+ if (!startf) return;
+
+ BM_Compute_Face_Center(bm, startf, cent);
+
+ /*make sure the starting face has the correct winding*/
+ if (cent[0]*startf->no[0] + cent[1]*startf->no[1] + cent[2]*startf->no[2] < 0.0)
+ BM_flip_normal(bm, startf);
+
+ /*now that we've found our starting face, make all connected faces
+ have the same winding. this is done recursively, using a manual
+ stack (if we use simple function recursion, we'd end up overloading
+ the stack on large meshes).*/
+
+ BLI_array_growone(fstack);
+ fstack[0] = startf;
+ BMO_SetFlag(bm, startf, FACE_VIS);
+
+ i = 0;
+ maxi = 1;
+ while (i >= 0) {
+ f = fstack[i];
+ i--;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ BM_ITER(l2, &liter2, bm, BM_LOOPS_OF_LOOP, l) {
+ if (!BMO_TestFlag(bm, l2->f, FACE_FLAG) || l2 == l)
+ continue;
+
+ if (!BMO_TestFlag(bm, l2->f, FACE_VIS)) {
+ BMO_SetFlag(bm, l2->f, FACE_VIS);
+ i++;
+
+ if (l2->v == l->v)
+ BM_flip_normal(bm, l2->f);
+
+ if (i == maxi) {
+ BLI_array_growone(fstack);
+ maxi++;
+ }
+
+ fstack[i] = l2->f;
+ }
+ }
+ }
+ }
+
+ BLI_array_free(fstack);
+
+ /*check if we have faces yet to do. if so, recurse.*/
+ BMO_ITER(f, &siter, bm, op, "faces", BM_FACE) {
+ if (!BMO_TestFlag(bm, f, FACE_VIS)) {
+ bmesh_righthandfaces_exec(bm, op);
+ break;
+ }
+ }
+}
+
+void bmesh_vertexsmooth_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMIter iter;
+ BMVert *v;
+ BMEdge *e;
+ BLI_array_declare(cos);
+ float (*cos)[3] = NULL;
+ float *co, *co2, clipdist = BMO_Get_Float(op, "clipdist");
+ int i, j, clipx, clipy, clipz;
+
+ clipx = BMO_Get_Int(op, "mirror_clip_x");
+ clipy = BMO_Get_Int(op, "mirror_clip_y");
+ clipz = BMO_Get_Int(op, "mirror_clip_z");
+
+ i = 0;
+ BMO_ITER(v, &siter, bm, op, "verts", BM_VERT) {
+ BLI_array_growone(cos);
+ co = cos[i];
+
+ j = 0;
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
+ co2 = BM_OtherEdgeVert(e, v)->co;
+ add_v3_v3v3(co, co, co2);
+ j += 1;
+ }
+
+ if (!j) {
+ copy_v3_v3(co, v->co);
+ i++;
+ continue;
+ }
+
+ co[0] /= (float)j;
+ co[1] /= (float)j;
+ co[2] /= (float)j;
+
+ co[0] = v->co[0]*0.5 + co[0]*0.5;
+ co[1] = v->co[1]*0.5 + co[1]*0.5;
+ co[2] = v->co[2]*0.5 + co[2]*0.5;
+
+ if (clipx && fabs(v->co[0]) < clipdist)
+ co[0] = 0.0f;
+ if (clipy && fabs(v->co[1]) < clipdist)
+ co[1] = 0.0f;
+ if (clipz && fabs(v->co[2]) < clipdist)
+ co[2] = 0.0f;
+
+ i++;
+ }
+
+ i = 0;
+ BMO_ITER(v, &siter, bm, op, "verts", BM_VERT) {
+ copy_v3_v3(v->co, cos[i]);
+ i++;
+ }
+
+ BLI_array_free(cos);
+}
+
+/*
+** compute the centroid of an ngon
+**
+** NOTE: This should probably go to bmesh_polygon.c and replace the function that compute its center
+** basing on bounding box
+*/
+static void ngon_center(float *v, BMesh *bm, BMFace *f)
+{
+ BMIter liter;
+ BMLoop *l;
+ v[0] = v[1] = v[2] = 0;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ add_v3_v3v3(v, v, l->v->co);
+ }
+
+ if( f->len )
+ {
+ v[0] /= f->len;
+ v[1] /= f->len;
+ v[2] /= f->len;
+ }
+}
+
+/*
+** compute the perimeter of an ngon
+**
+** NOTE: This should probably go to bmesh_polygon.c
+*/
+static float ngon_perimeter(BMesh *bm, BMFace *f)
+{
+ BMIter liter;
+ BMLoop *l;
+ int num_verts = 0;
+ float v[3], sv[3];
+ float perimeter = 0.0f;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ if( num_verts == 0 ) {
+ sv[0] = v[0] = l->v->co[0];
+ sv[1] = v[1] = l->v->co[1];
+ sv[2] = v[2] = l->v->co[2];
+ num_verts++;
+ } else {
+ perimeter += len_v3v3(v, l->v->co);
+ v[0] = l->v->co[0];
+ v[1] = l->v->co[1];
+ v[2] = l->v->co[2];
+ num_verts++;
+ }
+ }
+
+ perimeter += len_v3v3(v, sv);
+
+ return perimeter;
+}
+
+/*
+** compute the fake surface of an ngon
+** This is done by decomposing the ngon into triangles who share the centroid of the ngon
+** while this method is far from being exact, it should garantee an invariance.
+**
+** NOTE: This should probably go to bmesh_polygon.c
+*/
+static float ngon_fake_area(BMesh *bm, BMFace *f)
+{
+ BMIter liter;
+ BMLoop *l;
+ int num_verts = 0;
+ float v[3], sv[3], c[3];
+ float area = 0.0f;
+
+ ngon_center(c, bm, f);
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ if( num_verts == 0 ) {
+ sv[0] = v[0] = l->v->co[0];
+ sv[1] = v[1] = l->v->co[1];
+ sv[2] = v[2] = l->v->co[2];
+ num_verts++;
+ } else {
+ area += area_tri_v3(v, c, l->v->co);
+ v[0] = l->v->co[0];
+ v[1] = l->v->co[1];
+ v[2] = l->v->co[2];
+ num_verts++;
+ }
+ }
+
+ area += area_tri_v3(v, c, sv);
+
+ return area;
+}
+
+/*
+** extra face data (computed data)
+*/
+typedef struct tmp_face_ext {
+ BMFace *f; /* the face */
+ float c[3]; /* center */
+ union {
+ float area; /* area */
+ float perim; /* perimeter */
+ float d; /* 4th component of plane (the first three being the normal) */
+ struct Image *t; /* image pointer */
+ };
+} tmp_face_ext;
+
+/*
+** Select similar faces, the choices are in the enum in source/blender/bmesh/bmesh_operators.h
+** We select either similar faces based on material, image, area, perimeter, normal, or the coplanar faces
+*/
+void bmesh_similarfaces_exec(BMesh *bm, BMOperator *op)
+{
+ BMIter fm_iter;
+ BMFace *fs, *fm;
+ BMOIter fs_iter;
+ int num_sels = 0, num_total = 0, i = 0, idx = 0;
+ float angle = 0.0f;
+ tmp_face_ext *f_ext = NULL;
+ int *indices = NULL;
+ float t_no[3]; /* temporary normal */
+ int type = BMO_Get_Int(op, "type");
+ float thresh = BMO_Get_Float(op, "thresh");
+
+ num_total = BM_Count_Element(bm, BM_FACE);
+
+ /*
+ ** The first thing to do is to iterate through all the the selected items and mark them since
+ ** they will be in the selection anyway.
+ ** This will increase performance, (especially when the number of originaly selected faces is high)
+ ** so the overall complexity will be less than $O(mn)$ where is the total number of selected faces,
+ ** and n is the total number of faces
+ */
+ BMO_ITER(fs, &fs_iter, bm, op, "faces", BM_FACE) {
+ if (!BMO_TestFlag(bm, fs, FACE_MARK)) { /* is this really needed ? */
+ BMO_SetFlag(bm, fs, FACE_MARK);
+ num_sels++;
+ }
+ }
+
+ /* allocate memory for the selected faces indices and for all temporary faces */
+ indices = (int*)MEM_callocN(sizeof(int) * num_sels, "face indices util.c");
+ f_ext = (tmp_face_ext*)MEM_callocN(sizeof(tmp_face_ext) * num_total, "f_ext util.c");
+
+ /* loop through all the faces and fill the faces/indices structure */
+ BM_ITER(fm, &fm_iter, bm, BM_FACES_OF_MESH, NULL) {
+ f_ext[i].f = fm;
+ if (BMO_TestFlag(bm, fm, FACE_MARK)) {
+ indices[idx] = i;
+ idx++;
+ }
+ i++;
+ }
+
+ /*
+ ** Save us some computation burden: In case of perimeter/area/coplanar selection we compute
+ ** only once.
+ */
+ if( type == SIMFACE_PERIMETER || type == SIMFACE_AREA || type == SIMFACE_COPLANAR || type == SIMFACE_IMAGE ) {
+ for( i = 0; i < num_total; i++ ) {
+ switch( type ) {
+ case SIMFACE_PERIMETER:
+ /* set the perimeter */
+ f_ext[i].perim = ngon_perimeter(bm, f_ext[i].f);
+ break;
+
+ case SIMFACE_COPLANAR:
+ /* compute the center of the polygon */
+ ngon_center(f_ext[i].c, bm, f_ext[i].f);
+
+ /* normalize the polygon normal */
+ copy_v3_v3(t_no, f_ext[i].f->no);
+ normalize_v3(t_no);
+
+ /* compute the plane distance */
+ f_ext[i].d = dot_v3v3(t_no, f_ext[i].c);
+ break;
+
+ case SIMFACE_AREA:
+ f_ext[i].area = ngon_fake_area(bm, f_ext[i].f);
+ break;
+
+ case SIMFACE_IMAGE:
+ f_ext[i].t = NULL;
+ if( CustomData_has_layer(&(bm->pdata), CD_MTEXPOLY) ) {
+ MTexPoly *mtpoly = CustomData_bmesh_get(&bm->pdata, f_ext[i].f->head.data, CD_MTEXPOLY);
+ f_ext[i].t = mtpoly->tpage;
+ }
+ break;
+ }
+ }
+ }
+
+ /* now select the rest (if any) */
+ for( i = 0; i < num_total; i++ ) {
+ fm = f_ext[i].f;
+ if( !BMO_TestFlag(bm, fm, FACE_MARK) && !BM_TestHFlag(fm, BM_HIDDEN) ) {
+ int cont = 1;
+ for( idx = 0; idx < num_sels && cont == 1; idx++ ) {
+ fs = f_ext[indices[idx]].f;
+ switch( type ) {
+ case SIMFACE_MATERIAL:
+ if( fm->mat_nr == fs->mat_nr ) {
+ BMO_SetFlag(bm, fm, FACE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMFACE_IMAGE:
+ if( f_ext[i].t == f_ext[indices[idx]].t ) {
+ BMO_SetFlag(bm, fm, FACE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMFACE_NORMAL:
+ angle = RAD2DEG(angle_v2v2(fs->no, fm->no)); /* if the angle between the normals -> 0 */
+ if( angle / 180.0 <= thresh ) {
+ BMO_SetFlag(bm, fm, FACE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMFACE_COPLANAR:
+ angle = RAD2DEG(angle_v2v2(fs->no, fm->no)); /* angle -> 0 */
+ if( angle / 180.0 <= thresh ) { /* and dot product difference -> 0 */
+ if( fabs(f_ext[i].d - f_ext[indices[idx]].d) <= thresh ) {
+ BMO_SetFlag(bm, fm, FACE_MARK);
+ cont = 0;
+ }
+ }
+ break;
+
+ case SIMFACE_AREA:
+ if( fabs(f_ext[i].area - f_ext[indices[idx]].area) <= thresh ) {
+ BMO_SetFlag(bm, fm, FACE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMFACE_PERIMETER:
+ if( fabs(f_ext[i].perim - f_ext[indices[idx]].perim) <= thresh ) {
+ BMO_SetFlag(bm, fm, FACE_MARK);
+ cont = 0;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ MEM_freeN(f_ext);
+ MEM_freeN(indices);
+
+ /* transfer all marked faces to the output slot */
+ BMO_Flag_To_Slot(bm, op, "faceout", FACE_MARK, BM_FACE);
+}
+
+/******************************************************************************
+** Similar Edges
+******************************************************************************/
+#define EDGE_MARK 1
+
+/*
+** compute the angle of an edge (i.e. the angle between two faces)
+*/
+static float edge_angle(BMesh *bm, BMEdge *e)
+{
+ BMIter fiter;
+ BMFace *f;
+ int num_faces = 0;
+ float n1[3], n2[3];
+ float angle = 0.0f;
+
+ BM_ITER(f, &fiter, bm, BM_FACES_OF_EDGE, e) {
+ if( num_faces == 0 ) {
+ n1[0] = f->no[0];
+ n1[1] = f->no[1];
+ n1[2] = f->no[2];
+ num_faces++;
+ } else {
+ n2[0] = f->no[0];
+ n2[1] = f->no[1];
+ n2[2] = f->no[2];
+ num_faces++;
+ }
+ }
+
+ angle = angle_v2v2(n1, n2);
+
+ return angle;
+}
+/*
+** extra edge information
+*/
+typedef struct tmp_edge_ext {
+ BMEdge *e;
+ union {
+ float dir[3];
+ float angle; /* angle between the faces*/
+ };
+
+ union {
+ float length; /* edge length */
+ int faces; /* faces count */
+ };
+} tmp_edge_ext;
+
+/*
+** select similar edges: the choices are in the enum in source/blender/bmesh/bmesh_operators.h
+** choices are length, direction, face, ...
+*/
+void bmesh_similaredges_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter es_iter; /* selected edges iterator */
+ BMIter e_iter; /* mesh edges iterator */
+ BMEdge *es; /* selected edge */
+ BMEdge *e; /* mesh edge */
+ int idx = 0, i = 0, f = 0;
+ int *indices = NULL;
+ tmp_edge_ext *e_ext = NULL;
+ float *angles = NULL;
+ float angle;
+
+ int num_sels = 0, num_total = 0;
+ int type = BMO_Get_Int(op, "type");
+ float thresh = BMO_Get_Float(op, "thresh");
+
+ num_total = BM_Count_Element(bm, BM_EDGE);
+
+ /* iterate through all selected edges and mark them */
+ BMO_ITER(es, &es_iter, bm, op, "edges", BM_EDGE) {
+ BMO_SetFlag(bm, es, EDGE_MARK);
+ num_sels++;
+ }
+
+ /* allocate memory for the selected edges indices and for all temporary edges */
+ indices = (int*)MEM_callocN(sizeof(int) * num_sels, "indices util.c");
+ e_ext = (tmp_edge_ext*)MEM_callocN(sizeof(tmp_edge_ext) * num_total, "e_ext util.c");
+
+ /* loop through all the edges and fill the edges/indices structure */
+ BM_ITER(e, &e_iter, bm, BM_EDGES_OF_MESH, NULL) {
+ e_ext[i].e = e;
+ if (BMO_TestFlag(bm, e, EDGE_MARK)) {
+ indices[idx] = i;
+ idx++;
+ }
+ i++;
+ }
+
+ /* save us some computation time by doing heavy computation once */
+ if( type == SIMEDGE_LENGTH || type == SIMEDGE_FACE || type == SIMEDGE_DIR ||
+ type == SIMEDGE_FACE_ANGLE ) {
+ for( i = 0; i < num_total; i++ ) {
+ switch( type ) {
+ case SIMEDGE_LENGTH: /* compute the length of the edge */
+ e_ext[i].length = len_v3v3(e_ext[i].e->v1->co, e_ext[i].e->v2->co);
+ break;
+
+ case SIMEDGE_DIR: /* compute the direction */
+ sub_v3_v3v3(e_ext[i].dir, e_ext[i].e->v1->co, e_ext[i].e->v2->co);
+ break;
+
+ case SIMEDGE_FACE: /* count the faces around the edge */
+ e_ext[i].faces = BM_Edge_FaceCount(e_ext[i].e);
+ break;
+
+ case SIMEDGE_FACE_ANGLE:
+ e_ext[i].faces = BM_Edge_FaceCount(e_ext[i].e);
+ if( e_ext[i].faces == 2 )
+ e_ext[i].angle = edge_angle(bm, e_ext[i].e);
+ break;
+ }
+ }
+ }
+
+ /* select the edges if any */
+ for( i = 0; i < num_total; i++ ) {
+ e = e_ext[i].e;
+ if( !BMO_TestFlag(bm, e, EDGE_MARK) && !BM_TestHFlag(e, BM_HIDDEN) ) {
+ int cont = 1;
+ for( idx = 0; idx < num_sels && cont == 1; idx++ ) {
+ es = e_ext[indices[idx]].e;
+ switch( type ) {
+ case SIMEDGE_LENGTH:
+ if( fabs(e_ext[i].length - e_ext[indices[idx]].length) <= thresh ) {
+ BMO_SetFlag(bm, e, EDGE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMEDGE_DIR:
+ /* compute the angle between the two edges */
+ angle = RAD2DEG(angle_v2v2(e_ext[i].dir, e_ext[indices[idx]].dir));
+
+ if( angle > 90.0 ) /* use the smallest angle between the edges */
+ angle = fabs(angle - 180.0f);
+
+ if( angle / 90.0 <= thresh ) {
+ BMO_SetFlag(bm, e, EDGE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMEDGE_FACE:
+ if( e_ext[i].faces == e_ext[indices[idx]].faces ) {
+ BMO_SetFlag(bm, e, EDGE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMEDGE_FACE_ANGLE:
+ if( e_ext[i].faces == 2 ) {
+ if( e_ext[indices[idx]].faces == 2 ) {
+ if( fabs(e_ext[i].angle - e_ext[indices[idx]].angle) <= thresh ) {
+ BMO_SetFlag(bm, e, EDGE_MARK);
+ cont = 0;
+ }
+ }
+ } else cont = 0;
+ break;
+
+ case SIMEDGE_CREASE:
+ if (CustomData_has_layer(&bm->edata, CD_CREASE)) {
+ float *c1, *c2;
+
+ c1 = CustomData_bmesh_get(&bm->edata, e->head.data, CD_CREASE);
+ c2 = CustomData_bmesh_get(&bm->edata, es->head.data, CD_CREASE);
+
+ if( c1&&c2 && fabs(*c1 - *c2) <= thresh ) {
+ BMO_SetFlag(bm, e, EDGE_MARK);
+ cont = 0;
+ }
+ }
+ break;
+
+ case SIMEDGE_SEAM:
+ if( BM_TestHFlag(e, BM_SEAM) == BM_TestHFlag(es, BM_SEAM) ) {
+ BMO_SetFlag(bm, e, EDGE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMEDGE_SHARP:
+ if( BM_TestHFlag(e, BM_SHARP) == BM_TestHFlag(es, BM_SHARP) ) {
+ BMO_SetFlag(bm, e, EDGE_MARK);
+ cont = 0;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ MEM_freeN(e_ext);
+ MEM_freeN(indices);
+
+ /* transfer all marked edges to the output slot */
+ BMO_Flag_To_Slot(bm, op, "edgeout", EDGE_MARK, BM_EDGE);
+}
+
+/******************************************************************************
+** Similar Vertices
+******************************************************************************/
+#define VERT_MARK 1
+
+typedef struct tmp_vert_ext {
+ BMVert *v;
+ union {
+ int num_faces; /* adjacent faces */
+ MDeformVert *dvert; /* deform vertex */
+ };
+} tmp_vert_ext;
+
+/*
+** select similar vertices: the choices are in the enum in source/blender/bmesh/bmesh_operators.h
+** choices are normal, face, vertex group...
+*/
+void bmesh_similarverts_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter vs_iter; /* selected verts iterator */
+ BMIter v_iter; /* mesh verts iterator */
+ BMVert *vs; /* selected vertex */
+ BMVert *v; /* mesh vertex */
+ tmp_vert_ext *v_ext = NULL;
+ int *indices = NULL;
+ int num_total = 0, num_sels = 0, i = 0, idx = 0;
+ int type = BMO_Get_Int(op, "type");
+ float thresh = BMO_Get_Float(op, "thresh");
+
+ num_total = BM_Count_Element(bm, BM_VERT);
+
+ /* iterate through all selected edges and mark them */
+ BMO_ITER(vs, &vs_iter, bm, op, "verts", BM_VERT) {
+ BMO_SetFlag(bm, vs, VERT_MARK);
+ num_sels++;
+ }
+
+ /* allocate memory for the selected vertices indices and for all temporary vertices */
+ indices = (int*)MEM_mallocN(sizeof(int) * num_sels, "vertex indices");
+ v_ext = (tmp_vert_ext*)MEM_mallocN(sizeof(tmp_vert_ext) * num_total, "vertex extra");
+
+ /* loop through all the vertices and fill the vertices/indices structure */
+ BM_ITER(v, &v_iter, bm, BM_VERTS_OF_MESH, NULL) {
+ v_ext[i].v = v;
+ if (BMO_TestFlag(bm, v, VERT_MARK)) {
+ indices[idx] = i;
+ idx++;
+ }
+
+ switch( type ) {
+ case SIMVERT_FACE:
+ /* calling BM_Vert_FaceCount every time is time consumming, so call it only once per vertex */
+ v_ext[i].num_faces = BM_Vert_FaceCount(v);
+ break;
+
+ case SIMVERT_VGROUP:
+ if( CustomData_has_layer(&(bm->vdata),CD_MDEFORMVERT) ) {
+ v_ext[i].dvert = CustomData_bmesh_get(&bm->vdata, v_ext[i].v->head.data, CD_MDEFORMVERT);
+ } else v_ext[i].dvert = NULL;
+ break;
+ }
+
+ i++;
+ }
+
+ /* select the vertices if any */
+ for( i = 0; i < num_total; i++ ) {
+ v = v_ext[i].v;
+ if( !BMO_TestFlag(bm, v, VERT_MARK) && !BM_TestHFlag(v, BM_HIDDEN) ) {
+ int cont = 1;
+ for( idx = 0; idx < num_sels && cont == 1; idx++ ) {
+ vs = v_ext[indices[idx]].v;
+ switch( type ) {
+ case SIMVERT_NORMAL:
+ /* compare the angle between the normals */
+ if( RAD2DEG(angle_v2v2(v->no, vs->no) / 180.0 <= thresh )) {
+ BMO_SetFlag(bm, v, VERT_MARK);
+ cont = 0;
+
+ }
+ break;
+ case SIMVERT_FACE:
+ /* number of adjacent faces */
+ if( v_ext[i].num_faces == v_ext[indices[idx]].num_faces ) {
+ BMO_SetFlag(bm, v, VERT_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMVERT_VGROUP:
+ if( v_ext[i].dvert != NULL && v_ext[indices[idx]].dvert != NULL ) {
+ int v1, v2;
+ for( v1 = 0; v1 < v_ext[i].dvert->totweight && cont == 1; v1++ ) {
+ for( v2 = 0; v2 < v_ext[indices[idx]].dvert->totweight; v2++ ) {
+ if( v_ext[i].dvert->dw[v1].def_nr == v_ext[indices[idx]].dvert->dw[v2].def_nr ) {
+ BMO_SetFlag(bm, v, VERT_MARK);
+ cont = 0;
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ MEM_freeN(indices);
+ MEM_freeN(v_ext);
+
+ BMO_Flag_To_Slot(bm, op, "vertout", VERT_MARK, BM_VERT);
+}
+
+/******************************************************************************
+** Cycle UVs for a face
+******************************************************************************/
+
+void bmesh_rotateuvs_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter fs_iter; /* selected faces iterator */
+ BMFace *fs; /* current face */
+ BMIter l_iter; /* iteration loop */
+ int n;
+
+ int dir = BMO_Get_Int(op, "dir");
+
+ BMO_ITER(fs, &fs_iter, bm, op, "faces", BM_FACE) {
+ if( CustomData_has_layer(&(bm->ldata), CD_MLOOPUV) ) {
+ if( dir == DIRECTION_CW ) { /* same loops direction */
+ BMLoop *lf; /* current face loops */
+ MLoopUV *f_luv; /* first face loop uv */
+ float p_uv[2]; /* previous uvs */
+ float t_uv[2]; /* tmp uvs */
+
+ int n = 0;
+ BM_ITER(lf, &l_iter, bm, BM_LOOPS_OF_FACE, fs) {
+ /* current loop uv is the previous loop uv */
+ MLoopUV *luv = CustomData_bmesh_get(&bm->ldata, lf->head.data, CD_MLOOPUV);
+ if( n == 0 ) {
+ f_luv = luv;
+ p_uv[0] = luv->uv[0];
+ p_uv[1] = luv->uv[1];
+ } else {
+ t_uv[0] = luv->uv[0];
+ t_uv[1] = luv->uv[1];
+ luv->uv[0] = p_uv[0];
+ luv->uv[1] = p_uv[1];
+ p_uv[0] = t_uv[0];
+ p_uv[1] = t_uv[1];
+ }
+ n++;
+ }
+
+ f_luv->uv[0] = p_uv[0];
+ f_luv->uv[1] = p_uv[1];
+ } else if( dir == DIRECTION_CCW ) { /* counter loop direction */
+ BMLoop *lf; /* current face loops */
+ MLoopUV *p_luv; /*previous loop uv */
+ MLoopUV *luv;
+ float t_uv[2]; /* current uvs */
+
+ int n = 0;
+ BM_ITER(lf, &l_iter, bm, BM_LOOPS_OF_FACE, fs) {
+ /* previous loop uv is the current loop uv */
+ luv = CustomData_bmesh_get(&bm->ldata, lf->head.data, CD_MLOOPUV);
+ if( n == 0 ) {
+ p_luv = luv;
+ t_uv[0] = luv->uv[0];
+ t_uv[1] = luv->uv[1];
+ } else {
+ p_luv->uv[0] = luv->uv[0];
+ p_luv->uv[1] = luv->uv[1];
+ p_luv = luv;
+ }
+ n++;
+ }
+
+ luv->uv[0] = t_uv[0];
+ luv->uv[1] = t_uv[1];
+ }
+ }
+ }
+
+}
+
+/******************************************************************************
+** Reverse UVs for a face
+******************************************************************************/
+
+void bmesh_reverseuvs_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter fs_iter; /* selected faces iterator */
+ BMFace *fs; /* current face */
+ BMIter l_iter; /* iteration loop */
+ BLI_array_declare(uvs);
+ float (*uvs)[2] = NULL;
+
+ BMO_ITER(fs, &fs_iter, bm, op, "faces", BM_FACE) {
+ if( CustomData_has_layer(&(bm->ldata), CD_MLOOPUV) ) {
+ BMLoop *lf; /* current face loops */
+ int i = 0;
+
+ BLI_array_empty(uvs);
+ BM_ITER(lf, &l_iter, bm, BM_LOOPS_OF_FACE, fs) {
+ MLoopUV *luv = CustomData_bmesh_get(&bm->ldata, lf->head.data, CD_MLOOPUV);
+
+ /* current loop uv is the previous loop uv */
+ BLI_array_growone(uvs);
+ uvs[i][0] = luv->uv[0];
+ uvs[i][1] = luv->uv[1];
+ i++;
+ }
+
+ /* now that we have the uvs in the array, reverse! */
+ i = 0;
+ BM_ITER(lf, &l_iter, bm, BM_LOOPS_OF_FACE, fs) {
+ /* current loop uv is the previous loop uv */
+ MLoopUV *luv = CustomData_bmesh_get(&bm->ldata, lf->head.data, CD_MLOOPUV);
+ luv->uv[0] = uvs[(fs->len - i - 1)][0];
+ luv->uv[1] = uvs[(fs->len - i - 1)][1];
+ i++;
+ }
+ }
+ }
+
+ BLI_array_free(uvs);
+}
+
+/******************************************************************************
+** Cycle colors for a face
+******************************************************************************/
+
+void bmesh_rotatecolors_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter fs_iter; /* selected faces iterator */
+ BMFace *fs; /* current face */
+ BMIter l_iter; /* iteration loop */
+ int n;
+
+ int dir = BMO_Get_Int(op, "dir");
+
+ BMO_ITER(fs, &fs_iter, bm, op, "faces", BM_FACE) {
+ if( CustomData_has_layer(&(bm->ldata), CD_MLOOPCOL) ) {
+ if( dir == DIRECTION_CW ) { /* same loops direction */
+ BMLoop *lf; /* current face loops */
+ MLoopCol *f_lcol; /* first face loop color */
+ MLoopCol p_col; /* previous color */
+ MLoopCol t_col; /* tmp color */
+
+ int n = 0;
+ BM_ITER(lf, &l_iter, bm, BM_LOOPS_OF_FACE, fs) {
+ /* current loop color is the previous loop color */
+ MLoopCol *luv = CustomData_bmesh_get(&bm->ldata, lf->head.data, CD_MLOOPCOL);
+ if( n == 0 ) {
+ f_lcol = luv;
+ p_col = *luv;
+ } else {
+ t_col = *luv;
+ *luv = p_col;
+ p_col = t_col;
+ }
+ n++;
+ }
+
+ *f_lcol = p_col;
+ } else if( dir == DIRECTION_CCW ) { /* counter loop direction */
+ BMLoop *lf; /* current face loops */
+ MLoopCol *p_lcol; /*previous loop color */
+ MLoopCol *lcol;
+ MLoopCol t_col; /* current color */
+
+ int n = 0;
+ BM_ITER(lf, &l_iter, bm, BM_LOOPS_OF_FACE, fs) {
+ /* previous loop color is the current loop color */
+ lcol = CustomData_bmesh_get(&bm->ldata, lf->head.data, CD_MLOOPCOL);
+ if( n == 0 ) {
+ p_lcol = lcol;
+ t_col = *lcol;
+ } else {
+ *p_lcol = *lcol;
+ p_lcol = lcol;
+ }
+ n++;
+ }
+
+ *lcol = t_col;
+ }
+ }
+ }
+}
+
+/******************************************************************************
+** Reverse colors for a face
+******************************************************************************/
+
+void bmesh_reversecolors_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter fs_iter; /* selected faces iterator */
+ BMFace *fs; /* current face */
+ BMIter l_iter; /* iteration loop */
+ BLI_array_declare(cols);
+ MLoopCol *cols = NULL;
+
+ BMO_ITER(fs, &fs_iter, bm, op, "faces", BM_FACE) {
+ if( CustomData_has_layer(&(bm->ldata), CD_MLOOPCOL) ) {
+ BMLoop *lf; /* current face loops */
+ int i = 0;
+
+ BLI_array_empty(cols);
+ BM_ITER(lf, &l_iter, bm, BM_LOOPS_OF_FACE, fs) {
+ MLoopCol *lcol = CustomData_bmesh_get(&bm->ldata, lf->head.data, CD_MLOOPCOL);
+
+ /* current loop uv is the previous loop color */
+ BLI_array_growone(cols);
+ cols[i] = *lcol;
+ i++;
+ }
+
+ /* now that we have the uvs in the array, reverse! */
+ i = 0;
+ BM_ITER(lf, &l_iter, bm, BM_LOOPS_OF_FACE, fs) {
+ /* current loop uv is the previous loop color */
+ MLoopCol *lcol = CustomData_bmesh_get(&bm->ldata, lf->head.data, CD_MLOOPCOL);
+ *lcol = cols[(fs->len - i - 1)];
+ i++;
+ }
+ }
+ }
+
+ BLI_array_free(cols);
+}
+
+
+/******************************************************************************
+** shortest vertex path select
+******************************************************************************/
+
+typedef struct element_node {
+ BMVert *v; /* vertex */
+ BMVert *parent; /* node parent id */
+ float weight; /* node weight */
+ HeapNode *hn; /* heap node */
+} element_node;
+
+void bmesh_vertexshortestpath_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter vs_iter, vs2_iter; /* selected verts iterator */
+ BMIter v_iter; /* mesh verts iterator */
+ BMVert *vs, *sv, *ev; /* starting vertex, ending vertex */
+ BMVert *v; /* mesh vertex */
+ Heap *h = NULL;
+
+ element_node *vert_list = NULL;
+
+ int num_total = 0, num_sels = 0, i = 0;
+ int type = BMO_Get_Int(op, "type");
+
+ BMO_ITER(vs, &vs_iter, bm, op, "startv", BM_VERT)
+ sv = vs;
+ BMO_ITER(vs, &vs_iter, bm, op, "endv", BM_VERT)
+ ev = vs;
+
+ num_total = BM_Count_Element(bm, BM_VERT);
+
+ /* allocate memory for the nodes */
+ vert_list = (element_node*)MEM_mallocN(sizeof(element_node) * num_total, "vertex nodes");
+
+ /* iterate through all the mesh vertices */
+ /* loop through all the vertices and fill the vertices/indices structure */
+ i = 0;
+ BM_ITER(v, &v_iter, bm, BM_VERTS_OF_MESH, NULL) {
+ vert_list[i].v = v;
+ vert_list[i].parent = NULL;
+ vert_list[i].weight = FLT_MAX;
+ BMINDEX_SET(v, i);
+ i++;
+ }
+
+ /*
+ ** we now have everything we need, start Dijkstra path finding algorithm
+ */
+
+ /* set the distance/weight of the start vertex to 0 */
+ vert_list[BMINDEX_GET(sv)].weight = 0.0f;
+
+ h = BLI_heap_new();
+
+ for( i = 0; i < num_total; i++ )
+ vert_list[i].hn = BLI_heap_insert(h, vert_list[i].weight, vert_list[i].v);
+
+ while( !BLI_heap_empty(h) ) {
+ BMEdge *e;
+ BMIter e_i;
+ float v_weight;
+
+ /* take the vertex with the lowest weight out of the heap */
+ BMVert *v = (BMVert*)BLI_heap_popmin(h);
+
+ if( vert_list[BMINDEX_GET(v)].weight == FLT_MAX ) /* this means that there is no path */
+ break;
+
+ v_weight = vert_list[BMINDEX_GET(v)].weight;
+
+ BM_ITER(e, &e_i, bm, BM_EDGES_OF_VERT, v) {
+ BMVert *u;
+ float e_weight = v_weight;
+
+ if( type == VPATH_SELECT_EDGE_LENGTH )
+ e_weight += len_v3v3(e->v1->co, e->v2->co);
+ else e_weight += 1.0f;
+
+ u = ( e->v1 == v ) ? e->v2 : e->v1;
+
+ if( e_weight < vert_list[BMINDEX_GET(u)].weight ) { /* is this path shorter ? */
+ /* add it if so */
+ vert_list[BMINDEX_GET(u)].parent = v;
+ vert_list[BMINDEX_GET(u)].weight = e_weight;
+
+ /* we should do a heap update node function!!! :-/ */
+ BLI_heap_remove(h, vert_list[BMINDEX_GET(u)].hn);
+ BLI_heap_insert(h, e_weight, u);
+ }
+ }
+ }
+
+ /* now we trace the path (if it exists) */
+ v = ev;
+
+ while( vert_list[BMINDEX_GET(v)].parent != NULL ) {
+ BMO_SetFlag(bm, v, VERT_MARK);
+ v = vert_list[BMINDEX_GET(v)].parent;
+ }
+
+ BLI_heap_free(h, NULL);
+ MEM_freeN(vert_list);
+
+ BMO_Flag_To_Slot(bm, op, "vertout", VERT_MARK, BM_VERT);
+}
diff --git a/source/blender/bmesh/tools/BME_bevel.c b/source/blender/bmesh/tools/BME_bevel.c
new file mode 100644
index 00000000000..fba5536eb1e
--- /dev/null
+++ b/source/blender/bmesh/tools/BME_bevel.c
@@ -0,0 +1,918 @@
+/**
+ * BME_tools.c jan 2007
+ *
+ * Functions for changing the topology of a mesh.
+ *
+ * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle and Levi Schooley.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+
+#include "MTC_matrixops.h"
+#include "MTC_vectorops.h"
+
+#include "blendef.h"
+
+/* ------- Bevel code starts here -------- */
+
+BME_TransData_Head *BME_init_transdata(int bufsize) {
+ BME_TransData_Head *td;
+
+ td = MEM_callocN(sizeof(BME_TransData_Head), "BM transdata header");
+ td->gh = BLI_ghash_new(BLI_ghashutil_ptrhash,BLI_ghashutil_ptrcmp);
+ td->ma = BLI_memarena_new(bufsize);
+ BLI_memarena_use_calloc(td->ma);
+
+ return td;
+}
+
+void BME_free_transdata(BME_TransData_Head *td) {
+ BLI_ghash_free(td->gh,NULL,NULL);
+ BLI_memarena_free(td->ma);
+ MEM_freeN(td);
+}
+
+BME_TransData *BME_assign_transdata(BME_TransData_Head *td, BMesh *bm, BMVert *v,
+ float *co, float *org, float *vec, float *loc,
+ float factor, float weight, float maxfactor, float *max) {
+ BME_TransData *vtd;
+ int is_new = 0;
+
+ if (v == NULL) return NULL;
+
+ if ((vtd = BLI_ghash_lookup(td->gh, v)) == NULL && bm != NULL) {
+ vtd = BLI_memarena_alloc(td->ma, sizeof(*vtd));
+ BLI_ghash_insert(td->gh, v, vtd);
+ td->len++;
+ is_new = 1;
+ }
+
+ vtd->bm = bm;
+ vtd->v = v;
+ if (co != NULL) VECCOPY(vtd->co,co);
+ if (org == NULL && is_new) { VECCOPY(vtd->org,v->co); } /* default */
+ else if (org != NULL) VECCOPY(vtd->org,org);
+ if (vec != NULL) {
+ VECCOPY(vtd->vec,vec);
+ normalize_v3(vtd->vec);
+ }
+ vtd->loc = loc;
+
+ vtd->factor = factor;
+ vtd->weight = weight;
+ vtd->maxfactor = maxfactor;
+ vtd->max = max;
+
+ return vtd;
+}
+
+BME_TransData *BME_get_transdata(BME_TransData_Head *td, BMVert *v) {
+ BME_TransData *vtd;
+ vtd = BLI_ghash_lookup(td->gh, v);
+ return vtd;
+}
+
+/* a hack (?) to use the transdata memarena to allocate floats for use with the max limits */
+float *BME_new_transdata_float(BME_TransData_Head *td) {
+ return BLI_memarena_alloc(td->ma, sizeof(float));
+}
+
+static int BME_bevel_is_split_vert(BMLoop *l) {
+ /* look for verts that have already been added to the edge when
+ * beveling other polys; this can be determined by testing the
+ * vert and the edges around it for originality
+ */
+ if ((l->v->tflag1 & BME_BEVEL_ORIG)==0
+ && (l->e->tflag1 & BME_BEVEL_ORIG)
+ && (l->prev->e->tflag1 & BME_BEVEL_ORIG))
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/* get a vector, vec, that points from v1->co to wherever makes sense to
+ * the bevel operation as a whole based on the relationship between v1 and v2
+ * (won't necessarily be a vec from v1->co to v2->co, though it probably will be);
+ * the return value is -1 for failure, 0 if we used vert co's, and 1 if we used transform origins */
+static int BME_bevel_get_vec(float *vec, BMVert *v1, BMVert *v2, BME_TransData_Head *td) {
+ BME_TransData *vtd1, *vtd2;
+
+ vtd1 = BME_get_transdata(td,v1);
+ vtd2 = BME_get_transdata(td,v2);
+ if (!vtd1 || !vtd2) {
+ //printf("BME_bevel_get_vec() got called without proper BME_TransData\n");
+ return -1;
+ }
+
+ /* compare the transform origins to see if we can use the vert co's;
+ * if they belong to different origins, then we will use the origins to determine
+ * the vector */
+ if (compare_v3v3(vtd1->org,vtd2->org,0.000001f)) {
+ VECSUB(vec,v2->co,v1->co);
+ if (len_v3(vec) < 0.000001f) {
+ mul_v3_fl(vec,0);
+ }
+ return 0;
+ }
+ else {
+ VECSUB(vec,vtd2->org,vtd1->org);
+ if (len_v3(vec) < 0.000001f) {
+ mul_v3_fl(vec,0);
+ }
+ return 1;
+ }
+}
+
+/* "Projects" a vector perpendicular to vec2 against vec1, such that
+ * the projected vec1 + vec2 has a min distance of 1 from the "edge" defined by vec2.
+ * note: the direction, is_forward, is used in conjunction with up_vec to determine
+ * whether this is a convex or concave corner. If it is a concave corner, it will
+ * be projected "backwards." If vec1 is before vec2, is_forward should be 0 (we are projecting backwards).
+ * vec1 is the vector to project onto (expected to be normalized)
+ * vec2 is the direction of projection (pointing away from vec1)
+ * up_vec is used for orientation (expected to be normalized)
+ * returns the length of the projected vector that lies along vec1 */
+static float BME_bevel_project_vec(float *vec1, float *vec2, float *up_vec, int is_forward, BME_TransData_Head *td) {
+ float factor, vec3[3], tmp[3],c1,c2;
+
+ cross_v3_v3v3(tmp,vec1,vec2);
+ normalize_v3(tmp);
+ factor = dot_v3v3(up_vec,tmp);
+ if ((factor > 0 && is_forward) || (factor < 0 && !is_forward)) {
+ cross_v3_v3v3(vec3,vec2,tmp); /* hmm, maybe up_vec should be used instead of tmp */
+ }
+ else {
+ cross_v3_v3v3(vec3,tmp,vec2); /* hmm, maybe up_vec should be used instead of tmp */
+ }
+ normalize_v3(vec3);
+ c1 = dot_v3v3(vec3,vec1);
+ c2 = dot_v3v3(vec1,vec1);
+ if (fabs(c1) < 0.000001f || fabs(c2) < 0.000001f) {
+ factor = 0.0f;
+ }
+ else {
+ factor = c2/c1;
+ }
+
+ return factor;
+}
+
+/* BME_bevel_split_edge() is the main math work-house; its responsibilities are:
+ * using the vert and the loop passed, get or make the split vert, set its coordinates
+ * and transform properties, and set the max limits.
+ * Finally, return the split vert. */
+static BMVert *BME_bevel_split_edge(BMesh *bm, BMVert *v, BMVert *v1, BMLoop *l, float *up_vec, float value, BME_TransData_Head *td) {
+ BME_TransData *vtd, *vtd1, *vtd2;
+ BMVert *sv, *v2, *v3, *ov;
+ BMLoop *lv1, *lv2;
+ BMEdge *ne, *e1, *e2;
+ float maxfactor, scale, len, dis, vec1[3], vec2[3], t_up_vec[3];
+ int is_edge, forward, is_split_vert;
+
+ if (l == NULL) {
+ /* what you call operator overloading in C :)
+ * I wanted to use the same function for both wire edges and poly loops
+ * so... here we walk around edges to find the needed verts */
+ forward = 1;
+ is_split_vert = 0;
+ if (v->e == NULL) {
+ //printf("We can't split a loose vert's edge!\n");
+ return NULL;
+ }
+ e1 = v->e; /* we just use the first two edges */
+ e2 = bmesh_disk_nextedge(v->e, v);
+ if (e1 == e2) {
+ //printf("You need at least two edges to use BME_bevel_split_edge()\n");
+ return NULL;
+ }
+ v2 = BM_OtherEdgeVert(e1, v);
+ v3 = BM_OtherEdgeVert(e2, v);
+ if (v1 != v2 && v1 != v3) {
+ //printf("Error: more than 2 edges in v's disk cycle, or v1 does not share an edge with v\n");
+ return NULL;
+ }
+ if (v1 == v2) {
+ v2 = v3;
+ }
+ else {
+ e1 = e2;
+ }
+ ov = BM_OtherEdgeVert(e1,v);
+ sv = BM_Split_Edge(bm,v,e1,&ne,0);
+ //BME_data_interp_from_verts(bm, v, ov, sv, 0.25); /*this is technically wrong...*/
+ //BME_data_interp_from_faceverts(bm, v, ov, sv, 0.25);
+ //BME_data_interp_from_faceverts(bm, ov, v, sv, 0.25);
+ BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */
+ sv->tflag1 |= BME_BEVEL_BEVEL;
+ ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */
+ BME_bevel_get_vec(vec1,v1,v,td);
+ BME_bevel_get_vec(vec2,v2,v,td);
+ cross_v3_v3v3(t_up_vec,vec1,vec2);
+ normalize_v3(t_up_vec);
+ up_vec = t_up_vec;
+ }
+ else {
+ /* establish loop direction */
+ if (l->v == v) {
+ forward = 1;
+ lv1 = l->next;
+ lv2 = l->prev;
+ v1 = l->next->v;
+ v2 = l->prev->v;
+ }
+ else if (l->next->v == v) {
+ forward = 0;
+ lv1 = l;
+ lv2 = l->next->next;
+ v1 = l->v;
+ v2 = l->next->next->v;
+ }
+ else {
+ //printf("ERROR: BME_bevel_split_edge() - v must be adjacent to l\n");
+ return NULL;
+ }
+
+ if (BME_bevel_is_split_vert(lv1)) {
+ is_split_vert = 1;
+ sv = v1;
+ if (forward) v1 = l->next->next->v;
+ else v1 = l->prev->v;
+ }
+ else {
+ is_split_vert = 0;
+ ov = BM_OtherEdgeVert(l->e,v);
+ sv = BM_Split_Edge(bm,v,l->e,&ne,0);
+ //BME_data_interp_from_verts(bm, v, ov, sv, 0.25); /*this is technically wrong...*/
+ //BME_data_interp_from_faceverts(bm, v, ov, sv, 0.25);
+ //BME_data_interp_from_faceverts(bm, ov, v, sv, 0.25);
+ BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */
+ sv->tflag1 |= BME_BEVEL_BEVEL;
+ ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */
+ }
+
+ if (BME_bevel_is_split_vert(lv2)) {
+ if (forward) v2 = lv2->prev->v;
+ else v2 = lv2->next->v;
+ }
+ }
+
+ is_edge = BME_bevel_get_vec(vec1,v,v1,td); /* get the vector we will be projecting onto */
+ BME_bevel_get_vec(vec2,v,v2,td); /* get the vector we will be projecting parallel to */
+ len = len_v3(vec1);
+ normalize_v3(vec1);
+
+ vtd = BME_get_transdata(td, sv);
+ vtd1 = BME_get_transdata(td, v);
+ vtd2 = BME_get_transdata(td,v1);
+
+ if (vtd1->loc == NULL) {
+ /* this is a vert with data only for calculating initial weights */
+ if (vtd1->weight < 0) {
+ vtd1->weight = 0;
+ }
+ scale = vtd1->weight/vtd1->factor;
+ if (!vtd1->max) {
+ vtd1->max = BME_new_transdata_float(td);
+ *vtd1->max = -1;
+ }
+ }
+ else {
+ scale = vtd1->weight;
+ }
+ vtd->max = vtd1->max;
+
+ if (is_edge && vtd1->loc != NULL) {
+ maxfactor = vtd1->maxfactor;
+ }
+ else {
+ maxfactor = scale*BME_bevel_project_vec(vec1,vec2,up_vec,forward,td);
+ if (vtd->maxfactor > 0 && vtd->maxfactor < maxfactor) {
+ maxfactor = vtd->maxfactor;
+ }
+ }
+
+ dis = (v1->tflag1 & BME_BEVEL_ORIG)? len/3 : len/2;
+ if (is_edge || dis > maxfactor*value) {
+ dis = maxfactor*value;
+ }
+ VECADDFAC(sv->co,v->co,vec1,dis);
+ VECSUB(vec1,sv->co,vtd1->org);
+ dis = len_v3(vec1);
+ normalize_v3(vec1);
+ BME_assign_transdata(td, bm, sv, vtd1->org, vtd1->org, vec1, sv->co, dis, scale, maxfactor, vtd->max);
+
+ return sv;
+}
+
+static float BME_bevel_set_max(BMVert *v1, BMVert *v2, float value, BME_TransData_Head *td) {
+ BME_TransData *vtd1, *vtd2;
+ float max, fac1, fac2, vec1[3], vec2[3], vec3[3];
+
+ BME_bevel_get_vec(vec1,v1,v2,td);
+ vtd1 = BME_get_transdata(td,v1);
+ vtd2 = BME_get_transdata(td,v2);
+
+ if (vtd1->loc == NULL) {
+ fac1 = 0;
+ }
+ else {
+ VECCOPY(vec2,vtd1->vec);
+ mul_v3_fl(vec2,vtd1->factor);
+ if (dot_v3v3(vec1, vec1)) {
+ project_v3_v3v3(vec2,vec2,vec1);
+ fac1 = len_v3(vec2)/value;
+ }
+ else {
+ fac1 = 0;
+ }
+ }
+
+ if (vtd2->loc == NULL) {
+ fac2 = 0;
+ }
+ else {
+ VECCOPY(vec3,vtd2->vec);
+ mul_v3_fl(vec3,vtd2->factor);
+ if (dot_v3v3(vec1, vec1)) {
+ project_v3_v3v3(vec2,vec3,vec1);
+ fac2 = len_v3(vec2)/value;
+ }
+ else {
+ fac2 = 0;
+ }
+ }
+
+ if (fac1 || fac2) {
+ max = len_v3(vec1)/(fac1 + fac2);
+ if (vtd1->max && (*vtd1->max < 0 || max < *vtd1->max)) {
+ *vtd1->max = max;
+ }
+ if (vtd2->max && (*vtd2->max < 0 || max < *vtd2->max)) {
+ *vtd2->max = max;
+ }
+ }
+ else {
+ max = -1;
+ }
+
+ return max;
+}
+
+static BMVert *BME_bevel_wire(BMesh *bm, BMVert *v, float value, int res, int options, BME_TransData_Head *td) {
+ BMVert *ov1, *ov2, *v1, *v2;
+
+ ov1 = BM_OtherEdgeVert(v->e, v);
+ ov2 = BM_OtherEdgeVert(bmesh_disk_nextedge(v->e, v), v);
+
+ /* split the edges */
+ v1 = BME_bevel_split_edge(bm,v,ov1,NULL,NULL,value,td);
+ v1->tflag1 |= BME_BEVEL_NONMAN;
+ v2 = BME_bevel_split_edge(bm,v,ov2,NULL,NULL,value,td);
+ v2->tflag1 |= BME_BEVEL_NONMAN;
+
+ if (value > 0.5) {
+ BME_bevel_set_max(v1,ov1,value,td);
+ BME_bevel_set_max(v2,ov2,value,td);
+ }
+
+ /* remove the original vert */
+ if (res) {
+ bmesh_jekv;
+
+ //void BM_Collapse_Vert(BMesh *bm, BMEdge *ke, BMVert *kv, float fac, int calcnorm){
+ //hrm, why is there a fac here? it just removes a vert
+ BM_Collapse_Vert(bm, v->e, v, 1.0, 0);
+ //bmesh_jekv(bm,v->e,v);
+ }
+
+ return v1;
+}
+
+static BMLoop *BME_bevel_edge(BMesh *bm, BMLoop *l, float value, int options, float *up_vec, BME_TransData_Head *td) {
+ BMVert *v1, *v2, *kv;
+ BMLoop *kl=NULL, *nl;
+ BMEdge *e;
+ BMFace *f;
+
+ f = l->f;
+ e = l->e;
+
+ if ((l->e->tflag1 & BME_BEVEL_BEVEL) == 0
+ && ((l->v->tflag1 & BME_BEVEL_BEVEL) || (l->next->v->tflag1 & BME_BEVEL_BEVEL)))
+ { /* sanity check */
+ return l;
+ }
+
+ /* checks and operations for prev edge */
+ /* first, check to see if this edge was inset previously */
+ if ((l->prev->e->tflag1 & BME_BEVEL_ORIG) == 0
+ && (l->v->tflag1 & BME_BEVEL_NONMAN) == 0) {
+ kl = l->prev->radial_next;
+ if (kl->v == l->v) kl = kl->prev;
+ else kl = kl->next;
+ kv = l->v;
+ }
+ else {
+ kv = NULL;
+ }
+ /* get/make the first vert to be used in SFME */
+ if (l->v->tflag1 & BME_BEVEL_NONMAN){
+ v1 = l->v;
+ }
+ else { /* we'll need to split the previous edge */
+ v1 = BME_bevel_split_edge(bm,l->v,NULL,l->prev,up_vec,value,td);
+ }
+ /* if we need to clean up geometry... */
+ if (kv) {
+ l = l->next;
+ if (kl->v == kv) {
+ BM_Split_Face(bm,kl->f,kl->prev->v,kl->next->v,&nl,kl->prev->e);
+ bmesh_jfke(bm,((BMLoop*)kl->prev->radial_next)->f,kl->f,kl->prev->e);
+ BM_Collapse_Vert(bm, kl->e, kv, 1.0);
+ //BME_JEKV(bm,kl->e,kv);
+
+ }
+ else {
+ BM_Split_Face(bm,kl->f,kl->next->next->v,kl->v,&nl,kl->next->e);
+ bmesh_jfke(bm,((BMLoop*)kl->next->radial_next)->f,kl->f,kl->next->e);
+ BM_Collapse_Vert(bm, kl->e, kv, 1.0);
+ //BME_JEKV(bm,kl->e,kv);
+ }
+ l = l->prev;
+ }
+
+ /* checks and operations for the next edge */
+ /* first, check to see if this edge was inset previously */
+ if ((l->next->e->tflag1 & BME_BEVEL_ORIG) == 0
+ && (l->next->v->tflag1 & BME_BEVEL_NONMAN) == 0) {
+ kl = l->next->radial_next;
+ if (kl->v == l->next->v) kl = kl->prev;
+ else kl = kl->next;
+ kv = l->next->v;
+ }
+ else {
+ kv = NULL;
+ }
+ /* get/make the second vert to be used in SFME */
+ if (l->next->v->tflag1 & BME_BEVEL_NONMAN) {
+ v2 = l->next->v;
+ }
+ else { /* we'll need to split the next edge */
+ v2 = BME_bevel_split_edge(bm,l->next->v,NULL,l->next,up_vec,value,td);
+ }
+ /* if we need to clean up geometry... */
+ if (kv) {
+ if (kl->v == kv) {
+ BM_Split_Face(bm,kl->f,kl->prev->v,kl->next->v,&nl,kl->prev->e);
+ bmesh_jfke(bm,((BMLoop*)kl->prev->radial_next)->f,kl->f,kl->prev->e);
+ BM_Collapse_Vert(bm, kl->e, kv, 1.0);
+ //BME_JEKV(bm,kl->e,kv);
+ }
+ else {
+ BM_Split_Face(bm,kl->f,kl->next->next->v,kl->v,&nl,kl->next->e);
+ bmesh_jfke(bm,((BMLoop*)kl->next->radial_next)->f,kl->f,kl->next->e);
+ BM_Collapse_Vert(bm, kl->e, kv, 1.0);
+ //BME_JEKV(bm,kl->e,kv);
+ }
+ }
+
+ if ((v1->tflag1 & BME_BEVEL_NONMAN)==0 || (v2->tflag1 & BME_BEVEL_NONMAN)==0) {
+ BM_Split_Face(bm,f,v2,v1,&l,e);
+ l->e->tflag1 = BME_BEVEL_BEVEL;
+ l = l->radial_next;
+ }
+
+ if (l->f != f){
+ //printf("Whoops! You got something out of order in BME_bevel_edge()!\n");
+ }
+
+ return l;
+}
+
+static BMLoop *BME_bevel_vert(BMesh *bm, BMLoop *l, float value, int options, float *up_vec, BME_TransData_Head *td) {
+ BMVert *v1, *v2;
+ BMFace *f;
+
+ /* get/make the first vert to be used in SFME */
+ /* may need to split the previous edge */
+ v1 = BME_bevel_split_edge(bm,l->v,NULL,l->prev,up_vec,value,td);
+
+ /* get/make the second vert to be used in SFME */
+ /* may need to split this edge (so move l) */
+ l = l->prev;
+ v2 = BME_bevel_split_edge(bm,l->next->v,NULL,l->next,up_vec,value,td);
+ l = l->next->next;
+
+ /* "cut off" this corner */
+ f = BM_Split_Face(bm,l->f,v2,v1,NULL,l->e);
+
+ return l;
+}
+
+/**
+ * BME_bevel_poly
+ *
+ * Polygon inset tool:
+ *
+ * Insets a polygon/face based on the tflag1's of its vertices
+ * and edges. Used by the bevel tool only, for now.
+ * The parameter "value" is the distance to inset (should be negative).
+ * The parameter "options" is not currently used.
+ *
+ * Returns -
+ * A BMFace pointer to the resulting inner face.
+*/
+static BMFace *BME_bevel_poly(BMesh *bm, BMFace *f, float value, int options, BME_TransData_Head *td) {
+ BMLoop *l, *ol;
+ BME_TransData *vtd1, *vtd2;
+ float up_vec[3], vec1[3], vec2[3], vec3[3], fac1, fac2, max = -1;
+ int len, i;
+
+ up_vec[0] = 0.0f;
+ up_vec[1] = 0.0f;
+ up_vec[2] = 0.0f;
+ /* find a good normal for this face (there's better ways, I'm sure) */
+ ol = f->loopbase;
+ l = ol->next;
+ for (i=0,ol=f->loopbase,l=ol->next; l->next!=ol; l=l->next) {
+ BME_bevel_get_vec(vec1,l->next->v,ol->v,td);
+ BME_bevel_get_vec(vec2,l->v,ol->v,td);
+ cross_v3_v3v3(vec3,vec2,vec1);
+ VECADD(up_vec,up_vec,vec3);
+ i++;
+ }
+ mul_v3_fl(up_vec,1.0f/i);
+ normalize_v3(up_vec);
+
+ for (i=0,len=f->len; i<len; i++,l=l->next) {
+ if ((l->e->tflag1 & BME_BEVEL_BEVEL) && (l->e->tflag1 & BME_BEVEL_ORIG)) {
+ max = 1.0f;
+ l = BME_bevel_edge(bm, l, value, options, up_vec, td);
+ }
+
+ else if ((l->v->tflag1 & BME_BEVEL_BEVEL) && (l->v->tflag1 & BME_BEVEL_ORIG) && (l->prev->e->tflag1 & BME_BEVEL_BEVEL) == 0) {
+ max = 1.0f;
+ l = BME_bevel_vert(bm, l, value, options, up_vec, td);
+ }
+ }
+
+ /* max pass */
+ if (value > 0.5 && max > 0) {
+ max = -1;
+ for (i=0,len=f->len; i<len; i++,l=l->next) {
+ if ((l->e->tflag1 & BME_BEVEL_BEVEL) || (l->e->tflag1 & BME_BEVEL_ORIG)) {
+ BME_bevel_get_vec(vec1,l->v,l->next->v,td);
+ vtd1 = BME_get_transdata(td,l->v);
+ vtd2 = BME_get_transdata(td,l->next->v);
+ if (vtd1->loc == NULL) {
+ fac1 = 0;
+ }
+ else {
+ VECCOPY(vec2,vtd1->vec);
+ mul_v3_fl(vec2,vtd1->factor);
+ if (dot_v3v3(vec1, vec1)) {
+ project_v3_v3v3(vec2,vec2,vec1);
+ fac1 = len_v3(vec2)/value;
+ }
+ else {
+ fac1 = 0;
+ }
+ }
+ if (vtd2->loc == NULL) {
+ fac2 = 0;
+ }
+ else {
+ VECCOPY(vec3,vtd2->vec);
+ mul_v3_fl(vec3,vtd2->factor);
+ if (dot_v3v3(vec1, vec1)) {
+ project_v3_v3v3(vec2,vec3,vec1);
+ fac2 = len_v3(vec2)/value;
+ }
+ else {
+ fac2 = 0;
+ }
+ }
+ if (fac1 || fac2) {
+ max = len_v3(vec1)/(fac1 + fac2);
+ if (vtd1->max && (*vtd1->max < 0 || max < *vtd1->max)) {
+ *vtd1->max = max;
+ }
+ if (vtd2->max && (*vtd2->max < 0 || max < *vtd2->max)) {
+ *vtd2->max = max;
+ }
+ }
+ }
+ }
+ }
+
+ return l->f;
+}
+
+static void BME_bevel_add_vweight(BME_TransData_Head *td, BMesh *bm, BMVert *v, float weight, float factor, int options) {
+ BME_TransData *vtd;
+
+ if (v->tflag1 & BME_BEVEL_NONMAN) return;
+ v->tflag1 |= BME_BEVEL_BEVEL;
+ if ( (vtd = BME_get_transdata(td, v)) ) {
+ if (options & BME_BEVEL_EMIN) {
+ vtd->factor = 1.0;
+ if (vtd->weight < 0 || weight < vtd->weight) {
+ vtd->weight = weight;
+ }
+ }
+ else if (options & BME_BEVEL_EMAX) {
+ vtd->factor = 1.0;
+ if (weight > vtd->weight) {
+ vtd->weight = weight;
+ }
+ }
+ else if (vtd->weight < 0) {
+ vtd->factor = factor;
+ vtd->weight = weight;
+ }
+ else {
+ vtd->factor += factor; /* increment number of edges with weights (will be averaged) */
+ vtd->weight += weight; /* accumulate all the weights */
+ }
+ }
+ else {
+ /* we'll use vtd->loc == NULL to mark that this vert is not moving */
+ vtd = BME_assign_transdata(td, bm, v, v->co, NULL, NULL, NULL, factor, weight, -1, NULL);
+ }
+}
+
+
+static bevel_init_verts(BMesh *bm, int options, BME_TransData_Head *td){
+ BMVert *v;
+ float weight;
+ for(v=bm->verts.first; v; v=v->next){
+ weight = 0.0;
+ if(!(v->tflag1 & BME_BEVEL_NONMAN)){
+ if(options & BME_BEVEL_SELECT){
+ if(v->flag & SELECT) weight = 1.0;
+ }
+ else if(options & BME_BEVEL_WEIGHT) weight = v->bweight;
+ else weight = 1.0;
+ if(weight > 0.0){
+ v->tflag1 |= BME_BEVEL_BEVEL;
+ BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 1.0,weight, -1, NULL);
+ }
+ }
+ }
+}
+static bevel_init_edges(BMesh *bm, int options, BME_TransData_Head *td){
+ BMEdge *e;
+ int count;
+ float weight;
+ for( e = BM_first_element(bm, BME_EDGE); e; e = BM_next_element(bm, BME_EDGE, e)){
+ weight = 0.0;
+ if(!(e->tflag1 & BME_BEVEL_NONMAN)){
+ if(options & BME_BEVEL_SELECT){
+ if(e->flag & SELECT) weight = 1.0;
+ }
+ else if(options & BME_BEVEL_WEIGHT){
+ weight = e->bweight;
+ }
+ else{
+ weight = 1.0;
+ }
+ if(weight > 0.0){
+ e->tflag1 |= BME_BEVEL_BEVEL;
+ e->v1->tflag1 |= BME_BEVEL_BEVEL;
+ e->v2->tflag1 |= BME_BEVEL_BEVEL;
+ BME_bevel_add_vweight(td, bm, e->v1, weight, 1.0, options);
+ BME_bevel_add_vweight(td, bm, e->v2, weight, 1.0, options);
+ }
+ }
+ }
+
+ /*clean up edges with 2 faces that share more than one edge*/
+ for( e = BM_first_element(bm, BME_EDGE); e; e = BM_next_element(bm, BME_EDGE, e)){
+ if(e->tflag1 & BME_BEVEL_BEVEL){
+ count = BM_face_sharededges(e->l->f, ((BMLoop*)e->l->radial_next)->f);
+ if(count > 1) e->tflag1 &= ~BME_BEVEL_BEVEL;
+ }
+ }
+}
+static BMesh *BME_bevel_initialize(BMesh *bm, int options, int defgrp_index, float angle, BME_TransData_Head *td){
+
+ BMVert *v, *v2;
+ BMEdge *e, *curedge;
+ BMFace *f;
+ BMIter iter;
+ int wire, len;
+
+ for (v = BMIter_New(&iter, bm, BM_VERTS, nm); v; v = BMIter_Step(&iter)) v->tflag1 = 0;
+ for (e = BMIter_New(&iter, bm, BM_EDGES, nm); e; e = BMIter_Step(&iter)) e->tflag1 = 0;
+ for (f = BMIter_New(&iter, bm, BM_FACES, nm); f; f = BMIter_Step(&iter)) f->tflag1 = 0;
+
+ /*tag non-manifold geometry*/
+ for (v = BMIter_New(&iter, bm, BM_VERTS, nm); v; v = BMIter_Step(&iter)) {
+ v->tflag1 = BME_BEVEL_ORIG;
+ if(v->e){
+ BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 0, -1, -1, NULL);
+ if (BM_Nonmanifold_Vert(bm,v)) v->tflag1 |= BME_BEVEL_NONMAN;
+ /*test wire vert*/
+ len = bmesh_cycle_length(bmesh_disk_getpointer(v->e,v));
+ if(len == 2 && BME_wirevert(bm, v)) v->tflag1 &= ~BME_BEVEL_NONMAN;
+ }else v->tflag1 |= BME_BEVEL_NONMAN;
+ }
+
+ for (e = BMIter_New(&iter, bm, BM_EDGES, nm); e; e = BMIter_Step(&iter)) {
+ e->tflag1 = BME_BEVEL_ORIG;
+ if (e->l == NULL || BME_cycle_length(&(e->l->radial)) > 2){
+ e->v1->tflag1 |= BME_BEVEL_NONMAN;
+ e->v2->tflag1 |= BME_BEVEL_NONMAN;
+ e->tflag1 |= BME_BEVEL_NONMAN;
+ }
+ if((e->v1->tflag1 & BME_BEVEL_NONMAN) || (e->v2->tflag1 & BME_BEVEL_NONMAN)) e->tflag1 |= BME_BEVEL_NONMAN;
+ }
+
+ for (f = BMIter_New(&iter, bm, BM_FACES, nm); f; f = BMIter_Step(&iter))
+ f->tflag1 = BME_BEVEL_ORIG;
+ if(options & BME_BEVEL_VERT) bevel_init_verts(bm, options, td);
+ else bevel_init_edges(bm, options, td);
+ return bm;
+
+}
+static BMesh *BME_bevel_reinitialize(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ for (v = BMIter_New(bm, BM_VERTS, NULL); v; v = BMIter_Step(bm)){
+ v->tflag1 |= BME_BEVEL_ORIG;
+ v->tflag2 = 0;
+ }
+ for (e = BMIter_New(bm, BM_EDGES, NULL); e; e = BMIter_Step(bm)){
+ e->tflag1 |= BME_BEVEL_ORIG;
+ }
+ for (f = BMIter_New(bm, BM_FACES, NULL); f; f = BMIter_Step(bm)){
+ f->tflag1 |= BME_BEVEL_ORIG;
+ }
+ return bm;
+
+}
+
+/**
+ * BME_bevel_mesh
+ *
+ * Mesh beveling tool:
+ *
+ * Bevels an entire mesh. It currently uses the tflag1's of
+ * its vertices and edges to track topological changes.
+ * The parameter "value" is the distance to inset (should be negative).
+ * The parameter "options" is not currently used.
+ *
+ * Returns -
+ * A BMesh pointer to the BM passed as a parameter.
+*/
+
+static BMMesh *BME_bevel_mesh(BMMesh *bm, float value, int res, int options, int defgrp_index, BME_TransData_Head *td) {
+ BMVert *v, *nv;
+ BMEdge *e, *curedge, *ne;
+ BMLoop *l, *l2;
+ BMFace *f, *nf;
+
+ BMeshIter verts;
+ BMeshIter edges;
+ BMeshIter loops;
+ BMeshIter faces;
+
+ unsigned int i, len;
+
+ /*bevel polys*/
+ for(f = BMeshIter_init(faces, BM_FACES, bm, 0); f; f = BMeshIter_step(faces)){
+ if(bmesh_test_flag(f, BME_BEVEL_ORIG){
+ bevel_poly(bm,f,value,options,td);
+ }
+ }
+ /*get rid of beveled edges*/
+ for(e = BMeshIter_init(edges, BM_EDGES, bm, 0); e;){
+ ne = BMeshIter_step(edges);
+ if( bmesh_test_flag(e, BME_BEVEL_BEVEL) && bmesh_test_flag(e, BME_BEVEL_ORIG) ) bmesh_join_faces(bm, e->l->f, ((BMLoop*)e->l->radial_next)->f, e, 1);
+ e = ne;
+ }
+ /*link up corners and clip*/
+ for(v = BMeshIter_init(verts, BM_VERTS, bm, 0); v;){
+ nv = BMeshIter_step(verts)
+ if( bmesh_test_flag(v, BME_BEVEL_ORIG) && bmesh_test_flag(v, BME_BEVEL_BEVEL)){
+ curedge = v->e;
+ do{
+ l = curedge->l;
+ l2 = l->radial_next;
+ if(l->v != v) l = l->next;
+ if(l2->v != v) l2 = l2->next;
+ if(l->f->len > 3) BM_split_face(bm,l->f,l->next->v,l->prev->v,&l,l->e); /* clip this corner off */
+ if(l2->f->len > 3) BM_split_face(bm,l2->f,l2->next->v,l2->prev->v,&l,l2->e); /* clip this corner off */
+ curedge = BM_edge_of_vert(curedge, v);
+ }while(curedge != v->e);
+ BM_dissolve_disk(bm,v);
+ }
+ v = nv;
+ }
+
+ /*Debug print, remove*/
+ for(f = BMeshIter_init(faces, BM_FACES, bm, 0); f;){
+ if(f->len == 2){
+ printf("warning");
+ }
+ }
+
+ return bm;
+}
+
+BMesh *BME_bevel(BMMesh *bm, float value, int res, int options, int defgrp_index, float angle, BME_TransData_Head **rtd) {
+ BMVert *v;
+ BMEdge *e;
+ BMIter *verts;
+
+ BME_TransData_Head *td;
+ BME_TransData *vtd;
+ int i;
+ double fac=1, d;
+
+
+ td = BME_init_transdata(BLI_MEMARENA_STD_BUFSIZE);
+ /* recursion math courtesy of Martin Poirier (theeth) */
+ for (i=0; i<res-1; i++) {
+ if (i==0) fac += 1.0f/3.0f; else fac += 1.0f/(3 * i * 2.0f);
+ }
+ d = 1.0f/fac;
+
+
+ for (i=0; i<res || (res==0 && i==0); i++) {
+ BME_bevel_initialize(bm, options, defgrp_index, angle, td);
+ //if (i != 0) BME_bevel_reinitialize(bm);
+ bmesh_begin_edit(bm);
+ BME_bevel_mesh(bm,(float)d,res,options,defgrp_index,td);
+ bmesh_end_edit(bm);
+ if (i==0) d /= 3; else d /= 2;
+ }
+
+ BME_model_begin(bm);
+ BME_tesselate(bm);
+ BME_model_end(bm);
+
+
+ /*interactive preview?*/
+ if (rtd) {
+ *rtd = td;
+ return bm;
+ }
+
+ /* otherwise apply transforms */
+ for( v = BMeshIter_init(verts); v; v = BMeshIter_step(verts)){
+ if ( (vtd = BME_get_transdata(td, v)) ) {
+ if (vtd->max && (*vtd->max > 0 && value > *vtd->max)) {
+ d = *vtd->max;
+ }
+ else {
+ d = value;
+ }
+ VECADDFAC(v->co,vtd->org,vtd->vec,vtd->factor*d);
+ }
+ v->tflag1 = 0;
+ }
+
+ BME_free_transdata(td);
+ return bm;
+}
diff --git a/source/blender/bmesh/tools/BME_dupe_ops.c b/source/blender/bmesh/tools/BME_dupe_ops.c
new file mode 100644
index 00000000000..ad5739e9abc
--- /dev/null
+++ b/source/blender/bmesh/tools/BME_dupe_ops.c
@@ -0,0 +1,318 @@
+/*
+ * BME_DUPLICATE.C
+ *
+ * This file contains functions for duplicating, copying, and splitting
+ * elements from a bmesh.
+ *
+ */
+
+/*
+ * COPY VERTEX
+ *
+ * Copy an existing vertex from one bmesh to another.
+ *
+*/
+
+static BMVert *copy_vertex(BMMesh *source_mesh, BMVert *source_vertex, BMMesh *target_mesh, GHash *vhash)
+{
+ BMVert *target_vertex = NULL;
+
+ /*create a new vertex*/
+ target_vertex = BM_Make_Vert(target, source_vertex->co, NULL);
+
+ /*insert new vertex into the vert hash*/
+ BLI_ghash_insert(vhash, source_vertex, target_vertex);
+
+ /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/
+ CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata, source_vertex->data, &target_vertex->data);
+
+ /*Copy Markings*/
+ if(BM_Is_Selected((BMHeader*)source_vertex)) BM_Select_Vert(target_mesh, target_vertex, 1);
+ if(BM_Is_Hidden((BMHeader*)source_vertex)) BM_Mark_Hidden((BMHeader*)target_vertex, 1);
+
+ BMO_SetFlag(target_mesh, (BMHeader*)target_vertex, DUPE_NEW);
+
+ return target_vertex;
+}
+
+/*
+ * COPY EDGE
+ *
+ * Copy an existing edge from one bmesh to another.
+ *
+*/
+
+static BMEdge *copy_edge(BMMesh *source_mesh, BMEdge *source_edge, BMMesh *target_mesh, GHash *vhash, GHash *ehash)
+{
+ BMEdge *target_edge = NULL;
+ BMVert *target_vert1, *target_vert2;
+
+ /*lookup v1 and v2*/
+ target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1);
+ target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2);
+
+ /*create a new edge*/
+ target_edge = BM_Make_Edge(target_mesh, target_vert1, target_vert2, NULL, 0);
+
+ /*insert new edge into the edge hash*/
+ BLI_ghash_insert(ehash, source_edge, target_edge);
+
+ /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/
+ CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata, source_edge->data, &target_edge->data);
+
+ /*copy flags*/
+ if(BM_Is_Selected((BMHeader*) source_edge)) BM_Select_Edge(target_mesh, target_edge, 1);
+ if(BM_Is_Hidden((BMHeader*) source_edge)) BM_Mark_Hidden(target_mesh, target_edge, 1);
+ if(BM_Is_Sharp((BMHeader*) source_edge)) BM_Mark_Sharp(target_edge, 1);
+ if(BM_Is_Seam((BMHeader*) source_edge)) BM_Mark_Seam(target_edge, 1);
+ if(BM_Is_Fgon((BMHeader*) source_edge)) BM_Mark_Fgon(target_edge, 1);
+
+ BMO_SetFlag(target_mesh, (BMHeader*)target_edge, DUPE_NEW);
+
+ return target_edge;
+}
+
+/*
+ * COPY FACE
+ *
+ * Copy an existing face from one bmesh to another.
+ *
+*/
+
+static BMFace *copy_face(BMMesh *source_mesh, BMFace *source_face, BMMesh *target_mesh, BMEdge **edar, GHash *verthash, GHash *ehash)
+{
+ BMEdge *target_edge;
+ BMVert *target_vert1, *target_vert2;
+ BMLoop *source_loop, *target_loop;
+ BMFace *target_face = NULL;
+ int i;
+
+ /*lookup the first and second verts*/
+ target_vert1 = BLI_ghash_lookup(vhash, source_face->lbase->v);
+ target_vert2 = BLI_ghash_lookup(vhash, source_face->lbase->next->v);
+
+ /*lookup edges*/
+ i = 0;
+ source_loop = source_face->lbase;
+ do{
+ edar[i] = BLI_ghash_lookup(ehash, source_loop->e);
+ i++;
+ source_loop = source_loop->next;
+ }while(source_loop != source_face->lbase);
+
+ /*create new face*/
+ target_face = BM_Make_Ngon(target_mesh, target_vert1, target_vert2, edar, source_face->len, 0);
+
+ /*we copy custom data by hand, we cannot assume that customdata byte layout will be exactly the same....*/
+ CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata, source_face->data, &target_face->data);
+
+ /*copy flags*/
+ if(BM_Is_Selected((BMHeader*)source_face)) BM_Select_face(target, target_face, 1);
+ if(BM_Is_Hidden((BMHeader*)source_face)) BM_Mark_Hidden((BMHeader*)target_face, 1);
+
+ /*mark the face for output*/
+ BMO_SetFlag(target_mesh, (BMHeader*)target_face, DUPE_NEW);
+
+ /*copy per-loop custom data*/
+ source_loop = source_face->lbase;
+ target_loop = target_face->lbase;
+ do{
+ CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata, source_loop->data, &target_loop->data);
+ source_loop = source_loop->next;
+ target_loop = target_loop->next;
+ }while(source_loop != source_face->lbase);
+
+ return target_face;
+}
+
+/*
+ * COPY MESH
+ *
+ * Internal Copy function.
+*/
+
+/*local flag defines*/
+
+#define DUPE_INPUT 1 /*input from operator*/
+#define DUPE_NEW 2
+#define DUPE_DONE 3
+
+static void copy_mesh(BMMesh *source, BMMesh *target)
+{
+
+ BMVert *v = NULL;
+ BMEdge *e = NULL, **edar = NULL;
+ BMLoop *l = NULL;
+ BMFace *f = NULL;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+ BMIter loops;
+
+ GHash *vhash;
+ GHash *ehash;
+
+ int maxlength = 0, flag;
+
+ /*initialize pointer hashes*/
+ vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ ehash = BLI_ghash_new(BLI_ghashutil_ptrrhash, BLI_ghashutil_ptrcmp);
+
+ /*initialize edge pointer array*/
+ for(f = BMIter_New(&faces, source, BM_FACES, source, 0, NULL); f; f = BMIter_Step(&faces)){
+ if(f->len > maxlength) maxlength = f->len;
+ }
+ edar = MEM_callocN(sizeof(BMEdge*) * maxlength, "BM copy mesh edge pointer array");
+
+
+ /*first we dupe all flagged faces and their elements from source*/
+ for(f = BMIter_New(&faces, source, BM_FACES, source, 0, NULL); f; f= BMIter_Step(&faces)){
+ if(BMO_TestFlag(source, (BMHeader*)f, DUPE_INPUT)){
+ /*vertex pass*/
+ for(v = BMIter_New(&verts, source, BM_VERT_OF_FACE, f, 0, NULL); v; v = BMIter_Step(&verts)){
+ if(!BMO_TestFlag(source, (BMHeader*)v, DUPE_DONE)){
+ copy_vertex(source,v, target, vhash);
+ BMO_SetFlag(source, (BMHeader*)v, DUPE_DONE);
+ }
+ }
+
+ /*edge pass*/
+ for(e = BMIter_New(&edges, source, BM_EDGE_OF_FACE, f, 0, NULL); e; e = BMeshIter_step(&edges)){
+ if(!BMO_TestFlag(source, (BMHeader*)e, DUPE_DONE)){
+ copy_edge(source, e, target, vhash, ehash);
+ BMO_SetFlag(source, (BMHeader*)e, DUPE_DONE);
+ }
+ }
+ copy_face(source, f, target, edar, vhash, ehash);
+ BMO_SetFlag(source, (BMHeader*)f, DUPE_DONE);
+ }
+ }
+
+ /*now we dupe all the edges*/
+ for(e = BMIter_New(&edges, source, BM_EDGES, source, 0, NULL); e; e = BMIter_Step(&edges)){
+ if(BMO_TestFlag(source, (BMHeader*)e, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader*)e, DUPE_DONE))){
+ /*make sure that verts are copied*/
+ if(!BMO_TestFlag(source, (BMHeader*)e->v1, DUPE_DONE){
+ copy_vertex(source, e->v1, target, vhash);
+ BMO_SetFlag(source, (BMHeader*)e->v1, DUPE_DONE);
+ }
+ if(!BMO_TestFlag(source, (BMHeader*)e->v2, DUPE_DONE){
+ copy_vertex(source, e->v2, target, vhash);
+ BMO_SetFlag(source, (BMHeader*)e->v2, DUPE_DONE);
+ }
+ /*now copy the actual edge*/
+ copy_edge(source, e, target, vhash, ehash);
+ BMO_SetFlag(source, (BMHeader*)e, DUPE_DONE);
+ }
+ }
+
+ /*finally dupe all loose vertices*/
+ for(v = BMIter_New(&verts, source, BM_VERTS, source, 0, NULL); v; v = BMIter_Step(&verts)){
+ if(BMO_TestFlag(source, (BMHeader*)v, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader*)v, DUPE_DONE))){
+ copy_vertex(source, v, target, vhash);
+ BMO_SetFlag(source, (BMHeader*)v, DUPE_DONE);
+ }
+ }
+
+ /*free pointer hashes*/
+ BLI_ghash_free(vhash, NULL, NULL);
+ BLI_ghash_free(ehash, NULL, NULL);
+
+ /*free edge pointer array*/
+ if(edar)
+ MEM_freeN(edar);
+}
+/*
+BMMesh *bmesh_make_mesh_from_mesh(BMMesh *bm, int allocsize[4])
+{
+ BMMesh *target = NULL;
+ target = bmesh_make_mesh(allocsize);
+
+
+ CustomData_copy(&bm->vdata, &target->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->edata, &target->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->ldata, &target->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->pdata, &target->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+
+ CustomData_bmesh_init_pool(&target->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&target->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&target->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&target->pdata, allocsize[3]);
+
+ bmesh_begin_edit(bm);
+ bmesh_begin_edit(target);
+
+ bmesh_copy_mesh(bm, target, 0);
+
+ bmesh_end_edit(bm);
+ bmesh_end_edit(target);
+
+ return target;
+
+}
+*/
+
+void dupeop_exec(BMMesh *bm, BMOperator *op)
+{
+ BMOperator *dupeop = op;
+ BMOpSlot *vinput, *einput, *finput, *vnew, *enew, *fnew;
+ int i;
+
+ vinput = BMO_Get_Slot(dupeop, BMOP_DUPE_VINPUT);
+ einput = BMO_Get_Slot(dupeop, BMOP_DUPE_EINPUT);
+ finput = BMO_Get_Slot(dupeop, BMOP_DUPE_FINPUT);
+
+ /*go through vinput, einput, and finput and flag elements with private flags*/
+ BMO_Flag_Buffer(bm, dupeop, BMOP_DUPE_VINPUT, DUPE_INPUT);
+ BMO_Flag_Buffer(bm, dupeop, BMOP_DUPE_EINPUT, DUPE_INPUT);
+ BMO_Flag_Buffer(bm, dupeop, BMOP_DUPE_FINPUT, DUPE_INPUT);
+
+ /*use the internal copy function*/
+ copy_mesh(bm, bm);
+
+ /*Output*/
+ /*First copy the input buffers to output buffers - original data*/
+ BMO_Copy_Opslot_Buffer_Alloc(dupeop, vinput, BMO_Get_Slot(dupeop, BMOP_DUPE_VORIGINAL));
+ BMO_Copy_Opslot_Buffer_Alloc(dupeop, einput, BMO_Get_Slot(dupeop, BMOP_DUPE_EORIGINAL));
+ BMO_Copy_Opslot_Buffer_Alloc(dupeop, finput, BMO_Get_Slot(dupeop, BMOP_DUPE_FORIGINAL));
+
+ /*Now alloc the new output buffers*/
+ BMO_Flag_To_Slot(bm, dupeop, BMOP_DUPE_VNEW, DUPE_NEW, BMESH_VERT);
+ BMO_Flag_To_Slot(bm, dupeop, BMOP_DUPE_ENEW, DUPE_NEW, BMESH_EDGE);
+ BMO_Flag_To_Slot(bm, dupeop, BMOP_DUPE_FNEW, DUPE_NEW, BMESH_FACE);
+}
+
+void splitop_exec(BMMesh *bm, BMOperator *op)
+{
+ BMOperator *splitop = op;
+ BMOperator dupeop;
+ BMOperator delop;
+
+ /*initialize our sub-operators*/
+ BMO_Init_Op(&dupeop, BMOP_DUPE);
+ BMO_Init_Op(&delop, BMOP_DEL);
+
+ BMO_Connect(BMO_Get_Slot(splitop, BMOP_SPLIT_VINPUT),BMO_Get_Slot(&dupeop, BMOP_DUPE_VINPUT));
+ BMO_Connect(BMO_Get_Slot(splitop, BMOP_SPLIT_EINPUT),BMO_Get_Slot(&dupeop, BMOP_DUPE_EINPUT));
+ BMO_Connect(BMO_Get_Slot(splitop, BMOP_SPLIT_FINPUT),BMO_Get_Slot(&dupeop, BMOP_DUPE_FINPUT));
+
+ BMO_Exec_Op(&dupeop);
+
+ /*connect outputs of dupe to delete*/
+ BMO_Connect(BMO_Get_Slot(&dupeop, BMOP_DUPE_VORIGINAL), BMO_Get_Slot(&delop, BMOP_DEL_VINPUT));
+ BMO_Connect(BMO_Get_Slot(&dupeop, BMOP_DUPE_EORIGINAL), BMO_Get_Slot(&delop, BMOP_DEL_EINPUT));
+ BMO_Connect(BMO_Get_Slot(&dupeop, BMOP_DUPE_FORIGINAL), BMO_Get_Slot(&delop, BMOP_DEL_FINPUT));
+
+ BMO_Exec_Op(&delop);
+
+ /*now we make our outputs by copying the dupe outputs*/
+ BMO_Copy_Buffer_Alloc(BMO_Get_Slot(&dupeop, BMOP_DUPE_VNEW), BMO_Get_Slot(splitop, BMOP_SPLIT_VOUTPUT));
+ BMO_Copy_Buffer_Alloc(BMO_Get_Slot(&dupeop, BMOP_DUPE_ENEW), BMO_Get_Slot(splitop, BMOP_SPLIT_EOUTPUT));
+ BMO_Copy_Buffer_Alloc(BMO_Get_Slot(&dupeop, BMOP_DUPE_FNEW), BMO_Get_Slot(splitop, BMOP_SPLIT_FOUTPUT));
+
+ /*cleanup*/
+ BMO_Finish_Op(&dupeop);
+ BMO_Finish_Op(&delop);
+} \ No newline at end of file
diff --git a/source/blender/bmesh/tools/BME_duplicate.c b/source/blender/bmesh/tools/BME_duplicate.c
new file mode 100644
index 00000000000..ec3cfe56fc9
--- /dev/null
+++ b/source/blender/bmesh/tools/BME_duplicate.c
@@ -0,0 +1,307 @@
+/*
+ * BME_DUPLICATE.C
+ *
+ * This file contains functions for duplicating, copying, and splitting
+ * elements from a bmesh.
+ *
+ */
+
+/*
+ * BMESH COPY VERTEX
+ *
+ * Copy an existing vertex from one bmesh to another.
+ *
+*/
+
+static BMVert *bmesh_copy_vertex(BMMesh *source_mesh, BMVert *source_vertex, BMMesh *target_mesh, GHash *vhash)
+{
+ BMVert *target_vertex = NULL;
+
+ /*create a new vertex*/
+ target_vertex = bmesh_make_vert(target, source_vertex->co, NULL);
+
+ /*insert new vertex into the vert hash*/
+ BLI_ghash_insert(vhash, source_vertex, target_vertex);
+
+ /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/
+ CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata, source_vertex->data, &target_vertex->data);
+
+ /*copy flags*/
+ if(bmesh_test_flag(source_vertex, BMESH_SELECT)) bmesh_set_flag(target_vertex, BMESH_SELECT);
+ if(bmesh_test_flag(source_vertex, BMESH_HIDDEN)) bmesh_set_flag(target_vertex, BMESH_HIDDEN);
+
+ return target_vertex;
+}
+
+/*
+ * BMESH COPY EDGE
+ *
+ * Copy an existing edge from one bmesh to another.
+ *
+*/
+
+static BMEdge *bmesh_copy_edge(BMMesh *source_mesh, BMEdge *source_edge, BMMesh *target_mesh, GHash *vhash, GHash *ehash)
+{
+ BMEdge *target_edge = NULL;
+ BMVert *target_vert1, *target_vert2;
+
+ /*lookup v1 and v2*/
+ target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1);
+ target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2);
+
+ /*create a new edge*/
+ target_edge = bmesh_make_edge(target_mesh, target_vert1, target_vert2, NULL, 0);
+
+ /*insert new edge into the edge hash*/
+ BLI_ghash_insert(ehash, source_edge, target_edge);
+
+ /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/
+ CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata, source_edge->data, &target_edge->data);
+
+ /*copy flags*/
+ if(bmesh_test_flag(source_edge, BMESH_SELECT)) bmesh_set_flag(target_edge, BMESH_SELECT);
+ if(bmesh_test_flag(source_edge, BMESH_HIDDEN)) bmesh_set_flag(target_edge, BMESH_SELECT);
+ if(bmesh_test_flag(source_edge, BMESH_SHARP)) bmesh_set_flag(target_edge, BMESH_SHARP);
+ if(bmesh_test_flag(source_edge, BMESH_SEAM)) bmesh_set_flag(target_edge, BMESH_SEAM);
+ if(bmesh_test_flag(source_edge, BMESH_FGON)) bmesh_set_flag(target_edge, BMESH_FGON);
+
+ return target_edge;
+}
+
+/*
+ * BMESH COPY FACE
+ *
+ * Copy an existing face from one bmesh to another.
+ *
+*/
+
+static BMFace *bmesh_copy_face(BMMesh *source_mesh, BMFace *source_face, BMMesh *target_mesh, BMEdge **edar, GHash *verthash, GHash *ehash)
+{
+ BMEdge *target_edge;
+ BMVert *target_vert1, *target_vert2;
+ BMLoop *source_loop, *target_loop;
+ BMFace *target_face = NULL;
+ int i;
+
+
+ /*lookup the first and second verts*/
+ target_vert1 = BLI_ghash_lookup(vhash, source_face->lbase->v);
+ target_vert2 = BLI_ghash_lookup(vhash, source_face->lbase->next->v);
+
+ /*lookup edges*/
+ i = 0;
+ source_loop = source_face->lbase;
+ do{
+ edar[i] = BLI_ghash_lookup(ehash, source_loop->e);
+ i++;
+ source_loop = source_loop->next;
+ }while(source_loop != source_face->lbase);
+
+ /*create new face*/
+ target_face = bmesh_make_ngon(target_mesh, target_vert1, target_vert2, edar, source_face->len, 0);
+
+ /*we copy custom data by hand, we cannot assume that customdata byte layout will be exactly the same....*/
+ CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata, source_face->data, &target_face->data);
+
+ /*copy flags*/
+ if(bmesh_test_flag(source_face, BMESH_SELECT)) bmesh_set_flag(target_face, BMESH_SELECT);
+ if(bmesh_test_flag(source_face, BMESH_HIDDEN)) bmesh_set_flag(target_face, BMESH_HIDDEN);
+
+ /*mark the face as dirty for normal and tesselation calcs*/
+ bmesh_set_flag(target_face, BMESH_DIRTY);
+
+ /*copy per-loop custom data*/
+ source_loop = source_face->lbase;
+ target_loop = target_face->lbase;
+ do{
+ CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata, source_loop->data, &target_loop->data);
+ source_loop = source_loop->next;
+ target_loop = target_loop->next;
+ }while(source_loop != source_face->lbase);
+
+ return target_face;
+}
+
+/*
+ * BMESH COPY MESH
+ *
+ * Internal Copy function. copies flagged elements from
+ * source to target, which may in fact be the same mesh.
+ * Note that if __flag is 0, all elements will be copied.
+ *
+*/
+
+static void bmesh_copy_mesh(BMMesh *source, BMMesh *target, int __flag)
+{
+
+ BMVert *v;
+ BMEdge *e, **edar;
+ BMLoop *l;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+ BMIter loops;
+
+ GHash *vhash;
+ GHash *ehash;
+
+ int maxlength = 0, flag;
+
+ /*initialize pointer hashes*/
+ vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ ehash = BLI_ghash_new(BLI_ghashutil_ptrrhash, BLI_ghashutil_ptrcmp);
+
+ /*initialize edge pointer array*/
+ for(f = BMeshIter_init(faces, BM_FACES, source, 0); f; f = BMeshIter_step(faces)){
+ if(f->len > maxlength) maxlength = f->len;
+ }
+ edar = MEM_callocN(sizeof(BMEdge*) * maxlength, "BM copy mesh edge pointer array");
+
+ /*begin modelling loop for target*/
+ bmesh_begin_edit(target);
+
+ /*we make special exception for __flag == 0... we copy all*/
+ if(!__flag){
+ flag = BMESH_DUPE;
+ for(v = BMeshIter_init(verts, BM_VERTS, source, 0); v; v = BMeshIter_step(verts)) bmesh_set_flag(v, BMESH_DUPE);
+ for(e = BMeshIter_init(verts, BM_EDGES, source, 0); e; e = BMeshIter_step(edges)) bmesh_set_flag(e, BMESH_DUPE);
+ for(f = BMeshIter_init(faces, BM_FACES, source, 0); f; f = BMeshIter_step(faces)) bmesh_set_flag(f, BMESH_DUPE);
+ } else{
+ flag = __flag;
+ }
+
+ /*first we dupe all flagged faces and their elements from source*/
+ for(f = BMeshIter_init(faces, BM_FACES, source, 0); f; f= BMeshIter_step(faces)){
+ if(bmesh_test_flag(f, flag)){
+ /*vertex pass*/
+ for(l = BMeshIter_init(loops, BMESH_LOOP_OF_MESH, f, 0); l; l = BMeshIter_step(loops)){
+ if(!bmesh_test_flag(l->v, BMESH_DUPED)){
+ bmesh_copy_vertex(source,l->v, target, vhash);
+ bmesh_set_flag(l->v, BMESH_DUPED);
+ }
+ }
+
+ /*edge pass*/
+ for(l = BMeshIter_init(loops, BMESH_LOOP_OF_MESH, f, 0); l; l = BMeshIter_step(loops)){
+ if(!bmesh_test_flag(l->e, BMESH_DUPED)){
+ bmesh_copy_edge(source, l->e, target, vhash, ehash);
+ bmesh_set_flag(l->e, BMESH_DUPED);
+ }
+ }
+ bmesh_copy_face(source, f, target, edar, vhash, ehash);
+ bmesh_set_flag(f, BMESH_DUPED);
+ }
+ }
+
+ /*now we dupe all the edges*/
+ for(e = BMeshIter_init(edges, BM_EDGES, source, 0); e; e = BMeshIter_step(edges)){
+ if(bmesh_test_flag(e, flag) && (!bmesh_test_flag(e, BMESH_DUPED))){
+ /*make sure that verts are copied*/
+ if(!bmesh_test_flag(e->v1, BMESH_DUPED)){
+ bmesh_copy_vertex(source, e->v1, target, vhash);
+ bmesh_set_flag(e->v1, BMESH_DUPED);
+ }
+ if(!bmesh_test_flag(e->v2, BMESH_DUPED)){
+ bmesh_copy_vertex(source, e->v2, target, vhash);
+ bmesh_set_flag(e->v2, BMESH_DUPED);
+ }
+ /*now copy the actual edge*/
+ bmesh_copy_edge(source, e, target, vhash, ehash);
+ bmesh_set_flag(e, BMESH_DUPED);
+ }
+ }
+
+ /*finally dupe all loose vertices*/
+ for(v = BMeshIter_init(verts, BM_VERTS, bm, 0); v; v = BMeshIter_step(verts)){
+ if(bmesh_test_flag(v, flag) && (!bmesh_test_flag(v, BMESH_DUPED))){
+ bmesh_copy_vertex(source, v, target, vhash);
+ bmesh_set_flag(v, BMESH_DUPED);
+ }
+ }
+
+ /*finish*/
+ bmesh_end_edit(target, BMESH_CALC_NORM | BMESH_CALC_TESS);
+
+ /*free pointer hashes*/
+ BLI_ghash_free(vhash, NULL, NULL);
+ BLI_ghash_free(ehash, NULL, NULL);
+
+ /*free edge pointer array*/
+ MEM_freeN(edar);
+}
+
+/*
+ * BMESH MAKE MESH FROM MESH
+ *
+ * Creates a new mesh by duplicating an existing one.
+ *
+*/
+
+BMMesh *bmesh_make_mesh_from_mesh(BMMesh *bm, int allocsize[4])
+{
+ BMMesh *target = NULL;
+ target = bmesh_make_mesh(allocsize);
+
+ /*copy custom data layout*/
+ CustomData_copy(&bm->vdata, &target->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->edata, &target->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->ldata, &target->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->pdata, &target->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+ /*initialize memory pools*/
+ CustomData_bmesh_init_pool(&target->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&target->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&target->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&target->pdata, allocsize[3]);
+
+ bmesh_begin_edit(bm);
+ bmesh_begin_edit(target);
+
+ bmesh_copy_mesh(bm, target, 0); /*copy all elements*/
+
+ bmesh_end_edit(bm);
+ bmesh_end_edit(target);
+
+ return target;
+
+}
+
+/*
+ * BMESH SPLIT MESH
+ *
+ * Copies flagged elements then deletes them.
+ *
+*/
+
+void bmesh_split_mesh(BMMesh *bm, int flag){
+
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ bmesh_begin_edit(bm);
+ bmesh_copy_mesh(bm, bm, flag);
+
+ /*mark verts for deletion*/
+ for(v = BMeshIter_init(verts, BM_VERTS, bm, 0); v; v = BMeshIter_step(verts)){
+ if(bmesh_test_flag(v, flag)) bmesh_delete_vert(bm, v);
+ }
+ /*mark edges for deletion*/
+ for(e = BMeshIter_init(edges, BM_EDGES, bm, 0); e; e = BMeshIter_step(edges)){
+ if(bmesh_test_flag(e, flag)) bmesh_delete_edge(bm, e);
+
+ }
+ /*mark faces for deletion*/
+ for(f = BMeshIter_init(faces, BM_FACES, bm, 0); f; f= BMeshIter_step(faces)){
+ if(bmesh_tes t_flag(f, flag)) bmesh_delete_face(bm, f);
+
+ }
+ bmesh_end_edit(bm);
+}
+
diff --git a/source/blender/bmesh/tools/BME_extrude.c b/source/blender/bmesh/tools/BME_extrude.c
new file mode 100644
index 00000000000..70baff2adf6
--- /dev/null
+++ b/source/blender/bmesh/tools/BME_extrude.c
@@ -0,0 +1,216 @@
+/**
+ * BMESH EXTRUDE TOOL
+ *
+ * A rewrite of the old editmesh extrude code with the
+ * redundant parts broken into multiple functions
+ * in an effort to reduce code. This works with multiple
+ * selection modes, and is intended to build the
+ * extrusion in steps, depending on what elements are selected.
+ * Also decoupled the calculation of transform normal
+ * and put it in UI where it probably is more appropriate
+ * for the moment.
+ *
+ * TODO:
+ * -Fit this into the new 'easy' API.
+*/
+
+void BME_extrude_verts(BME_Mesh *bm, GHash *vhash){
+ BMVert *v, *nv = NULL;
+ BMEdge *ne = NULL;
+ float vec[3];
+
+ //extrude the vertices
+ for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){
+ if(BME_SELECTED(v)){
+ VECCOPY(vec,v->co);
+ nv = BME_MV(bm,vec);
+ nv->tflag2 =1; //mark for select
+ ne = BME_ME(bm,v,nv);
+ ne->tflag1 = 2; //mark as part of skirt 'ring'
+ BLI_ghash_insert(vhash,v,nv);
+ BME_VISIT(v);
+ }
+ }
+}
+
+void BME_extrude_skirt(BME_Mesh *bm, GHash *ehash){
+
+ BMFace *nf=NULL;
+ BMEdge *e, *l=NULL, *r=NULL, *edar[4], *ne;
+ BMVert *v, *v1, *v2, *lv, *rv, *nv;
+
+ for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){
+ if(BME_SELECTED(e)){
+ /*find one face incident upon e and use it for winding of new face*/
+ if(e->l){
+ v1 = e->l->next->v;
+ v2 = e->l->v;
+ }
+ else{
+ v1 = e->v1;
+ v2 = e->v2;
+ }
+
+ if(v1->e->tflag1 == 2) l = v1->e;
+ else l = BME_disk_next_edgeflag(v1->e, v1, 0, 2);
+ if(v2->e->tflag1 == 2) r = v2->e;
+ else r = BME_disk_next_edgeflag(v2->e, v2, 0, 2);
+
+ lv = BME_edge_getothervert(l,v1);
+ rv = BME_edge_getothervert(r,v2);
+
+ ne = BME_ME(bm,lv,rv);
+ ne->tflag2 = 1; //mark for select
+ BLI_ghash_insert(ehash,e,ne);
+ BME_VISIT(e);
+
+ edar[0] = e;
+ edar[1] = l;
+ edar[2] = ne;
+ edar[3] = r;
+ BME_MF(bm,v1,v2,edar,4);
+ }
+ }
+}
+
+void BME_cap_skirt(BME_Mesh *bm, GHash *vhash, GHash *ehash){
+ BMVert *v, *nv, *v1, *v2;
+ BMEdge *e, **edar, *ne;
+ BME_Loop *l;
+ BMFace *f, *nf;
+ MemArena *edgearena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
+ float vec[3];
+ int i, j, del_old =0;
+
+
+ //loop through faces, then loop through their verts. If the verts havnt been visited yet, duplicate these.
+ for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){
+ if(BME_SELECTED(f)){
+ l = f->loopbase;
+ do{
+ if(!(BME_ISVISITED(l->v))){ //interior vertex
+ //dupe vert
+ VECCOPY(vec,l->v->co);
+ nv = BME_MV(bm,vec);
+ BLI_ghash_insert(vhash,l->v,nv);
+ //mark for delete
+ l->v->tflag1 = 1;
+ BME_VISIT(l->v); //we dont want to dupe it again.
+ }
+ l=l->next;
+ }while(l!=f->lbase);
+ }
+ }
+
+ //find out if we delete old faces or not. This needs to be improved a lot.....
+ for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){
+ if(BME_SELECTED(e) && e->l){
+ i= BME_cycle_length(&(e->l->radial));
+ if(i > 2){
+ del_old = 1;
+ break;
+ }
+ }
+ }
+
+
+ //build a new edge net, insert the new edges into the edge hash
+ for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){
+ if(BME_SELECTED(f)){
+ l=f->loopbase;
+ do{
+ if(!(BME_ISVISITED(l->e))){ //interior edge
+ //dupe edge
+ ne = BME_ME(bm,BLI_ghash_lookup(vhash,l->e->v1),BLI_ghash_lookup(vhash,l->e->v2));
+ BLI_ghash_insert(ehash,l->e,ne);
+ //mark for delete
+ l->e->tflag1 = 1;
+ BME_VISIT(l->e); //we dont want to dupe it again.
+ }
+ l=l->next;
+ }while(l!=f->lbase);
+ }
+ }
+
+ //build new faces. grab edges from edge hash.
+ for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){
+ if(BME_SELECTED(f)){
+ edar = MEM_callocN(sizeof(BMEdge*)*f->len,"Extrude array");
+ v1 = BLI_ghash_lookup(vhash,f->loopbase->v);
+ v2 = BLI_ghash_lookup(vhash,f->loopbase->next->v);
+ for(i=0,l=f->loopbase; i < f->len; i++,l=l->next){
+ ne = BLI_ghash_lookup(ehash,l->e);
+ edar[i] = ne;
+ }
+ nf=BME_MF(bm,v1,v2,edar,f->len);
+ nf->tflag2 = 1; // mark for select
+ if(del_old) f->tflag1 = 1; //mark for delete
+ MEM_freeN(edar);
+ }
+ }
+ BLI_memarena_free(edgearena);
+}
+
+/*unified extrude code*/
+void BME_extrude_mesh(BME_Mesh *bm, int type){
+
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+ BME_Loop *l;
+
+ struct GHash *vhash, *ehash;
+ /*Build a hash table of old pointers and new pointers.*/
+ vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+ BME_selectmode_flush(bm); //ensure consistent selection. contains hack to make sure faces get consistent select.
+ if(type & BME_EXTRUDE_FACES){ //Find selected edges with more than one incident face that is also selected. deselect them.
+ for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){
+ int totsel=0;
+ if(e->l){
+ l= e->l;
+ do{
+ if(BME_SELECTED(l->f)) totsel++;
+ l=BME_radial_nextloop(l);
+ }while(l!=e->l);
+ }
+ if(totsel > 1) BME_select_edge(bm,e,0);
+ }
+ }
+
+ /*another hack to ensure consistent selection.....*/
+ for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){
+ if(BME_SELECTED(e)) BME_select_edge(bm,e,1);
+ }
+
+ /*now we are ready to extrude*/
+ if(type & BME_EXTRUDE_VERTS) BME_extrude_verts(bm,vhash);
+ if(type & BME_EXTRUDE_EDGES) BME_extrude_skirt(bm,ehash);
+ if(type & BME_EXTRUDE_FACES) BME_cap_skirt(bm,vhash,ehash);
+
+ /*clear all selection flags*/
+ BME_clear_flag_all(bm, SELECT|BME_VISITED);
+ /*go through and fix up selection flags. Anything with BME_NEW should be selected*/
+ for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){
+ if(f->tflag2 == 1) BME_select_poly(bm,f,1);
+ if(f->tflag1 == 1) BME_VISIT(f); //mark for delete
+ }
+ for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){
+ if(e->tflag2 == 1) BME_select_edge(bm,e,1);
+ if(e->tflag1 == 1) BME_VISIT(e); // mark for delete
+ }
+ for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){
+ if(v->tflag2 == 1) BME_select_vert(bm,v,1);
+ if(v->tflag1 == 1) BME_VISIT(v); //mark for delete
+ }
+ /*go through and delete all of our old faces , edges and vertices.*/
+ remove_tagged_polys(bm);
+ remove_tagged_edges(bm);
+ remove_tagged_verts(bm);
+ /*free our hash tables*/
+ BLI_ghash_free(vhash,NULL, NULL); //check usage!
+ BLI_ghash_free(ehash,NULL, NULL); //check usage!
+ BME_selectmode_flush(bm);
+}
+
diff --git a/source/blender/bmesh/tools/BME_weld.c b/source/blender/bmesh/tools/BME_weld.c
new file mode 100644
index 00000000000..a17c07addbc
--- /dev/null
+++ b/source/blender/bmesh/tools/BME_weld.c
@@ -0,0 +1,333 @@
+/*
+ * BME_WELD.C
+ *
+ * This file contains functions for welding
+ * elements in a mesh togather (remove doubles,
+ * collapse, ect).
+ *
+ * TODO:
+ * -Rewrite this to fit into the new API
+ * -Seperate out find doubles code and put it in
+ * BME_queries.c
+ *
+*/
+
+
+/********* qsort routines *********/
+
+
+typedef struct xvertsort {
+ float x;
+ BMVert *v1;
+} xvertsort;
+
+static int vergxco(const void *v1, const void *v2)
+{
+ const xvertsort *x1=v1, *x2=v2;
+
+ if( x1->x > x2->x ) return 1;
+ else if( x1->x < x2->x) return -1;
+ return 0;
+}
+
+struct facesort {
+ unsigned long x;
+ struct BMFace *f;
+};
+
+
+static int vergface(const void *v1, const void *v2)
+{
+ const struct facesort *x1=v1, *x2=v2;
+
+ if( x1->x > x2->x ) return 1;
+ else if( x1->x < x2->x) return -1;
+ return 0;
+}
+
+
+
+/*break this into two functions.... 'find doubles' and 'remove doubles'?*/
+
+static void BME_remove_doubles__splitface(BME_Mesh *bm,BMFace *f,GHash *vhash){
+ BMVert *doub=NULL, *target=NULL;
+ BME_Loop *l;
+ BMFace *f2=NULL;
+ int split=0;
+
+ l=f->loopbase;
+ do{
+ if(l->v->tflag1 == 2){
+ target = BLI_ghash_lookup(vhash,l->v);
+ if((BME_vert_in_face(target,f)) && (target != l->next->v) && (target != l->prev->v)){
+ doub = l->v;
+ split = 1;
+ break;
+ }
+ }
+
+ l= l->next;
+ }while(l!= f->loopbase);
+
+ if(split){
+ f2 = BME_SFME(bm,f,doub,target,NULL);
+ BME_remove_doubles__splitface(bm,f,vhash);
+ BME_remove_doubles__splitface(bm,f2,vhash);
+ }
+}
+
+int BME_remove_doubles(BME_Mesh *bm, float limit)
+{
+
+ /* all verts with (flag & 'flag') are being evaluated */
+ BMVert *v, *v2, *target;
+ BMEdge *e, **edar, *ne;
+ BME_Loop *l;
+ BMFace *f, *nf;
+ xvertsort *sortblock, *sb, *sb1;
+ struct GHash *vhash;
+ struct facesort *fsortblock, *vsb, *vsb1;
+ int a, b, test, amount=0, found;
+ float dist;
+
+ /*Build a hash table of doubles to thier target vert/edge.*/
+ vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+ /*count amount of selected vertices*/
+ for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){
+ if(BME_SELECTED(v))amount++;
+ }
+
+ /*qsort vertices based upon average of coordinate. We test this way first.*/
+ sb= sortblock= MEM_mallocN(sizeof(xvertsort)*amount,"sortremovedoub");
+
+ for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){
+ if(BME_SELECTED(v)){
+ sb->x = v->co[0]+v->co[1]+v->co[2];
+ sb->v1 = v;
+ sb++;
+ }
+ }
+ qsort(sortblock, amount, sizeof(xvertsort), vergxco);
+
+ /* test for doubles */
+ sb= sortblock;
+ for(a=0; a<amount; a++) {
+ v= sb->v1;
+ if(!(v->tflag1)) { //have we tested yet?
+ sb1= sb+1;
+ for(b=a+1; b<amount; b++) {
+ /* first test: simple distance. Simple way to discard*/
+ dist= sb1->x - sb->x;
+ if(dist > limit) break;
+
+ /* second test: have we already done this vertex?
+ (eh this should be swapped, simple equality test should be cheaper than math above... small savings
+ though) */
+ v2= sb1->v1;
+ if(!(v2->tflag1)) {
+ dist= (float)fabs(v2->co[0]-v->co[0]);
+ if(dist<=limit) {
+ dist= (float)fabs(v2->co[1]-v->co[1]);
+ if(dist<=limit) {
+ dist= (float)fabs(v2->co[2]-v->co[2]);
+ if(dist<=limit) {
+ /*v2 is a double of v. We want to throw out v1 and relink everything to v*/
+ BLI_ghash_insert(vhash,v2, v);
+ v->tflag1 = 1; //mark this vertex as a target
+ v->tflag2++; //increase user count for this vert.
+ v2->tflag1 = 2; //mark this vertex as a double.
+ BME_VISIT(v2); //mark for delete
+ }
+ }
+ }
+ }
+ sb1++;
+ }
+ }
+ sb++;
+ }
+ MEM_freeN(sortblock);
+
+
+ /*todo... figure out what this is for...
+ for(eve = em->verts.first; eve; eve=eve->next)
+ if((eve->f & flag) && (eve->f & 128))
+ EM_data_interp_from_verts(eve, eve->tmp.v, eve->tmp.v, 0.5f);
+ */
+
+ /*We cannot collapse a vertex onto another vertex if they share a face and are not connected via a collapsable edge.
+ so to deal with this we simply find these offending vertices and split the faces. Note that this is not optimal, but works.
+ */
+
+
+ for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){
+ if(!(BME_NEWELEM(f))){
+ BME_remove_doubles__splitface(bm,f,vhash);
+ }
+ }
+
+ for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){
+ /*If either vertices of this edge are a double, we must mark it for removal and we create a new one.*/
+ if(e->v1->tflag1 == 2 || e->v2->tflag1 == 2){
+ v = v2 = NULL;
+ /*For each vertex in the edge, test to find out what it should equal now.*/
+ if(e->v1->tflag1 == 2) v= BLI_ghash_lookup(vhash,e->v1);
+ else v = e->v1;
+ if(e->v2->tflag1 == 2) v2 = BLI_ghash_lookup(vhash,e->v2);
+ else v2 = e->v2;
+
+ /*small optimization, test to see if the edge needs to be rebuilt at all*/
+ if((e->v1 != v) || (e->v2 != v2)){ /*will this always be true of collapsed edges?*/
+ if(v == v2) e->tflag1 = 2; /*mark as a collapsed edge*/
+ else if(!BME_disk_existedge(v,v2)) ne = BME_ME(bm,v,v2);
+ BME_VISIT(e); /*mark for delete*/
+ }
+ }
+ }
+
+
+ /*need to remove double edges as well. To do this we decide on one edge to keep, and if its inserted into hash then we need to remove all other
+ edges incident upon and relink.*/
+ /*
+ * REBUILD FACES
+ *
+ * Loop through double faces and if they have vertices that have been flagged, they need to be rebuilt.
+ * We do this by looking up the face
+ *rebuild faces. loop through original face, for each loop, if the edge it is attached to is marked for delete and has no
+ *other edge in the hash edge, then we know to skip that loop on face recreation. Simple.
+ */
+
+ /*1st loop through, just marking elements*/
+ for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ //insert bit here about double edges, mark with a flag (e->tflag2) so that we can nuke it later.
+ l = f->loopbase;
+ do{
+ if(l->v->tflag1 == 2) f->tflag1 = 1; //double, mark for rebuild
+ if(l->e->tflag1 != 2) f->tflag2++; //count number of edges in the new face.
+ l=l->next;
+ }while(l!=f->loopbase);
+ }
+
+ /*now go through and create new faces*/
+ for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){
+ if(f->tflag1 && f->tflag2 < 3) BME_VISIT(f); //mark for delete
+ else if (f->tflag1 == 1){ /*is the face marked for rebuild*/
+ edar = MEM_callocN(sizeof(BMEdge *)*f->tflag2,"Remove doubles face creation array.");
+ a=0;
+ l = f->loopbase;
+ do{
+ v = l->v;
+ v2 = l->next->v;
+ if(l->v->tflag1 == 2) v = BLI_ghash_lookup(vhash,l->v);
+ if(l->next->v->tflag1 == 2) v2 = BLI_ghash_lookup(vhash,l->next->v);
+ ne = BME_disk_existedge(v,v2); //use BME_disk_next_edgeflag here or something to find the edge that is marked as 'target'.
+ //add in call here to edge doubles hash array... then bobs your uncle.
+ if(ne){
+ edar[a] = ne;
+ a++;
+ }
+ l=l->next;
+ }while(l!=f->loopbase);
+
+ if(BME_vert_in_edge(edar[1],edar[0]->v2)){
+ v = edar[0]->v1;
+ v2 = edar[0]->v2;
+ }
+ else{
+ v = edar[0]->v2;
+ v2 = edar[0]->v1;
+ }
+
+ nf = BME_MF(bm,v,v2,edar,f->tflag2);
+
+ /*copy per loop data here*/
+ if(nf){
+ BME_VISIT(f); //mark for delete
+ }
+ MEM_freeN(edar);
+ }
+ }
+
+ /*count amount of removed vert doubles*/
+ a = 0;
+ for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){
+ if(v->tflag1 == 2) a++;
+ }
+
+ /*free memory and return amount removed*/
+ remove_tagged_polys(bm);
+ remove_tagged_edges(bm);
+ remove_tagged_verts(bm);
+ BLI_ghash_free(vhash,NULL, NULL);
+ BME_selectmode_flush(bm);
+ return a;
+}
+
+static void BME_MeshWalk__collapsefunc(void *userData, BMEdge *applyedge){
+ int index;
+ GHash *collected = userData;
+ index = BLI_ghash_size(collected);
+ if(!BLI_ghash_lookup(collected,applyedge->v1)){
+ BLI_ghash_insert(collected,index,applyedge->v1);
+ index++;
+ }
+ if(!BLI_ghash_lookup(collected,applyedge->v2)){
+ BLI_ghash_insert(collected,index,applyedge->v2);
+ }
+}
+
+void BME_collapse_edges(BME_Mesh *bm){
+
+ BMVert *v, *cvert;
+ GHash *collected;
+ float min[3], max[3], cent[3];
+ int size, i=0, j, num=0;
+
+ for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){
+ if(!(BME_ISVISITED(v)) && v->edge){
+ /*initiate hash table*/
+ collected = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ /*do the walking.*/
+ BME_MeshWalk(bm,v,BME_MeshWalk__collapsefunc,collected,BME_RESTRICTSELECT);
+ /*now loop through the hash table twice, once to calculate bounding box, second time to do the actual collapse*/
+ size = BLI_ghash_size(collected);
+ /*initial values*/
+ VECCOPY(min,v->co);
+ VECCOPY(max,v->co);
+ cent[0] = cent[1] = cent[2]=0;
+ for(i=0; i<size; i++){
+ cvert = BLI_ghash_lookup(collected,i);
+ cent[0] = cent[0] + cvert->co[0];
+ cent[1] = cent[1] + cvert->co[1];
+ cent[2] = cent[2] + cvert->co[2];
+ }
+
+ cent[0] = cent[0] / size;
+ cent[1] = cent[1] / size;
+ cent[2] = cent[2] / size;
+
+ for(i=0; i<size; i++){
+ cvert = BLI_ghash_lookup(collected,i);
+ VECCOPY(cvert->co,cent);
+ num++;
+ }
+ /*free the hash table*/
+ BLI_ghash_free(collected,NULL, NULL);
+ }
+ }
+ /*if any collapsed, call remove doubles*/
+ if(num){
+ //need to change selection mode here, OR do something else? Or does tool change selection mode?
+ //selectgrep
+ //first clear flags
+ BMEdge *e;
+ BMFace *f;
+ BME_clear_flag_all(bm,BME_VISITED);
+ for(v=BME_first(bm,BME_VERT); v; v=BME_next(bm,BME_VERT,v)) v->tflag1 = v->tflag2 = 0;
+ for(e=BME_first(bm,BME_EDGE); e; e=BME_next(bm,BME_EDGE,e)) e->tflag1 = e->tflag2 = 0;
+ for(f=BME_first(bm,BME_POLY); f; f=BME_next(bm,BME_POLY,f)) f->tflag1 = f->tflag2 = 0;
+ /*now call remove doubles*/
+ BME_remove_doubles(bm,0.0000001);
+ }
+ BME_selectmode_flush(bm);
+} \ No newline at end of file
diff --git a/source/blender/collada/CMakeLists.txt b/source/blender/collada/CMakeLists.txt
index 73e81025226..3f8abb7ed5d 100644
--- a/source/blender/collada/CMakeLists.txt
+++ b/source/blender/collada/CMakeLists.txt
@@ -100,9 +100,17 @@ if(WITH_BUILDINFO)
add_definitions(-DNAN_BUILDINFO)
endif()
+<<<<<<< .working
+IF(WITH_BUILDINFO)
+ ADD_DEFINITIONS(-DNAN_BUILDINFO)
+ENDIF(WITH_BUILDINFO)
+
+BLENDERLIB(bf_collada "${SRC}" "${INC}")
+=======
if(CMAKE_COMPILER_IS_GNUCXX)
# COLLADAFWArray.h gives error with gcc 4.5
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
endif()
blender_add_lib(bf_collada "${SRC}" "${INC}")
+>>>>>>> .merge-right.r35190
diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp
index 9d9d105d04d..1a648f43097 100644
--- a/source/blender/collada/DocumentExporter.cpp
+++ b/source/blender/collada/DocumentExporter.cpp
@@ -290,6 +290,446 @@ public:
}
};
+<<<<<<< .working
+class ImagesExporter: COLLADASW::LibraryImages
+{
+ const char *mfilename;
+ std::vector<std::string> mImages; // contains list of written images, to avoid duplicates
+public:
+ ImagesExporter(COLLADASW::StreamWriter *sw, const char* filename) : COLLADASW::LibraryImages(sw), mfilename(filename)
+ {}
+
+ void exportImages(Scene *sce)
+ {
+ openLibrary();
+
+ forEachMaterialInScene(sce, *this);
+
+ closeLibrary();
+ }
+
+ void operator()(Material *ma, Object *ob)
+ {
+ int a;
+ for (a = 0; a < MAX_MTEX; a++) {
+ MTex *mtex = ma->mtex[a];
+ if (mtex && mtex->tex && mtex->tex->ima) {
+
+ Image *image = mtex->tex->ima;
+ std::string name(id_name(image));
+ name = translate_id(name);
+ char rel[FILE_MAX];
+ char abs[FILE_MAX];
+ char src[FILE_MAX];
+ char dir[FILE_MAX];
+
+ BLI_split_dirfile(mfilename, dir, NULL);
+
+ BKE_rebase_path(abs, sizeof(abs), rel, sizeof(rel), G.sce, image->name, dir);
+
+ if (abs[0] != '\0') {
+
+ // make absolute source path
+ BLI_strncpy(src, image->name, sizeof(src));
+ BLI_path_abs(src, G.sce);
+
+ // make dest directory if it doesn't exist
+ BLI_make_existing_file(abs);
+
+ if (BLI_copy_fileops(src, abs) != 0) {
+ fprintf(stderr, "Cannot copy image to file's directory. \n");
+ }
+ }
+
+ if (find(mImages.begin(), mImages.end(), name) == mImages.end()) {
+ COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(rel)), name);
+ img.add(mSW);
+
+ mImages.push_back(name);
+ }
+ }
+ }
+ }
+};
+
+class EffectsExporter: COLLADASW::LibraryEffects
+{
+public:
+ EffectsExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryEffects(sw){}
+ void exportEffects(Scene *sce)
+ {
+ openLibrary();
+
+ forEachMaterialInScene(sce, *this);
+
+ closeLibrary();
+ }
+
+ void operator()(Material *ma, Object *ob)
+ {
+ // create a list of indices to textures of type TEX_IMAGE
+ std::vector<int> tex_indices;
+ createTextureIndices(ma, tex_indices);
+
+ openEffect(translate_id(id_name(ma)) + "-effect");
+
+ COLLADASW::EffectProfile ep(mSW);
+ ep.setProfileType(COLLADASW::EffectProfile::COMMON);
+ ep.openProfile();
+ // set shader type - one of three blinn, phong or lambert
+ if (ma->spec_shader == MA_SPEC_BLINN) {
+ ep.setShaderType(COLLADASW::EffectProfile::BLINN);
+ // shininess
+ ep.setShininess(ma->spec);
+ }
+ else if (ma->spec_shader == MA_SPEC_PHONG) {
+ ep.setShaderType(COLLADASW::EffectProfile::PHONG);
+ // shininess
+ // XXX not sure, stolen this from previous Collada plugin
+ ep.setShininess(ma->har / 4);
+ }
+ else {
+ // XXX write warning "Current shader type is not supported"
+ ep.setShaderType(COLLADASW::EffectProfile::LAMBERT);
+ }
+ // index of refraction
+ if (ma->mode & MA_RAYTRANSP) {
+ ep.setIndexOfRefraction(ma->ang);
+ }
+ else {
+ ep.setIndexOfRefraction(1.0f);
+ }
+
+ COLLADASW::ColorOrTexture cot;
+
+ // transparency
+ // Tod: because we are in A_ONE mode transparency is calculated like this:
+ ep.setTransparency(1.0f);
+ cot = getcol(0.0f, 0.0f, 0.0f, ma->alpha);
+ ep.setTransparent(cot);
+
+ // emission
+ cot=getcol(ma->emit, ma->emit, ma->emit, 1.0f);
+ ep.setEmission(cot);
+
+ // diffuse
+ cot = getcol(ma->r, ma->g, ma->b, 1.0f);
+ ep.setDiffuse(cot);
+
+ // ambient
+ cot = getcol(ma->ambr, ma->ambg, ma->ambb, 1.0f);
+ ep.setAmbient(cot);
+
+ // reflective, reflectivity
+ if (ma->mode & MA_RAYMIRROR) {
+ cot = getcol(ma->mirr, ma->mirg, ma->mirb, 1.0f);
+ ep.setReflective(cot);
+ ep.setReflectivity(ma->ray_mirror);
+ }
+ else {
+ cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f);
+ ep.setReflective(cot);
+ ep.setReflectivity(ma->spec);
+ }
+
+ // specular
+ if (ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT) {
+ cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f);
+ ep.setSpecular(cot);
+ }
+
+ // XXX make this more readable if possible
+
+ // create <sampler> and <surface> for each image
+ COLLADASW::Sampler samplers[MAX_MTEX];
+ //COLLADASW::Surface surfaces[MAX_MTEX];
+ //void *samp_surf[MAX_MTEX][2];
+ void *samp_surf[MAX_MTEX][1];
+
+ // image to index to samp_surf map
+ // samp_surf[index] stores 2 pointers, sampler and surface
+ std::map<std::string, int> im_samp_map;
+
+ unsigned int a, b;
+ for (a = 0, b = 0; a < tex_indices.size(); a++) {
+ MTex *t = ma->mtex[tex_indices[a]];
+ Image *ima = t->tex->ima;
+
+ std::string key(id_name(ima));
+ key = translate_id(key);
+
+ // create only one <sampler>/<surface> pair for each unique image
+ if (im_samp_map.find(key) == im_samp_map.end()) {
+ //<newparam> <surface> <init_from>
+ // COLLADASW::Surface surface(COLLADASW::Surface::SURFACE_TYPE_2D,
+// key + COLLADASW::Surface::SURFACE_SID_SUFFIX);
+// COLLADASW::SurfaceInitOption sio(COLLADASW::SurfaceInitOption::INIT_FROM);
+// sio.setImageReference(key);
+// surface.setInitOption(sio);
+
+ //<newparam> <sampler> <source>
+ COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
+ key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
+ key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
+ sampler.setImageId(key);
+ // copy values to arrays since they will live longer
+ samplers[a] = sampler;
+ //surfaces[a] = surface;
+
+ // store pointers so they can be used later when we create <texture>s
+ samp_surf[b][0] = &samplers[a];
+ //samp_surf[b][1] = &surfaces[a];
+
+ im_samp_map[key] = b;
+ b++;
+ }
+ }
+
+ // used as fallback when MTex->uvname is "" (this is pretty common)
+ // it is indeed the correct value to use in that case
+ std::string active_uv(getActiveUVLayerName(ob));
+
+ // write textures
+ // XXX very slow
+ for (a = 0; a < tex_indices.size(); a++) {
+ MTex *t = ma->mtex[tex_indices[a]];
+ Image *ima = t->tex->ima;
+
+ // we assume map input is always TEXCO_UV
+
+ std::string key(id_name(ima));
+ key = translate_id(key);
+ int i = im_samp_map[key];
+ COLLADASW::Sampler *sampler = (COLLADASW::Sampler*)samp_surf[i][0];
+ //COLLADASW::Surface *surface = (COLLADASW::Surface*)samp_surf[i][1];
+
+ std::string uvname = strlen(t->uvname) ? t->uvname : active_uv;
+
+ // color
+ if (t->mapto & MAP_COL) {
+ ep.setDiffuse(createTexture(ima, uvname, sampler));
+ }
+ // ambient
+ if (t->mapto & MAP_AMB) {
+ ep.setAmbient(createTexture(ima, uvname, sampler));
+ }
+ // specular
+ if (t->mapto & MAP_SPEC) {
+ ep.setSpecular(createTexture(ima, uvname, sampler));
+ }
+ // emission
+ if (t->mapto & MAP_EMIT) {
+ ep.setEmission(createTexture(ima, uvname, sampler));
+ }
+ // reflective
+ if (t->mapto & MAP_REF) {
+ ep.setReflective(createTexture(ima, uvname, sampler));
+ }
+ // alpha
+ if (t->mapto & MAP_ALPHA) {
+ ep.setTransparent(createTexture(ima, uvname, sampler));
+ }
+ // extension:
+ // Normal map --> Must be stored with <extra> tag as different technique,
+ // since COLLADA doesn't support normal maps, even in current COLLADA 1.5.
+ if (t->mapto & MAP_NORM) {
+ COLLADASW::Texture texture(key);
+ texture.setTexcoord(uvname);
+ texture.setSampler(*sampler);
+ // technique FCOLLADA, with the <bump> tag, is most likely the best understood,
+ // most widespread de-facto standard.
+ texture.setProfileName("FCOLLADA");
+ texture.setChildElementName("bump");
+ ep.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture));
+ }
+ }
+ // performs the actual writing
+ ep.addProfileElements();
+ bool twoSided = false;
+ if (ob->type == OB_MESH && ob->data) {
+ Mesh *me = (Mesh*)ob->data;
+ if (me->flag & ME_TWOSIDED)
+ twoSided = true;
+ }
+ if (twoSided)
+ ep.addExtraTechniqueParameter("GOOGLEEARTH", "show_double_sided", 1);
+ ep.addExtraTechniques(mSW);
+
+ ep.closeProfile();
+ if (twoSided)
+ mSW->appendTextBlock("<extra><technique profile=\"MAX3D\"><double_sided>1</double_sided></technique></extra>");
+ closeEffect();
+ }
+
+ COLLADASW::ColorOrTexture createTexture(Image *ima,
+ std::string& uv_layer_name,
+ COLLADASW::Sampler *sampler
+ /*COLLADASW::Surface *surface*/)
+ {
+
+ COLLADASW::Texture texture(translate_id(id_name(ima)));
+ texture.setTexcoord(uv_layer_name);
+ //texture.setSurface(*surface);
+ texture.setSampler(*sampler);
+
+ COLLADASW::ColorOrTexture cot(texture);
+ return cot;
+ }
+
+ COLLADASW::ColorOrTexture getcol(float r, float g, float b, float a)
+ {
+ COLLADASW::Color color(r,g,b,a);
+ COLLADASW::ColorOrTexture cot(color);
+ return cot;
+ }
+
+ //returns the array of mtex indices which have image
+ //need this for exporting textures
+ void createTextureIndices(Material *ma, std::vector<int> &indices)
+ {
+ indices.clear();
+
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (ma->mtex[a] &&
+ ma->mtex[a]->tex &&
+ ma->mtex[a]->tex->type == TEX_IMAGE &&
+ ma->mtex[a]->texco == TEXCO_UV){
+ indices.push_back(a);
+ }
+ }
+ }
+};
+
+class MaterialsExporter: COLLADASW::LibraryMaterials
+{
+public:
+ MaterialsExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryMaterials(sw){}
+ void exportMaterials(Scene *sce)
+ {
+ openLibrary();
+
+ forEachMaterialInScene(sce, *this);
+
+ closeLibrary();
+ }
+
+ void operator()(Material *ma, Object *ob)
+ {
+ std::string name(id_name(ma));
+
+ openMaterial(translate_id(name), name);
+
+ std::string efid = translate_id(name) + "-effect";
+ addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, efid));
+
+ closeMaterial();
+ }
+};
+
+class CamerasExporter: COLLADASW::LibraryCameras
+{
+public:
+ CamerasExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryCameras(sw){}
+ void exportCameras(Scene *sce)
+ {
+ openLibrary();
+
+ forEachCameraObjectInScene(sce, *this);
+
+ closeLibrary();
+ }
+ void operator()(Object *ob, Scene *sce)
+ {
+ // XXX add other params later
+ Camera *cam = (Camera*)ob->data;
+ std::string cam_id(get_camera_id(ob));
+ std::string cam_name(id_name(cam));
+
+ if (cam->type == CAM_PERSP) {
+ COLLADASW::PerspectiveOptic persp(mSW);
+ persp.setXFov(1.0);
+ persp.setAspectRatio(0.1);
+ persp.setZFar(cam->clipend);
+ persp.setZNear(cam->clipsta);
+ COLLADASW::Camera ccam(mSW, &persp, cam_id, cam_name);
+ addCamera(ccam);
+ }
+ else {
+ COLLADASW::OrthographicOptic ortho(mSW);
+ ortho.setXMag(1.0);
+ ortho.setAspectRatio(0.1);
+ ortho.setZFar(cam->clipend);
+ ortho.setZNear(cam->clipsta);
+ COLLADASW::Camera ccam(mSW, &ortho, cam_id, cam_name);
+ addCamera(ccam);
+ }
+ }
+};
+
+class LightsExporter: COLLADASW::LibraryLights
+{
+public:
+ LightsExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryLights(sw){}
+ void exportLights(Scene *sce)
+ {
+ openLibrary();
+
+ forEachLampObjectInScene(sce, *this);
+
+ closeLibrary();
+ }
+ void operator()(Object *ob)
+ {
+ Lamp *la = (Lamp*)ob->data;
+ std::string la_id(get_light_id(ob));
+ std::string la_name(id_name(la));
+ COLLADASW::Color col(la->r, la->g, la->b);
+ float e = la->energy;
+
+ // sun
+ if (la->type == LA_SUN) {
+ COLLADASW::DirectionalLight cla(mSW, la_id, la_name, e);
+ cla.setColor(col);
+ addLight(cla);
+ }
+ // hemi
+ else if (la->type == LA_HEMI) {
+ COLLADASW::AmbientLight cla(mSW, la_id, la_name, e);
+ cla.setColor(col);
+ addLight(cla);
+ }
+ // spot
+ else if (la->type == LA_SPOT) {
+ COLLADASW::SpotLight cla(mSW, la_id, la_name, e);
+ cla.setColor(col);
+ cla.setFallOffAngle(la->spotsize);
+ cla.setFallOffExponent(la->spotblend);
+ cla.setLinearAttenuation(la->att1);
+ cla.setQuadraticAttenuation(la->att2);
+ addLight(cla);
+ }
+ // lamp
+ else if (la->type == LA_LOCAL) {
+ COLLADASW::PointLight cla(mSW, la_id, la_name, e);
+ cla.setColor(col);
+ cla.setLinearAttenuation(la->att1);
+ cla.setQuadraticAttenuation(la->att2);
+ addLight(cla);
+ }
+ // area lamp is not supported
+ // it will be exported as a local lamp
+ else {
+ COLLADASW::PointLight cla(mSW, la_id, la_name, e);
+ cla.setColor(col);
+ cla.setLinearAttenuation(la->att1);
+ cla.setQuadraticAttenuation(la->att2);
+ addLight(cla);
+ }
+ }
+};
+
+=======
+>>>>>>> .merge-right.r35190
// TODO: it would be better to instantiate animations rather than create a new one per object
// COLLADA allows this through multiple <channel>s in <animation>.
// For this to work, we need to know objects that use a certain action.
@@ -965,6 +1405,17 @@ void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename)
asset.setUnit(unitname, linearmeasure);
asset.setUpAxisType(COLLADASW::Asset::Z_UP);
+<<<<<<< .working
+ // TODO: need an Author field in userpref
+ asset.getContributor().mAuthor = "Blender User";
+#ifdef NAN_BUILDINFO
+ char version_buf[128];
+ sprintf(version_buf, "Blender %d.%02d.%d r%s", BLENDER_VERSION/100, BLENDER_VERSION%100, BLENDER_SUBVERSION, build_rev);
+ asset.getContributor().mAuthoringTool = version_buf;
+#else
+ asset.getContributor().mAuthoringTool = "Blender 2.5x";
+#endif
+=======
// TODO: need an Author field in userpref
if(strlen(U.author) > 0) {
asset.getContributor().mAuthor = U.author;
@@ -979,6 +1430,7 @@ void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename)
#else
asset.getContributor().mAuthoringTool = "Blender 2.5x";
#endif
+>>>>>>> .merge-right.r35190
asset.add();
// <library_cameras>
diff --git a/source/blender/editors/animation/SConscript b/source/blender/editors/animation/SConscript
index 96b05b8bccc..17f8d32ccf1 100644
--- a/source/blender/editors/animation/SConscript
+++ b/source/blender/editors/animation/SConscript
@@ -4,6 +4,11 @@ Import ('env')
sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../makesrna ../../imbuf'
+<<<<<<< .working
+incs += ' ../../windowmanager ../../bmesh'
+incs += ' #/intern/guardedalloc #/extern/glew/include'
+=======
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include ../../blenloader'
+>>>>>>> .merge-right.r35190
env.BlenderLib ( 'bf_editors_animation', sources, Split(incs), [], libtype=['core'], priority=[125] )
diff --git a/source/blender/editors/armature/SConscript b/source/blender/editors/armature/SConscript
index beabd912a20..e9694bab63f 100644
--- a/source/blender/editors/armature/SConscript
+++ b/source/blender/editors/armature/SConscript
@@ -5,6 +5,7 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf ../../blenloader'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
+incs += ' ../../render/extern/include ../../bmesh'
incs += ' ../../gpu ../../makesrna #/intern/opennl/extern'
if env['OURPLATFORM'] == 'linux2':
diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c
index 5c1d1300599..5616a3424ba 100644
--- a/source/blender/editors/armature/editarmature.c
+++ b/source/blender/editors/armature/editarmature.c
@@ -2271,7 +2271,7 @@ typedef struct UndoArmature {
ListBase lb;
} UndoArmature;
-static void undoBones_to_editBones(void *uarmv, void *armv)
+static void undoBones_to_editBones(void *uarmv, void *armv, void *data)
{
UndoArmature *uarm= uarmv;
bArmature *arm= armv;
@@ -2304,7 +2304,7 @@ static void undoBones_to_editBones(void *uarmv, void *armv)
}
}
-static void *editBones_to_undoBones(void *armv)
+static void *editBones_to_undoBones(void *armv, void *obdata)
{
bArmature *arm= armv;
UndoArmature *uarm;
@@ -4681,7 +4681,8 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i
/* for each vertex in the mesh */
for (i=0; i < mesh->totvert; i++) {
- iflip = (dgroupflip)? mesh_get_x_mirror_vert(ob, i): 0;
+ /*BMESH_TODO*/
+ iflip = 0; //(dgroupflip)? mesh_get_x_mirror_vert(ob, i): 0;
/* for each skinnable bone */
for (j=0; j < numbones; ++j) {
@@ -4874,7 +4875,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
}
/* only generated in some cases but can call anyway */
- mesh_octree_table(ob, NULL, NULL, 'e');
+ //BMESH_TODO mesh_octree_table(ob, NULL, NULL, 'e');
/* free the memory allocated */
MEM_freeN(bonelist);
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index efd671c64b3..d06464c486b 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -687,12 +687,16 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
laplacian_system_construct_end(sys);
+#if 0 /*BMESH_TODO*/
if(dgroupflip) {
vertsflipped = MEM_callocN(sizeof(int)*me->totvert, "vertsflipped");
for(a=0; a<me->totvert; a++)
vertsflipped[a] = mesh_get_x_mirror_vert(ob, a);
}
-
+#else
+ dgroupflip = 0;
+#endif
+
/* compute weights per bone */
for(j=0; j<numsource; j++) {
if(!selected[j])
@@ -1165,8 +1169,8 @@ static int meshdeform_intersect(MeshDeformBind *mdb, MeshDeformIsect *isec)
isec->labda= 1e10;
- mface= mdb->cagedm->getFaceArray(mdb->cagedm);
- totface= mdb->cagedm->getNumFaces(mdb->cagedm);
+ mface= mdb->cagedm->getTessFaceArray(mdb->cagedm);
+ totface= mdb->cagedm->getNumTessFaces(mdb->cagedm);
add_v3_v3v3(end, isec->start, isec->vec);
@@ -1855,7 +1859,7 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa
static void heat_weighting_bind(Scene *scene, DerivedMesh *dm, MeshDeformModifierData *mmd, MeshDeformBind *mdb)
{
LaplacianSystem *sys;
- MFace *mface= dm->getFaceArray(dm), *mf;
+ MFace *mface= dm->getTessFaceArray(dm), *mf;
int totvert= dm->getNumVerts(dm);
int totface= dm->getNumFaces(dm);
float solution, weight;
diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c
index 01e534cd538..c5ae60e982b 100644
--- a/source/blender/editors/armature/poseobject.c
+++ b/source/blender/editors/armature/poseobject.c
@@ -1332,9 +1332,9 @@ static int pose_group_assign_exec (bContext *C, wmOperator *op)
/* add selected bones to group then */
CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones)
{
- pchan->agrp_index= pose->active_group;
- done= 1;
- }
+ pchan->agrp_index= pose->active_group;
+ done= 1;
+ }
CTX_DATA_END;
/* notifiers for updates */
diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c
index 61ad5528607..3def3dbf611 100644
--- a/source/blender/editors/armature/reeb.c
+++ b/source/blender/editors/armature/reeb.c
@@ -52,6 +52,7 @@
//#include "BIF_toolbox.h"
//#include "BIF_graphics.h"
+#include "BKE_mesh.h"
//#include "blendef.h"
@@ -3378,9 +3379,11 @@ static int iteratorStopped(void *arg)
ReebGraph *BIF_ReebGraphMultiFromEditMesh(bContext *C)
{
+ return NULL;
+#if 0
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
- EditMesh *em =( (Mesh*)obedit->data)->edit_mesh;
+ EditMesh *em =BKE_mesh_get_editmesh(((Mesh*)obedit->data));
EdgeIndex indexed_edges;
VertexData *data;
ReebGraph *rg = NULL;
@@ -3476,7 +3479,14 @@ ReebGraph *BIF_ReebGraphMultiFromEditMesh(bContext *C)
MEM_freeN(data);
+ /*no need to load the editmesh back into the object, just
+ free it (avoids ngon conversion issues too going back the
+ other way)*/
+ free_editMesh(em);
+ MEM_freeN(em);
+
return rg;
+#endif
}
#if 0
diff --git a/source/blender/editors/curve/SConscript b/source/blender/editors/curve/SConscript
index efb56ce5466..721b269edf3 100644
--- a/source/blender/editors/curve/SConscript
+++ b/source/blender/editors/curve/SConscript
@@ -5,7 +5,11 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
+<<<<<<< .working
+incs += ' ../../gpu ../../bmesh'
+=======
incs += ' ../../gpu ../../blenloader'
+>>>>>>> .merge-right.r35190
incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern'
env.BlenderLib ( 'bf_editors_curve', sources, Split(incs), [], libtype=['core'], priority=[45] )
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index bceb103503c..86d344d566a 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -6927,7 +6927,7 @@ static void *undo_check_lastsel(void *lastsel, Nurb *nu, Nurb *newnu)
return NULL;
}
-static void undoCurve_to_editCurve(void *ucu, void *obe)
+static void undoCurve_to_editCurve(void *ucu, void *obe, void *obdata)
{
Object *obedit= obe;
Curve *cu= (Curve*)obedit->data;
@@ -6977,7 +6977,7 @@ static void undoCurve_to_editCurve(void *ucu, void *obe)
ED_curve_updateAnimPaths(obedit);
}
-static void *editCurve_to_undoCurve(void *obe)
+static void *editCurve_to_undoCurve(void *obe, void *cue)
{
Object *obedit= obe;
Curve *cu= (Curve*)obedit->data;
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 9616d452333..ef1c53c9f5d 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -1776,7 +1776,7 @@ void FONT_OT_unlink(wmOperatorType *ot)
/* **************** undo for font object ************** */
-static void undoFont_to_editFont(void *strv, void *ecu)
+static void undoFont_to_editFont(void *strv, void *ecu, void *obdata)
{
Curve *cu= (Curve *)ecu;
EditFont *ef= cu->editfont;
@@ -1793,7 +1793,7 @@ static void undoFont_to_editFont(void *strv, void *ecu)
update_string(cu);
}
-static void *editFont_to_undoFont(void *ecu)
+static void *editFont_to_undoFont(void *ecu, void *obdata)
{
Curve *cu= (Curve *)ecu;
EditFont *ef= cu->editfont;
diff --git a/source/blender/editors/datafiles/SConscript b/source/blender/editors/datafiles/SConscript
index dd0db90af44..0cbeb96ffdb 100644
--- a/source/blender/editors/datafiles/SConscript
+++ b/source/blender/editors/datafiles/SConscript
@@ -4,6 +4,6 @@ Import ('env')
sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
-incs += ' #/intern/guardedalloc'
+incs += ' ../../bmesh #/intern/guardedalloc'
env.BlenderLib ( 'bf_editor_datafiles', sources, Split(incs), [], libtype=['core', 'player'], priority=[235, 30] )
diff --git a/source/blender/editors/gpencil/SConscript b/source/blender/editors/gpencil/SConscript
index d2fd9e5fe9d..e75e3f032c1 100644
--- a/source/blender/editors/gpencil/SConscript
+++ b/source/blender/editors/gpencil/SConscript
@@ -5,7 +5,11 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
+<<<<<<< .working
+incs += ' ../../gpu ../../bmesh'
+=======
incs += ' ../../gpu ../../blenloader'
+>>>>>>> .merge-right.r35190
incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern'
env.BlenderLib ( 'bf_editors_gpencil', sources, Split(incs), [], libtype=['core'], priority=[45] )
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index db594694e64..06e67128496 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -906,8 +906,8 @@ static tGPsdata *gp_session_initpaint (bContext *C)
/* supported views first */
case SPACE_VIEW3D:
{
- // View3D *v3d= curarea->spacedata.first;
- // RegionView3D *rv3d= ar->regiondata;
+ View3D *v3d= curarea->spacedata.first;
+ RegionView3D *rv3d= ar->regiondata;
/* set current area
* - must verify that region data is 3D-view (and not something else)
@@ -922,6 +922,12 @@ static tGPsdata *gp_session_initpaint (bContext *C)
return p;
}
+ /* for camera view set the subrect */
+ if(rv3d->persp == RV3D_CAMOB) {
+ view3d_calc_camera_border(p->scene, p->ar, NULL, v3d, &p->subrect_data, 1);
+ p->subrect= &p->subrect_data;
+ }
+
#if 0 // XXX will this sort of antiquated stuff be restored?
/* check that gpencil data is allowed to be drawn */
if ((v3d->flag2 & V3D_DISPGP)==0) {
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 054e46971b5..d486a8f2fef 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -45,7 +45,6 @@ struct EditVert;
struct EditEdge;
struct EditFace;
struct bContext;
-struct wmOperator;
struct wmWindowManager;
struct wmKeyConfig;
struct ReportList;
@@ -63,130 +62,177 @@ struct MCol;
struct UvVertMap;
struct UvMapVert;
struct CustomData;
+struct BMEditMesh;
+struct BMEditSelection;
+struct BMesh;
+struct BMVert;
+struct MLoopCol;
+struct BMEdge;
+struct BMFace;
+struct UvVertMap;
+struct UvMapVert;
struct Material;
struct Object;
struct rcti;
+struct wmOperator;
-#define EM_FGON_DRAW 1 // face flag
-#define EM_FGON 2 // edge and face flag both
+// edge and face flag both
+#define EM_FGON 2
+// face flag
+#define EM_FGON_DRAW 1
/* editbutflag */
-#define B_CLOCKWISE 1
-#define B_KEEPORIG 2
-#define B_BEAUTY 4
-#define B_SMOOTH 8
-#define B_BEAUTY_SHORT 0x10
-#define B_AUTOFGON 0x20
-#define B_KNIFE 0x80
+#define B_CLOCKWISE 1
+#define B_KEEPORIG 2
+#define B_BEAUTY 4
+#define B_SMOOTH 8
+#define B_BEAUTY_SHORT 16
+#define B_AUTOFGON 32
+#define B_KNIFE 0x80
#define B_PERCENTSUBD 0x40
//#define B_MESH_X_MIRROR 0x100 // deprecated, use mesh
#define B_JOINTRIA_UV 0x200
#define B_JOINTRIA_VCOL 0X400
#define B_JOINTRIA_SHARP 0X800
#define B_JOINTRIA_MAT 0X1000
-#define B_FRACTAL 0x2000
-#define B_SPHERE 0x4000
-
-/* meshtools.c */
+#define B_FRACTAL 0x2000
+#define B_SPHERE 0x4000
-intptr_t mesh_octree_table(struct Object *ob, struct EditMesh *em, float *co, char mode);
-long mesh_mirrtopo_table(struct Object *ob, char mode);
+float *bm_get_cd_float(struct CustomData *cdata, void *data, int type);
-struct EditVert *editmesh_get_x_mirror_vert(struct Object *ob, struct EditMesh *em, struct EditVert *eve, float *co, int index);
-int mesh_get_x_mirror_vert(struct Object *ob, int index);
-int *mesh_get_x_mirror_faces(struct Object *ob, struct EditMesh *em);
+/* bmeshutils.c */
-int join_mesh_exec(struct bContext *C, struct wmOperator *op);
-int join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op);
-
-/* mesh_ops.c */
-void ED_operatortypes_mesh(void);
-void ED_operatormacros_mesh(void);
-void ED_keymap_mesh(struct wmKeyConfig *keyconf);
+/*
+ [note: I've decided to use ideasman's code for non-editmode stuff, but since
+ it has a big "not for editmode!" disclaimer, I'm going to keep what I have here
+ - joeedh]
+
+ x-mirror editing api. usage:
+
+ EDBM_CacheMirrorVerts(em);
+ ...
+ ...
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ mirrorv = EDBM_GetMirrorVert(em, v);
+ }
+ ...
+ ...
+ EDBM_EndMirrorCache(em);
+
+ note: why do we only allow x axis mirror editing?
+ */
+void EDBM_CacheMirrorVerts(struct BMEditMesh *em);
+
+/*retrieves mirrored cache vert, or NULL if there isn't one.
+ note: calling this without ensuring the mirror cache state
+ is bad.*/
+struct BMVert *EDBM_GetMirrorVert(struct BMEditMesh *em, struct BMVert *v);
+void EDBM_EndMirrorCache(struct BMEditMesh *em);
+
+void EDBM_RecalcNormals(struct BMEditMesh *em);
+
+void EDBM_MakeEditBMesh(struct ToolSettings *ts, struct Scene *scene, struct Object *ob);
+void EDBM_FreeEditBMesh(struct BMEditMesh *tm);
+void EDBM_LoadEditBMesh(struct Scene *scene, struct Object *ob);
+
+void EDBM_init_index_arrays(struct BMEditMesh *em, int forvert, int foredge, int forface);
+void EDBM_free_index_arrays(struct BMEditMesh *em);
+struct BMVert *EDBM_get_vert_for_index(struct BMEditMesh *em, int index);
+struct BMEdge *EDBM_get_edge_for_index(struct BMEditMesh *em, int index);
+struct BMFace *EDBM_get_face_for_index(struct BMEditMesh *em, int index);
+struct BMFace *EDBM_get_actFace(struct BMEditMesh *em, int sloppy);
+
+int EDBM_CallAndSelectOpf(struct BMEditMesh *em, struct wmOperator *op,
+ const char *selectslot, const char *fmt, ...);
+
+/*flushes based on the current select mode. if in vertex select mode,
+ verts select/deselect edges and faces, if in edge select mode,
+ edges select/deselect faces and vertices, and in face select mode faces select/deselect
+ edges and vertices.*/
+void EDBM_selectmode_flush(struct BMEditMesh *em);
+
+int EDBM_get_actSelection(struct BMEditMesh *em, struct BMEditSelection *ese);
+
+/*exactly the same as EDBM_selectmode_flush, but you pass in the selectmode
+ instead of using the current one*/
+void EDBM_select_flush(struct BMEditMesh *em, int selectmode);
+void EDBM_deselect_flush(struct BMEditMesh *em);
+
+void EDBM_selectmode_set(struct BMEditMesh *em);
+void EDBM_convertsel(struct BMEditMesh *em, short oldmode, short selectmode);
+void undo_push_mesh(struct bContext *C, const char *name);
+void EDBM_editselection_center(struct BMEditMesh *em, float *center, struct BMEditSelection *ese);
+void EDBM_editselection_plane(struct BMEditMesh *em, float *plane, struct BMEditSelection *ese);
+void EDBM_editselection_normal(float *normal, struct BMEditSelection *ese);
+int EDBM_vertColorCheck(struct BMEditMesh *em);
+void EDBM_validate_selections(struct BMEditMesh *em);
-/* editmesh.c */
-void make_editMesh(struct Scene *scene, struct Object *ob);
-void load_editMesh(struct Scene *scene, struct Object *ob);
-void remake_editMesh(struct Scene *scene, struct Object *ob);
-void free_editMesh(struct EditMesh *em);
+void EDBM_pin_mesh(struct BMEditMesh *em, int swap);
+void EDBM_unpin_mesh(struct BMEditMesh *em, int swap);
-void recalc_editnormals(struct EditMesh *em);
+void EDBM_hide_mesh(struct BMEditMesh *em, int swap);
+void EDBM_reveal_mesh(struct BMEditMesh *em);
-void EM_init_index_arrays(struct EditMesh *em, int forVert, int forEdge, int forFace);
-void EM_free_index_arrays(void);
-struct EditVert *EM_get_vert_for_index(int index);
-struct EditEdge *EM_get_edge_for_index(int index);
-struct EditFace *EM_get_face_for_index(int index);
-int EM_texFaceCheck(struct EditMesh *em);
-int EM_vertColorCheck(struct EditMesh *em);
+int EDBM_check_backbuf(unsigned int index);
+int EDBM_mask_init_backbuf_border(struct ViewContext *vc, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax);
+void EDBM_free_backbuf(void);
+int EDBM_init_backbuf_border(struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax);
+int EDBM_init_backbuf_circle(struct ViewContext *vc, short xs, short ys, short rads);
-void undo_push_mesh(struct bContext *C, const char *name);
+void EDBM_select_swap(struct BMEditMesh *em); /* exported for UV */
+void EDBM_set_actFace(struct BMEditMesh *em, struct BMFace *efa);
+int EDBM_texFaceCheck(struct BMEditMesh *em);
+struct MTexPoly *EDBM_get_active_mtexpoly(struct BMEditMesh *em, struct BMFace **act_efa, int sloppy);
-/* editmesh_lib.c */
+void EDBM_free_uv_vert_map(struct UvVertMap *vmap);
+struct UvMapVert *EDBM_get_uv_map_vert(struct UvVertMap *vmap, unsigned int v);
+struct UvVertMap *EDBM_make_uv_vert_map(struct BMEditMesh *em, int selected, int do_face_idx_array, float *limit);
+void EM_add_data_layer(struct BMEditMesh *em, struct CustomData *data, int type, const char *name);
+void EM_free_data_layer(struct BMEditMesh *em, struct CustomData *data, int type);
-struct EditFace *EM_get_actFace(struct EditMesh *em, int sloppy);
-void EM_set_actFace(struct EditMesh *em, struct EditFace *efa);
-float EM_face_area(struct EditFace *efa);
+void EDBM_toggle_select_all(struct BMEditMesh *em);
+void EDBM_set_flag_all(struct BMEditMesh *em, int flag);
+void EDBM_clear_flag_all(struct BMEditMesh *em, int flag);
+void EDBM_automerge(struct Scene *scene, struct Object *ob, int update);
-void EM_select_edge(struct EditEdge *eed, int sel);
-void EM_select_face(struct EditFace *efa, int sel);
-void EM_select_face_fgon(struct EditMesh *em, struct EditFace *efa, int val);
-void EM_select_swap(struct EditMesh *em);
-void EM_toggle_select_all(struct EditMesh *em);
-void EM_select_all(struct EditMesh *em);
-void EM_deselect_all(struct EditMesh *em);
-void EM_selectmode_flush(struct EditMesh *em);
-void EM_deselect_flush(struct EditMesh *em);
-void EM_selectmode_set(struct EditMesh *em);
-void EM_select_flush(struct EditMesh *em);
-void EM_convertsel(struct EditMesh *em, short oldmode, short selectmode);
-void EM_validate_selections(struct EditMesh *em);
-void EM_selectmode_to_scene(struct Scene *scene, struct Object *obedit);
+/* meshtools.c */
- /* exported to transform */
-int EM_get_actSelection(struct EditMesh *em, struct EditSelection *ese);
-void EM_editselection_normal(float *normal, struct EditSelection *ese);
-void EM_editselection_plane(float *plane, struct EditSelection *ese);
-void EM_editselection_center(float *center, struct EditSelection *ese);
+void EM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct Object *obedit, struct BMEditMesh *em);
-struct UvVertMap *EM_make_uv_vert_map(struct EditMesh *em, int selected, int do_face_idx_array, float *limit);
-struct UvMapVert *EM_get_uv_map_vert(struct UvVertMap *vmap, unsigned int v);
-void EM_free_uv_vert_map(struct UvVertMap *vmap);
+/* editmesh_mods.c */
+extern unsigned int bm_vertoffs, bm_solidoffs, bm_wireoffs;
-void EM_add_data_layer(struct EditMesh *em, struct CustomData *data, int type, const char *name);
-void EM_free_data_layer(struct EditMesh *em, struct CustomData *data, int type);
+intptr_t mesh_octree_table(struct Object *ob, struct BMEditMesh *em, float *co, char mode);
+long mesh_mirrtopo_table(struct Object *ob, char mode);
-void EM_make_hq_normals(struct EditMesh *em);
-void EM_solidify(struct EditMesh *em, float dist);
+struct BMVert *editbmesh_get_x_mirror_vert(struct Object *ob, struct BMEditMesh *em, struct BMVert *eve, float *co, int index);
+int mesh_get_x_mirror_vert(struct Object *ob, int index);
+int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em);
-int EM_deselect_nth(struct EditMesh *em, int nth);
+int join_mesh_exec(struct bContext *C, struct wmOperator *op);
+int join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op);
-void EM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct Object *obedit, struct EditMesh *em);
+/* mesh_ops.c */
+void ED_operatortypes_mesh(void);
+void ED_operatormacros_mesh(void);
+void ED_keymap_mesh(struct wmKeyConfig *keyconf);
-/* editmesh_mods.c */
-extern unsigned int em_vertoffs, em_solidoffs, em_wireoffs;
-void EM_cache_x_mirror_vert(struct Object *ob, struct EditMesh *em);
-int mouse_mesh(struct bContext *C, short mval[2], short extend);
-int EM_check_backbuf(unsigned int index);
-int EM_mask_init_backbuf_border(struct ViewContext *vc, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax);
-void EM_free_backbuf(void);
-int EM_init_backbuf_border(struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax);
-int EM_init_backbuf_circle(struct ViewContext *vc, short xs, short ys, short rads);
+/* editmesh.c */
-void EM_hide_mesh(struct EditMesh *em, int swap);
-void EM_reveal_mesh(struct EditMesh *em);
+void ED_spacetypes_init(void);
+void ED_keymap_mesh(struct wmKeyConfig *keyconf);
-void EM_select_by_material(struct EditMesh *em, int index);
-void EM_deselect_by_material(struct EditMesh *em, int index);
+/* bmesh_mods.c */
+extern unsigned int bm_vertoffs, bm_solidoffs, bm_wireoffs;
-void EM_automerge(struct Scene *scene, struct Object *obedit, int update);
+int mouse_mesh(struct bContext *C, short mval[2], short extend);
/* editface.c */
void paintface_flush_flags(struct Object *ob);
-struct MTFace *EM_get_active_mtface(struct EditMesh *em, struct EditFace **act_efa, struct MCol **mcol, int sloppy);
+struct MTexPoly *EM_get_active_mtexpoly(struct BMEditMesh *em, struct BMFace **act_efa, struct MLoopCol **col, int sloppy);
int paintface_mouse_select(struct bContext *C, struct Object *ob, short mval[2], int extend);
int do_paintface_box_select(struct ViewContext *vc, struct rcti *rect, int select, int extend);
void paintface_deselect_all_visible(struct Object *ob, int action, short flush_flags);
@@ -217,13 +263,19 @@ void ED_vgroup_vert_add(struct Object *ob, struct bDeformGroup *dg, int vertnum
void ED_vgroup_vert_remove(struct Object *ob, struct bDeformGroup *dg, int vertnum);
float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vertnum);
-/*needed by edge slide*/
-struct EditVert *editedge_getOtherVert(struct EditEdge *eed, struct EditVert *eve);
-struct EditVert *editedge_getSharedVert(struct EditEdge *eed, struct EditEdge *eed2);
-int editedge_containsVert(struct EditEdge *eed, struct EditVert *eve);
-int editface_containsVert(struct EditFace *efa, struct EditVert *eve);
-int editface_containsEdge(struct EditFace *efa, struct EditEdge *eed);
-short sharesFace(struct EditMesh *em, struct EditEdge *e1, struct EditEdge *e2);
+/**
+ * findnearestvert
+ *
+ * dist (in/out): minimal distance to the nearest and at the end, actual distance
+ * sel: selection bias
+ * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
+ * if 0, unselected vertice are given the bias
+ * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
+ */
+
+struct BMVert *EDBM_findnearestvert(struct ViewContext *vc, int *dist, short sel, short strict);
+struct BMEdge *EDBM_findnearestedge(struct ViewContext *vc, int *dist);
+struct BMFace *EDBM_findnearestface(struct ViewContext *vc, int *dist);
/* mesh_data.c */
// void ED_mesh_geometry_add(struct Mesh *mesh, struct ReportList *reports, int verts, int edges, int faces);
@@ -241,9 +293,12 @@ int ED_mesh_uv_texture_remove(struct bContext *C, struct Object *ob, struct Mesh
int ED_mesh_color_add(struct bContext *C, struct Scene *scene, struct Object *ob, struct Mesh *me, const char *name, int active_set);
int ED_mesh_color_remove(struct bContext *C, struct Object *ob, struct Mesh *me);
+void EDBM_selectmode_to_scene(struct Scene *scene, struct Object *obedit);
+
+#include "../mesh/editbmesh_bvh.h"
+
#ifdef __cplusplus
}
#endif
#endif /* ED_MESH_H */
-
diff --git a/source/blender/editors/include/ED_toolmode.h b/source/blender/editors/include/ED_toolmode.h
new file mode 100755
index 00000000000..733ca6c74fc
--- /dev/null
+++ b/source/blender/editors/include/ED_toolmode.h
@@ -0,0 +1,80 @@
+#if 0
+/**
+ * $Id:
+ *
+ * ***** 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): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef ED_TOOLMODE_H
+#define ED_TOOLMODE_H
+
+struct ID;
+struct View3D;
+struct ARegion;
+struct bContext;
+struct wmWindowManager;
+struct wmKeyConfig;
+struct ReportList;
+struct ViewContext;
+struct bDeformGroup;
+struct MDeformWeight;
+struct MDeformVert;
+struct Scene;
+struct Mesh;
+struct MCol;
+struct UvVertMap;
+struct UvMapVert;
+struct CustomData;
+struct BMEditMesh;
+struct BMEditSelection;
+struct BMesh;
+struct BMVert;
+struct BMEdge;
+struct BMFace;
+struct UvVertMap;
+struct UvMapVert;
+struct Material;
+struct Object;
+struct rcti;
+struct wmOperator;
+
+typedef struct ToolModeDefine {
+ short idtype, icon;
+ char *name;
+ void (*create)(void *args);
+ void (*free)(void *self);
+
+ /*called when mode is set active*/
+ void (*enter)(void *self, struct bContext *C);
+ void (*exit)(void *self, struct bContext *C);
+
+ /*called on draw*/
+ void (*draw)(void *self, struct bContext *C);
+ /*modal is option, and should be used carefully*/
+ void (*modal)(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
+
+ /*keymap stuff*/
+ void (*create_keymap)(struct wmKeyConfig *km);
+ void (*keymap_poll)(struct bContext *C);
+};
+#endif
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 77b754519fb..06c9c12444e 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -71,8 +71,8 @@ int ED_undo_valid (const struct bContext *C, const char *undoname);
void undo_editmode_push(struct bContext *C, const char *name,
void * (*getdata)(struct bContext *C),
void (*freedata)(void *),
- void (*to_editmode)(void *, void *),
- void *(*from_editmode)(void *),
+ void (*to_editmode)(void *, void *, void *),
+ void *(*from_editmode)(void *, void *),
int (*validate_undo)(void *, void *));
@@ -84,9 +84,8 @@ void undo_editmode_step (struct bContext *C, int step);
/* crazyspace.c */
float *crazyspace_get_mapped_editverts(struct Scene *scene, struct Object *obedit);
-void crazyspace_set_quats_editmesh(struct EditMesh *em, float *origcos, float *mappedcos, float *quats);
+void crazyspace_set_quats_editmesh(struct BMEditMesh *em, float *origcos, float *mappedcos, float *quats);
void crazyspace_set_quats_mesh(struct Mesh *me, float *origcos, float *mappedcos, float *quats);
-int editmesh_get_first_deform_matrices(struct Scene *scene, struct Object *ob, struct EditMesh *em, float (**deformmats)[3][3], float (**deformcos)[3]);
int sculpt_get_first_deform_matrices(struct Scene *scene, struct Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]);
void crazyspace_build_sculpt(struct Scene *scene, struct Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]);
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index a0c4148c055..5d45415c3b3 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -51,18 +51,17 @@ int ED_uvedit_test_silent(struct Object *obedit);
int ED_uvedit_test(struct Object *obedit);
/* visibility and selection */
-int uvedit_edge_selected(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
-int uvedit_face_selected(struct Scene *scene, struct EditFace *efa, struct MTFace *tf);
-int uvedit_face_visible_nolocal(struct Scene *scene, struct EditFace *efa);
-int uvedit_face_visible(struct Scene *scene, struct Image *ima, struct EditFace *efa, struct MTFace *tf);
-int uvedit_uv_selected(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
-void uvedit_edge_deselect(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
-void uvedit_edge_select(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
-void uvedit_face_deselect(struct Scene *scene, struct EditFace *efa, struct MTFace *tf);
-void uvedit_face_select(struct Scene *scene, struct EditFace *efa, struct MTFace *tf);
-void uvedit_uv_deselect(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
-void uvedit_uv_select(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
+int uvedit_face_visible(struct Scene *scene, struct Image *ima, struct BMFace *efa, struct MTexPoly *tf);
+int uvedit_face_selected(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa);
+int uvedit_edge_selected(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l);
+int uvedit_uv_selected(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l);
+int uvedit_face_select(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa);
+int uvedit_face_deselect(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa);
+void uvedit_edge_select(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l);
+void uvedit_edge_deselect(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l);
+void uvedit_uv_select(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l);
+void uvedit_uv_deselect(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l);
int ED_uvedit_nearest_uv(struct Scene *scene, struct Object *obedit, struct Image *ima, float co[2], float uv[2]);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 53a518d1fe6..37541722682 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -40,8 +40,11 @@ struct BezTriple;
struct bglMats;
struct BoundBox;
struct BPoint;
-struct EditEdge;
-struct EditFace;
+struct Nurb;
+struct BezTriple;
+struct BMVert;
+struct BMEdge;
+struct BMFace;
struct EditVert;
struct ImBuf;
struct Main;
@@ -63,7 +66,7 @@ typedef struct ViewContext {
struct ARegion *ar;
struct View3D *v3d;
struct RegionView3D *rv3d;
- struct EditMesh *em;
+ struct BMEditMesh *em;
short mval[2];
} ViewContext;
@@ -112,13 +115,15 @@ int get_view3d_cliprange(struct View3D *v3d, struct RegionView3D *rv3d, float *c
int get_view3d_viewplane(struct View3D *v3d, struct RegionView3D *rv3d, int winxi, int winyi, struct rctf *viewplane, float *clipsta, float *clipend, float *pixsize);
int get_view3d_ortho(struct View3D *v3d, struct RegionView3D *rv3d);
void view3d_get_object_project_mat(struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]);
+/* computes screen x/y in vec */
void view3d_project_float(struct ARegion *a, float *vec, float *adr, float mat[4][4]);
+void view3d_project_float_v3(struct ARegion *a, float *vec, float *adr, float mat[4][4]);
void view3d_calc_camera_border(struct Scene *scene, struct ARegion *ar, struct RegionView3D *rv3d, struct View3D *v3d, struct rctf *viewborder_r, short do_shift);
/* drawobject.c iterators */
-void mesh_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct EditVert *eve, int x, int y, int index), void *userData, int clipVerts);
-void mesh_foreachScreenEdge(struct ViewContext *vc, void (*func)(void *userData, struct EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts);
-void mesh_foreachScreenFace(struct ViewContext *vc, void (*func)(void *userData, struct EditFace *efa, int x, int y, int index), void *userData);
+void mesh_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct BMVert *eve, int x, int y, int index), void *userData, int clipVerts);
+void mesh_foreachScreenEdge(struct ViewContext *vc, void (*func)(void *userData, struct BMEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts);
+void mesh_foreachScreenFace(struct ViewContext *vc, void (*func)(void *userData, struct BMFace *efa, int x, int y, int index), void *userData);
void nurbs_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct Nurb *nu, struct BPoint *bp, struct BezTriple *bezt, int beztindex, int x, int y), void *userData);
void lattice_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct BPoint *bp, int x, int y), void *userData);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 55d7d0c219d..553ac3b0222 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -153,6 +153,7 @@ typedef struct uiLayout uiLayout;
#define UI_BUT_IMMEDIATE (1<<27)
#define UI_BUT_NO_TOOLTIP (1<<28)
#define UI_BUT_NO_UTF8 (1<<29)
+#define UI_BUT_NO_UTF8 (1<<28)
#define UI_BUT_VEC_SIZE_LOCK (1<<30) /* used to flag if color hsv-circle should keep luminance */
#define UI_BUT_COLOR_CUBIC (1<<31) /* cubic saturation for the color wheel */
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 2fb2e882afb..9c3a378608b 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -232,6 +232,9 @@ enum {
TH_DOPESHEET_CHANNELOB,
TH_DOPESHEET_CHANNELSUBOB,
+
+ TH_PIN,
+ TH_PIN_OPAC,
TH_PREVIEW_BACK,
diff --git a/source/blender/editors/interface/SConscript b/source/blender/editors/interface/SConscript
index 5998d4d2953..e3b730e85c1 100644
--- a/source/blender/editors/interface/SConscript
+++ b/source/blender/editors/interface/SConscript
@@ -7,8 +7,13 @@ for source in env.Glob('*_api.c'):
sources.remove(source)
incs = '../include ../../blenlib ../../blenfont ../../blenkernel ../../makesdna ../../imbuf'
+<<<<<<< .working
+incs += ' ../../makesrna ../../windowmanager ../../gpu ../../bmesh'
+incs += ' #/intern/guardedalloc #/extern/glew/include'
+=======
incs += ' ../../makesrna ../../windowmanager #/intern/guardedalloc ../../gpu'
incs += ' #/extern/glew/include ../../blenloader'
+>>>>>>> .merge-right.r35190
incs += ' ../../python/' # python button eval
defs = []
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index e8d2771e257..a556d8322b2 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -4366,9 +4366,9 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
/* RMB has two options now */
if (ui_but_menu(C, but)) {
return WM_UI_HANDLER_BREAK;
- }
}
}
+ }
/* verify if we can edit this button */
if(ELEM(event->type, LEFTMOUSE, RETKEY)) {
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 2fe50bba7ab..890ce14f53b 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -399,6 +399,11 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
case TH_DOPESHEET_CHANNELSUBOB:
cp= ts->ds_subchannel;
break;
+
+ case TH_PIN:
+ cp= ts->pin; break;
+ case TH_PIN_OPAC:
+ cp= &ts->pin_opac; break;
case TH_PREVIEW_BACK:
cp= ts->preview_back;
@@ -546,6 +551,9 @@ void ui_theme_init_default(void)
SETCOL(btheme->tv3d.bone_solid, 200, 200, 200, 255);
SETCOL(btheme->tv3d.bone_pose, 80, 200, 255, 80); // alpha 80 is not meant editable, used for wire+action draw
+
+ SETCOL(btheme->tv3d.pin, 115, 171, 209, 255);
+ btheme->tv3d.pin_opac = 40;
/* space buttons */
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 8ff323d88b6..2295cca29a9 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -21,9 +21,11 @@
set(INC
../include
+ ../uvedit
../../blenkernel
../../blenloader
../../blenlib
+ ../../bmesh
../../imbuf
../../makesdna
../../makesrna
@@ -33,19 +35,20 @@ set(INC
)
set(SRC
- editface.c
- editmesh.c
- editmesh_add.c
- editmesh_lib.c
- editmesh_loop.c
- editmesh_mods.c
- editmesh_tools.c
+ meshtools.c
loopcut.c
- mesh_data.c
mesh_ops.c
- meshtools.c
-
+ editbmesh_bvh.c
+ editbmesh_bvh.h
+ editbmesh_add.c
+ bmeshutils.c
mesh_intern.h
+ bmesh_selecthistory.c
+ bmesh_select.c
+ mesh_data.c
+ bmesh_tools.c
+ knifetool.c
+ editface.c
)
blender_add_lib(bf_editor_mesh "${SRC}" "${INC}")
diff --git a/source/blender/editors/mesh/SConscript b/source/blender/editors/mesh/SConscript
index 34936c025bc..388fdbc15b7 100644
--- a/source/blender/editors/mesh/SConscript
+++ b/source/blender/editors/mesh/SConscript
@@ -7,6 +7,7 @@ incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../gpu ../../blenloader'
incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern'
+incs += ' ../../bmesh '
if env['OURPLATFORM'] == 'linux2':
cflags='-pthread'
diff --git a/source/blender/editors/mesh/bmesh_select.c b/source/blender/editors/mesh/bmesh_select.c
new file mode 100644
index 00000000000..00b30dc3f5a
--- /dev/null
+++ b/source/blender/editors/mesh/bmesh_select.c
@@ -0,0 +1,2170 @@
+/**
+ * $Id:
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/*
+
+BMEditMesh_mods.c, UI level access, no geometry changes
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_array.h"
+
+#include "BKE_context.h"
+#include "BKE_displist.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+#include "BKE_paint.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "RE_render_ext.h" /* externtex */
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_mesh.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "bmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "UI_resources.h"
+
+#include "mesh_intern.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+/* ****************************** MIRROR **************** */
+
+void EDBM_select_mirrored(Object *obedit, BMEditMesh *em)
+{
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ BMVert *eve, *v1;
+ BMIter iter;
+ int i;
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_SELECT) && !BM_TestHFlag(eve, BM_HIDDEN)) {
+ v1= editbmesh_get_x_mirror_vert(obedit, em, eve, eve->co, i);
+ if(v1) {
+ BM_Select(em->bm, eve, 0);
+ BM_Select(em->bm, v1, 1);
+ }
+ }
+ i++;
+ }
+ }
+}
+
+void EDBM_automerge(Scene *scene, Object *obedit, int update)
+{
+ BMEditMesh *em;
+ int len;
+
+ if ((scene->toolsettings->automerge) &&
+ (obedit && obedit->type==OB_MESH) &&
+ (((Mesh*)obedit->data)->mr==NULL))
+ {
+ em = ((Mesh*)obedit->data)->edit_btmesh;
+ if (!em)
+ return;
+
+ BMO_CallOpf(em->bm, "automerge verts=%hv dist=%f", BM_SELECT, scene->toolsettings->doublimit);
+ if (update) {
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ }
+ }
+}
+
+/* ****************************** SELECTION ROUTINES **************** */
+
+unsigned int bm_solidoffs=0, bm_wireoffs=0, bm_vertoffs=0; /* set in drawobject.c ... for colorindices */
+
+/* facilities for border select and circle select */
+static char *selbuf= NULL;
+
+/* opengl doesn't support concave... */
+static void draw_triangulated(short mcords[][2], short tot)
+{
+ ListBase lb={NULL, NULL};
+ DispList *dl;
+ float *fp;
+ int a;
+
+ /* make displist */
+ dl= MEM_callocN(sizeof(DispList), "poly disp");
+ dl->type= DL_POLY;
+ dl->parts= 1;
+ dl->nr= tot;
+ dl->verts= fp= MEM_callocN(tot*3*sizeof(float), "poly verts");
+ BLI_addtail(&lb, dl);
+
+ for(a=0; a<tot; a++, fp+=3) {
+ fp[0]= (float)mcords[a][0];
+ fp[1]= (float)mcords[a][1];
+ }
+
+ /* do the fill */
+ filldisplist(&lb, &lb, 0);
+
+ /* do the draw */
+ dl= lb.first; /* filldisplist adds in head of list */
+ if(dl->type==DL_INDEX3) {
+ int *index;
+
+ a= dl->parts;
+ fp= dl->verts;
+ index= dl->index;
+ glBegin(GL_TRIANGLES);
+ while(a--) {
+ glVertex3fv(fp+3*index[0]);
+ glVertex3fv(fp+3*index[1]);
+ glVertex3fv(fp+3*index[2]);
+ index+= 3;
+ }
+ glEnd();
+ }
+
+ freedisplist(&lb);
+}
+
+
+/* reads rect, and builds selection array for quick lookup */
+/* returns if all is OK */
+int EDBM_init_backbuf_border(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
+{
+ struct ImBuf *buf;
+ unsigned int *dr;
+ int a;
+
+ if(vc->obedit==NULL || vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
+
+ buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ if(buf==NULL) return 0;
+ if(bm_vertoffs==0) return 0;
+
+ dr = buf->rect;
+
+ /* build selection lookup */
+ selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
+
+ a= (xmax-xmin+1)*(ymax-ymin+1);
+ while(a--) {
+ if(*dr>0 && *dr<=bm_vertoffs)
+ selbuf[*dr]= 1;
+ dr++;
+ }
+ IMB_freeImBuf(buf);
+ return 1;
+}
+
+int EDBM_check_backbuf(unsigned int index)
+{
+ if(selbuf==NULL) return 1;
+ if(index>0 && index<=bm_vertoffs)
+ return selbuf[index];
+ return 0;
+}
+
+void EDBM_free_backbuf(void)
+{
+ if(selbuf) MEM_freeN(selbuf);
+ selbuf= NULL;
+}
+
+/* mcords is a polygon mask
+ - grab backbuffer,
+ - draw with black in backbuffer,
+ - grab again and compare
+ returns 'OK'
+*/
+int EDBM_mask_init_backbuf_border(ViewContext *vc, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
+{
+ unsigned int *dr, *drm;
+ struct ImBuf *buf, *bufmask;
+ int a;
+
+ /* method in use for face selecting too */
+ if(vc->obedit==NULL) {
+ if(paint_facesel_test(vc->obact));
+ else return 0;
+ }
+ else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
+
+ buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ if(buf==NULL) return 0;
+ if(bm_vertoffs==0) return 0;
+
+ dr = buf->rect;
+
+ /* draw the mask */
+ glDisable(GL_DEPTH_TEST);
+
+ glColor3ub(0, 0, 0);
+
+ /* yah, opengl doesn't do concave... tsk! */
+ ED_region_pixelspace(vc->ar);
+ draw_triangulated(mcords, tot);
+
+ glBegin(GL_LINE_LOOP); /* for zero sized masks, lines */
+ for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]);
+ glEnd();
+
+ glFinish(); /* to be sure readpixels sees mask */
+
+ /* grab mask */
+ bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ drm = bufmask->rect;
+ if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
+
+ /* build selection lookup */
+ selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
+
+ a= (xmax-xmin+1)*(ymax-ymin+1);
+ while(a--) {
+ if(*dr>0 && *dr<=bm_vertoffs && *drm==0) selbuf[*dr]= 1;
+ dr++; drm++;
+ }
+ IMB_freeImBuf(buf);
+ IMB_freeImBuf(bufmask);
+ return 1;
+
+}
+
+/* circle shaped sample area */
+int EDBM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
+{
+ struct ImBuf *buf;
+ unsigned int *dr;
+ short xmin, ymin, xmax, ymax, xc, yc;
+ int radsq;
+
+ /* method in use for face selecting too */
+ if(vc->obedit==NULL) {
+ if(paint_facesel_test(vc->obact));
+ else return 0;
+ }
+ else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
+
+ xmin= xs-rads; xmax= xs+rads;
+ ymin= ys-rads; ymax= ys+rads;
+ buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ if(bm_vertoffs==0) return 0;
+ if(buf==NULL) return 0;
+
+ dr = buf->rect;
+
+ /* build selection lookup */
+ selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
+ radsq= rads*rads;
+ for(yc= -rads; yc<=rads; yc++) {
+ for(xc= -rads; xc<=rads; xc++, dr++) {
+ if(xc*xc + yc*yc < radsq) {
+ if(*dr>0 && *dr<=bm_vertoffs) selbuf[*dr]= 1;
+ }
+ }
+ }
+
+ IMB_freeImBuf(buf);
+ return 1;
+
+}
+
+static void findnearestvert__doClosest(void *userData, BMVert *eve, int x, int y, int index)
+{
+ struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } *data = userData;
+
+ if (data->pass==0) {
+ if (index<=data->lastIndex)
+ return;
+ } else {
+ if (index>data->lastIndex)
+ return;
+ }
+
+ if (data->dist>3) {
+ int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
+ if (BM_TestHFlag(eve, BM_SELECT) == data->select) {
+ if (data->strict == 1)
+ return;
+ else
+ temp += 5;
+ }
+
+ if (temp<data->dist) {
+ data->dist = temp;
+ data->closest = eve;
+ data->closestIndex = index;
+ }
+ }
+}
+
+
+
+
+static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index)
+{
+ BMEditMesh *em= (BMEditMesh *)handle;
+ BMVert *eve = BMIter_AtIndex(em->bm, BM_VERTS_OF_MESH, NULL, index-1);
+
+ if(eve && BM_TestHFlag(eve, BM_SELECT)) return 0;
+ return 1;
+}
+/**
+ * findnearestvert
+ *
+ * dist (in/out): minimal distance to the nearest and at the end, actual distance
+ * sel: selection bias
+ * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
+ * if 0, unselected vertice are given the bias
+ * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
+ */
+BMVert *EDBM_findnearestvert(ViewContext *vc, int *dist, short sel, short strict)
+{
+ if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){
+ int distance;
+ unsigned int index;
+ BMVert *eve;
+
+ if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest);
+ else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL);
+
+ eve = BMIter_AtIndex(vc->em->bm, BM_VERTS_OF_MESH, NULL, index-1);
+
+ if(eve && distance < *dist) {
+ *dist = distance;
+ return eve;
+ } else {
+ return NULL;
+ }
+
+ }
+ else {
+ struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } data;
+ static int lastSelectedIndex=0;
+ static BMVert *lastSelected=NULL;
+
+ if (lastSelected && BMIter_AtIndex(vc->em->bm, BM_VERTS_OF_MESH, NULL, lastSelectedIndex)!=lastSelected) {
+ lastSelectedIndex = 0;
+ lastSelected = NULL;
+ }
+
+ data.lastIndex = lastSelectedIndex;
+ data.mval[0] = vc->mval[0];
+ data.mval[1] = vc->mval[1];
+ data.select = sel;
+ data.dist = *dist;
+ data.strict = strict;
+ data.closest = NULL;
+ data.closestIndex = 0;
+
+ data.pass = 0;
+
+ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+
+ mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
+
+ if (data.dist>3) {
+ data.pass = 1;
+ mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
+ }
+
+ *dist = data.dist;
+ lastSelected = data.closest;
+ lastSelectedIndex = data.closestIndex;
+
+ return data.closest;
+ }
+}
+
+/* returns labda for closest distance v1 to line-piece v2-v3 */
+float labda_PdistVL2Dfl( float *v1, float *v2, float *v3)
+{
+ float rc[2], len;
+
+ rc[0]= v3[0]-v2[0];
+ rc[1]= v3[1]-v2[1];
+ len= rc[0]*rc[0]+ rc[1]*rc[1];
+ if(len==0.0f)
+ return 0.0f;
+
+ return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
+}
+
+/* note; uses v3d, so needs active 3d window */
+static void findnearestedge__doClosest(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index)
+{
+ struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } *data = userData;
+ float v1[2], v2[2];
+ int distance;
+
+ v1[0] = x0;
+ v1[1] = y0;
+ v2[0] = x1;
+ v2[1] = y1;
+
+ distance= dist_to_line_segment_v2(data->mval, v1, v2);
+
+ if(BM_TestHFlag(eed, BM_SELECT)) distance+=5;
+ if(distance < data->dist) {
+ if(data->vc.rv3d->rflag & RV3D_CLIPPING) {
+ float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
+ float vec[3];
+
+ vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
+ vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
+ vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
+ mul_m4_v3(data->vc.obedit->obmat, vec);
+
+ if(view3d_test_clipping(data->vc.rv3d, vec, 1)==0) {
+ data->dist = distance;
+ data->closest = eed;
+ }
+ }
+ else {
+ data->dist = distance;
+ data->closest = eed;
+ }
+ }
+}
+BMEdge *EDBM_findnearestedge(ViewContext *vc, int *dist)
+{
+
+ if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
+ int distance;
+ unsigned int index;
+ BMEdge *eed;
+
+ view3d_validate_backbuf(vc);
+
+ index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_solidoffs, bm_wireoffs, &distance,0, NULL, NULL);
+ eed = BMIter_AtIndex(vc->em->bm, BM_EDGES_OF_MESH, NULL, index-1);
+
+ if (eed && distance<*dist) {
+ *dist = distance;
+ return eed;
+ } else {
+ return NULL;
+ }
+ }
+ else {
+ struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } data;
+
+ data.vc= *vc;
+ data.mval[0] = vc->mval[0];
+ data.mval[1] = vc->mval[1];
+ data.dist = *dist;
+ data.closest = NULL;
+ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+
+ mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2);
+
+ *dist = data.dist;
+ return data.closest;
+ }
+}
+
+static void findnearestface__getDistance(void *userData, BMFace *efa, int x, int y, int index)
+{
+ struct { short mval[2]; int dist; BMFace *toFace; } *data = userData;
+
+ if (efa==data->toFace) {
+ int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
+
+ if (temp<data->dist)
+ data->dist = temp;
+ }
+}
+static void findnearestface__doClosest(void *userData, BMFace *efa, int x, int y, int index)
+{
+ struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } *data = userData;
+
+ if (data->pass==0) {
+ if (index<=data->lastIndex)
+ return;
+ } else {
+ if (index>data->lastIndex)
+ return;
+ }
+
+ if (data->dist>3) {
+ int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
+
+ if (temp<data->dist) {
+ data->dist = temp;
+ data->closest = efa;
+ data->closestIndex = index;
+ }
+ }
+}
+
+BMFace *EDBM_findnearestface(ViewContext *vc, int *dist)
+{
+
+ if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
+ unsigned int index;
+ BMFace *efa;
+
+ view3d_validate_backbuf(vc);
+
+ index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
+ efa = BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, index-1);
+
+ if (efa) {
+ struct { short mval[2]; int dist; BMFace *toFace; } data;
+
+ data.mval[0] = vc->mval[0];
+ data.mval[1] = vc->mval[1];
+ data.dist = 0x7FFF; /* largest short */
+ data.toFace = efa;
+
+ mesh_foreachScreenFace(vc, findnearestface__getDistance, &data);
+
+ if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) { /* only faces, no dist check */
+ *dist= data.dist;
+ return efa;
+ }
+ }
+
+ return NULL;
+ }
+ else {
+ struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } data;
+ static int lastSelectedIndex=0;
+ static BMFace *lastSelected=NULL;
+
+ if (lastSelected && BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, lastSelectedIndex)!=lastSelected) {
+ lastSelectedIndex = 0;
+ lastSelected = NULL;
+ }
+
+ data.lastIndex = lastSelectedIndex;
+ data.mval[0] = vc->mval[0];
+ data.mval[1] = vc->mval[1];
+ data.dist = *dist;
+ data.closest = NULL;
+ data.closestIndex = 0;
+ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+
+ data.pass = 0;
+ mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
+
+ if (data.dist>3) {
+ data.pass = 1;
+ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+ mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
+ }
+
+ *dist = data.dist;
+ lastSelected = data.closest;
+ lastSelectedIndex = data.closestIndex;
+
+ return data.closest;
+ }
+}
+
+/* best distance based on screen coords.
+ use em->selectmode to define how to use
+ selected vertices and edges get disadvantage
+ return 1 if found one
+*/
+static int unified_findnearest(ViewContext *vc, BMVert **eve, BMEdge **eed, BMFace **efa)
+{
+ BMEditMesh *em= vc->em;
+ int dist= 75;
+
+ *eve= NULL;
+ *eed= NULL;
+ *efa= NULL;
+
+ /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
+ view3d_validate_backbuf(vc);
+
+ if(em->selectmode & SCE_SELECT_VERTEX)
+ *eve= EDBM_findnearestvert(vc, &dist, BM_SELECT, 0);
+ if(em->selectmode & SCE_SELECT_FACE)
+ *efa= EDBM_findnearestface(vc, &dist);
+
+ dist-= 20; /* since edges select lines, we give dots advantage of 20 pix */
+ if(em->selectmode & SCE_SELECT_EDGE)
+ *eed= EDBM_findnearestedge(vc, &dist);
+
+ /* return only one of 3 pointers, for frontbuffer redraws */
+ if(*eed) {
+ *efa= NULL; *eve= NULL;
+ }
+ else if(*efa) {
+ *eve= NULL;
+ }
+
+ return (*eve || *eed || *efa);
+}
+
+/* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
+
+static EnumPropertyItem prop_similar_types[] = {
+ {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
+ {SIMVERT_FACE, "FACE", 0, "Amount of Adjacent Faces", ""},
+ {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
+
+ {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
+ {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
+ {SIMEDGE_FACE, "FACE", 0, "Amount of Faces Around an Edge", ""},
+ {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
+ {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
+ {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
+ {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
+
+ {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
+ {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
+ {SIMFACE_AREA, "AREA", 0, "Area", ""},
+ {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
+ {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
+ {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
+
+ {0, NULL, 0, NULL, NULL}
+};
+
+/* selects new faces/edges/verts based on the existing selection */
+
+static int similar_face_select_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+
+ /* get the type from RNA */
+ int type = RNA_enum_get(op->ptr, "type");
+
+ float thresh = CTX_data_tool_settings(C)->select_thresh;
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "similarfaces faces=%hf type=%d thresh=%f", BM_SELECT, type, thresh);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* clear the existing selection */
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ /* select the output */
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT, BM_ALL);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+ /* dependencies graph and notification stuff */
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
+
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+}
+
+/* ***************************************************** */
+
+/* EDGE GROUP */
+
+/* wrap the above function but do selection flushing edge to face */
+static int similar_edge_select_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+
+ /* get the type from RNA */
+ int type = RNA_enum_get(op->ptr, "type");
+
+ float thresh = CTX_data_tool_settings(C)->select_thresh;
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "similaredges edges=%he type=%d thresh=%f", BM_SELECT, type, thresh);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* clear the existing selection */
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ /* select the output */
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "edgeout", BM_SELECT, BM_ALL);
+ EDBM_selectmode_flush(em);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+ /* dependencies graph and notification stuff */
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
+
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+}
+
+/* ********************************* */
+
+/*
+VERT GROUP
+ mode 1: same normal
+ mode 2: same number of face users
+ mode 3: same vertex groups
+*/
+
+
+static int similar_vert_select_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+ /* get the type from RNA */
+ int type = RNA_enum_get(op->ptr, "type");
+ float thresh = CTX_data_tool_settings(C)->select_thresh;
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "similarverts verts=%hv type=%d thresh=%f", BM_SELECT, type, thresh);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* clear the existing selection */
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ /* select the output */
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_ALL);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+ EDBM_selectmode_flush(em);
+
+ /* dependencies graph and notification stuff */
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
+
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+}
+
+static int select_similar_exec(bContext *C, wmOperator *op)
+{
+ int type= RNA_enum_get(op->ptr, "type");
+
+ if(type < 100)
+ return similar_vert_select_exec(C, op);
+ else if(type < 200)
+ return similar_edge_select_exec(C, op);
+ else
+ return similar_face_select_exec(C, op);
+}
+
+static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *ptr, int *free)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ EnumPropertyItem *item= NULL;
+ int a, totitem= 0;
+
+ if(obedit && obedit->type == OB_MESH) {
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ for (a=SIMVERT_NORMAL; a<SIMEDGE_LENGTH; a++) {
+ RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
+ }
+ } else if(em->selectmode & SCE_SELECT_EDGE) {
+ for (a=SIMEDGE_LENGTH; a<SIMFACE_MATERIAL; a++) {
+ RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
+ }
+ } else if(em->selectmode & SCE_SELECT_FACE) {
+ for (a=SIMFACE_MATERIAL; a<=SIMFACE_COPLANAR; a++) {
+ RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
+ }
+ }
+ RNA_enum_item_end(&item, &totitem);
+
+ *free= 1;
+
+ return item;
+ }
+
+ return NULL;
+}
+
+void MESH_OT_select_similar(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name= "Select Similar";
+ ot->idname= "MESH_OT_select_similar";
+
+ /* api callbacks */
+ ot->invoke= WM_menu_invoke;
+ ot->exec= select_similar_exec;
+ ot->poll= ED_operator_editmesh;
+ ot->description= "Select similar vertices, edges or faces by property types.";
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ prop= RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
+ RNA_def_enum_funcs(prop, select_similar_type_itemf);
+}
+
+/* ***************************************************** */
+
+/* **************** LOOP SELECTS *************** */
+/*faceloop_select, edgeloop_select, and edgering_select, are left
+ here for reference purposes temporarily, but have all been replaced
+ by uses of walker_select.*/
+
+static void walker_select(BMEditMesh *em, int walkercode, void *start, int select)
+{
+ BMesh *bm = em->bm;
+ BMHeader *h;
+ BMWalker walker;
+
+ BMW_Init(&walker, bm, walkercode, 0, 0);
+ h = BMW_Begin(&walker, start);
+ for (; h; h=BMW_Step(&walker)) {
+ BM_Select(bm, h, select);
+ }
+ BMW_End(&walker);
+}
+
+static int loop_multiselect(bContext *C, wmOperator *op)
+{
+#if 0 //BMESH_TODO
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= EM_GetBMEditMesh(((Mesh *)obedit->data));
+ BMEdge *eed;
+ BMEdge **edarray;
+ int edindex, edfirstcount;
+ int looptype= RNA_boolean_get(op->ptr, "ring");
+
+ /* sets em->totedgesel */
+ EM_nedges_selected(em);
+
+ edarray = MEM_mallocN(sizeof(BMEdge*)*em->totedgesel,"edge array");
+ edindex = 0;
+ edfirstcount = em->totedgesel;
+
+ for(eed=em->edges.first; eed; eed=eed->next){
+ if(eed->f&SELECT){
+ edarray[edindex] = eed;
+ edindex += 1;
+ }
+ }
+
+ if(looptype){
+ for(edindex = 0; edindex < edfirstcount; edindex +=1){
+ eed = edarray[edindex];
+ edgering_select(em, eed,SELECT);
+ }
+ EM_selectmode_flush(em);
+ }
+ else{
+ for(edindex = 0; edindex < edfirstcount; edindex +=1){
+ eed = edarray[edindex];
+ edgeloop_select(em, eed,SELECT);
+ }
+ EM_selectmode_flush(em);
+ }
+ MEM_freeN(edarray);
+// if (EM_texFaceCheck())
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ EM_EndBMEditMesh(obedit->data, em);
+#endif
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_loop_multi_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Multi Select Loops";
+ ot->idname= "MESH_OT_loop_multi_select";
+
+ /* api callbacks */
+ ot->exec= loop_multiselect;
+ ot->poll= ED_operator_editmesh;
+ ot->description= "Select a loop of connected edges by connection type.";
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
+}
+
+
+/* ***************** MAIN MOUSE SELECTION ************** */
+
+
+/* ***************** loop select (non modal) ************** */
+
+static void mouse_mesh_loop(bContext *C, short mval[2], short extend, short ring)
+{
+ ViewContext vc;
+ BMEditMesh *em;
+ BMEdge *eed;
+ int select= 1;
+ int dist= 50;
+
+ em_setup_viewcontext(C, &vc);
+ vc.mval[0]= mval[0];
+ vc.mval[1]= mval[1];
+ em= vc.em;
+
+ /* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */
+ view3d_validate_backbuf(&vc);
+
+ eed= EDBM_findnearestedge(&vc, &dist);
+ if(eed) {
+ if(extend==0) EDBM_clear_flag_all(em, BM_SELECT);
+
+ if(BM_TestHFlag(em, BM_SELECT)==0) select=1;
+ else if(extend) select=0;
+
+ if(em->selectmode & SCE_SELECT_FACE) {
+ walker_select(em, BMW_FACELOOP, eed, select);
+ }
+ else if(em->selectmode & SCE_SELECT_EDGE) {
+ if(ring)
+ walker_select(em, BMW_EDGERING, eed, select);
+ else
+ walker_select(em, BMW_LOOP, eed, select);
+ }
+ else if(em->selectmode & SCE_SELECT_VERTEX) {
+ if(ring)
+ walker_select(em, BMW_EDGERING, eed, select);
+ else
+ walker_select(em, BMW_LOOP, eed, select);
+ }
+
+ EDBM_selectmode_flush(em);
+// if (EM_texFaceCheck())
+
+ /* sets as active, useful for other tools */
+ if(select && em->selectmode & SCE_SELECT_EDGE) {
+ EDBM_store_selection(em, eed);
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit);
+ }
+}
+
+static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+
+ view3d_operator_needs_opengl(C);
+
+ mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
+ RNA_boolean_get(op->ptr, "ring"));
+
+ /* cannot do tweaks for as long this keymap is after transform map */
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_loop_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Loop Select";
+ ot->idname= "MESH_OT_loop_select";
+
+ /* api callbacks */
+ ot->invoke= mesh_select_loop_invoke;
+ ot->poll= ED_operator_editmesh;
+ ot->description= "Select a loop of connected edges.";
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
+ RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "");
+}
+
+/* ******************* mesh shortest path select, uses prev-selected edge ****************** */
+
+/* since you want to create paths with multiple selects, it doesn't have extend option */
+static void mouse_mesh_shortest_path(bContext *C, short mval[2])
+{
+#if 0 //BMESH_TODO
+ ViewContext vc;
+ BMEditMesh *em;
+ BMEdge *eed;
+ int dist= 50;
+
+ em_setup_viewcontext(C, &vc);
+ vc.mval[0]= mval[0];
+ vc.mval[1]= mval[1];
+ em= vc.em;
+
+ eed= findnearestedge(&vc, &dist);
+ if(eed) {
+ Mesh *me= vc.obedit->data;
+ int path = 0;
+
+ if (em->bm->selected.last) {
+ EditSelection *ese = em->bm->selected.last;
+
+ if(ese && ese->type == BMEdge) {
+ BMEdge *eed_act;
+ eed_act = (BMEdge*)ese->data;
+ if (eed_act != eed) {
+ if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) {
+ EM_remove_selection(em, eed_act, BMEdge);
+ path = 1;
+ }
+ }
+ }
+ }
+ if (path==0) {
+ int act = (edgetag_context_check(vc.scene, eed)==0);
+ edgetag_context_set(em, vc.scene, eed, act); /* switch the edge option */
+ }
+
+ EM_selectmode_flush(em);
+
+ /* even if this is selected it may not be in the selection list */
+ if(edgetag_context_check(vc.scene, eed)==0)
+ EDBM_remove_selection(em, eed);
+ else
+ EDBM_store_selection(em, eed);
+
+ /* force drawmode for mesh */
+ switch (CTX_data_tool_settings(C)->edge_mode) {
+
+ case EDGE_MODE_TAG_SEAM:
+ me->drawflag |= ME_DRAWSEAMS;
+ break;
+ case EDGE_MODE_TAG_SHARP:
+ me->drawflag |= ME_DRAWSHARP;
+ break;
+ case EDGE_MODE_TAG_CREASE:
+ me->drawflag |= ME_DRAWCREASES;
+ break;
+ case EDGE_MODE_TAG_BEVEL:
+ me->drawflag |= ME_DRAWBWEIGHTS;
+ break;
+ }
+
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
+ }
+#endif
+}
+
+
+static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+
+ view3d_operator_needs_opengl(C);
+
+ mouse_mesh_shortest_path(C, event->mval);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_shortest_path(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Shortest Path Select";
+ ot->idname= "MESH_OT_select_shortest_path";
+
+ /* api callbacks */
+ ot->invoke= mesh_shortest_path_select_invoke;
+ ot->poll= ED_operator_editmesh;
+ ot->description= "Select shortest path between two selections.";
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
+}
+
+/* ************************************************** */
+/* here actual select happens */
+/* gets called via generic mouse select operator */
+int mouse_mesh(bContext *C, short mval[2], short extend)
+{
+ ViewContext vc;
+ BMVert *eve = NULL;
+ BMEdge *eed = NULL;
+ BMFace *efa = NULL;
+
+ /* setup view context for argument to callbacks */
+ em_setup_viewcontext(C, &vc);
+ vc.mval[0]= mval[0];
+ vc.mval[1]= mval[1];
+
+ if(unified_findnearest(&vc, &eve, &eed, &efa)) {
+
+ if(extend==0) EDBM_clear_flag_all(vc.em, BM_SELECT);
+
+ if(efa) {
+ /* set the last selected face */
+ EDBM_set_actFace(vc.em, efa);
+
+ if(!BM_TestHFlag(efa, BM_SELECT)) {
+ EDBM_store_selection(vc.em, efa);
+ BM_Select(vc.em->bm, efa, 1);
+ }
+ else if(extend) {
+ EDBM_remove_selection(vc.em, efa);
+ BM_Select(vc.em->bm, efa, 0);
+ }
+ }
+ else if(eed) {
+ if(!BM_TestHFlag(eed, BM_SELECT)) {
+ EDBM_store_selection(vc.em, eed);
+ BM_Select(vc.em->bm, eed, 1);
+ }
+ else if(extend) {
+ EDBM_remove_selection(vc.em, eed);
+ BM_Select(vc.em->bm, eed, 0);
+ }
+ }
+ else if(eve) {
+ if(!BM_TestHFlag(eve, BM_SELECT)) {
+ EDBM_store_selection(vc.em, eve);
+ BM_Select(vc.em->bm, eve, 1);
+ }
+ else if(extend){
+ EDBM_remove_selection(vc.em, eve);
+ BM_Select(vc.em->bm, eve, 0);
+ }
+ }
+
+ EDBM_selectmode_flush(vc.em);
+
+// if (EM_texFaceCheck()) {
+
+ if (efa && efa->mat_nr != vc.obedit->actcol-1) {
+ vc.obedit->actcol= efa->mat_nr+1;
+ vc.em->mat_nr= efa->mat_nr;
+// BIF_preview_changed(ID_MA);
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void EDBM_strip_selections(BMEditMesh *em)
+{
+ BMEditSelection *ese, *nextese;
+
+ if(!(em->selectmode & SCE_SELECT_VERTEX)){
+ ese = em->bm->selected.first;
+ while(ese){
+ nextese = ese->next;
+ if(ese->type == BM_VERT) BLI_freelinkN(&(em->bm->selected),ese);
+ ese = nextese;
+ }
+ }
+ if(!(em->selectmode & SCE_SELECT_EDGE)){
+ ese=em->bm->selected.first;
+ while(ese){
+ nextese = ese->next;
+ if(ese->type == BM_EDGE) BLI_freelinkN(&(em->bm->selected), ese);
+ ese = nextese;
+ }
+ }
+ if(!(em->selectmode & SCE_SELECT_FACE)){
+ ese=em->bm->selected.first;
+ while(ese){
+ nextese = ese->next;
+ if(ese->type == BM_FACE) BLI_freelinkN(&(em->bm->selected), ese);
+ ese = nextese;
+ }
+ }
+}
+
+/* when switching select mode, makes sure selection is consistant for editing */
+/* also for paranoia checks to make sure edge or face mode works */
+void EDBM_selectmode_set(BMEditMesh *em)
+{
+ BMVert *eve;
+ BMEdge *eed;
+ BMFace *efa;
+ BMIter iter;
+
+ em->bm->selectmode = em->selectmode;
+
+ EDBM_strip_selections(em); /*strip BMEditSelections from em->selected that are not relevant to new mode*/
+
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ /*BMIter iter;
+
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, 0);
+
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter)) BM_Select(em->bm, efa, 0);*/
+
+ EDBM_selectmode_flush(em);
+ }
+ else if(em->selectmode & SCE_SELECT_EDGE) {
+ /* deselect vertices, and select again based on edge select */
+ eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for ( ; eve; eve=BMIter_Step(&iter)) BM_Select(em->bm, eve, 0);
+
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(eed, BM_SELECT))
+ BM_Select(em->bm, eed, 1);
+ }
+
+ /* selects faces based on edge status */
+ EDBM_selectmode_flush(em);
+ }
+ else if(em->selectmode & SCE_SELECT_FACE) {
+ /* deselect eges, and select again based on face select */
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, 0);
+
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(efa, BM_SELECT))
+ BM_Select(em->bm, efa, 1);
+ }
+ }
+}
+
+void EDBM_convertsel(BMEditMesh *em, short oldmode, short selectmode)
+{
+ BMVert *eve;
+ BMEdge *eed;
+ BMFace *efa;
+ BMIter iter;
+
+ /*have to find out what the selectionmode was previously*/
+ if(oldmode == SCE_SELECT_VERTEX) {
+ if(selectmode == SCE_SELECT_EDGE) {
+ /*select all edges associated with every selected vertex*/
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter)) {
+ if(BM_TestHFlag(eed->v1, BM_SELECT)) BM_Select(em->bm, eed, 1);
+ else if(BM_TestHFlag(eed->v2, BM_SELECT)) BM_Select(em->bm, eed, 1);
+ }
+ }
+ else if(selectmode == SCE_SELECT_FACE) {
+ BMIter liter;
+ BMLoop *l;
+
+ /*select all faces associated with every selected vertex*/
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter)) {
+ l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BMIter_Step(&liter)) {
+ if (BM_TestHFlag(l->v, BM_SELECT)) {
+ BM_Select(em->bm, efa, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if(oldmode == SCE_SELECT_EDGE){
+ if(selectmode == SCE_SELECT_FACE) {
+ BMIter liter;
+ BMLoop *l;
+
+ /*select all faces associated with every selected vertex*/
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter)) {
+ l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BMIter_Step(&liter)) {
+ if (BM_TestHFlag(l->v, BM_SELECT)) {
+ BM_Select(em->bm, efa, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void EDBM_select_swap(BMEditMesh *em) /* exported for UV */
+{
+ BMIter iter;
+ BMVert *eve;
+ BMEdge *eed;
+ BMFace *efa;
+
+ if(em->bm->selectmode & SCE_SELECT_VERTEX) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_HIDDEN))
+ continue;
+ BM_Select(em->bm, eve, !BM_TestHFlag(eve, BM_SELECT));
+ }
+ }
+ else if(em->selectmode & SCE_SELECT_EDGE) {
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(eed, BM_HIDDEN))
+ continue;
+ BM_Select(em->bm, eed, !BM_TestHFlag(eed, BM_SELECT));
+ }
+ }
+ else {
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_TestHFlag(efa, BM_HIDDEN))
+ continue;
+ BM_Select(em->bm, efa, !BM_TestHFlag(efa, BM_SELECT));
+ }
+
+ }
+// if (EM_texFaceCheck())
+}
+
+static int select_inverse_mesh_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ EDBM_select_swap(em);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_inverse(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Inverse";
+ ot->idname= "MESH_OT_select_inverse";
+ ot->description= "Select inverse of (un)selected vertices, edges or faces.";
+
+ /* api callbacks */
+ ot->exec= select_inverse_mesh_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+
+static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ ViewContext vc;
+ BMWalker walker;
+ BMEditMesh *em;
+ BMVert *eve;
+ BMEdge *e, *eed;
+ BMFace *efa;
+ short done=1, toggle=0;
+ int sel= !RNA_boolean_get(op->ptr, "deselect");
+ int limit= RNA_boolean_get(op->ptr, "limit");
+
+ /* unified_finednearest needs ogl */
+ view3d_operator_needs_opengl(C);
+
+ /* setup view context for argument to callbacks */
+ em_setup_viewcontext(C, &vc);
+ em = vc.em;
+
+ if(vc.em->bm->totedge==0)
+ return OPERATOR_CANCELLED;
+
+ vc.mval[0]= event->mval[0];
+ vc.mval[1]= event->mval[1];
+
+ /* return warning! */
+
+ /*if(limit) {
+ int retval= select_linked_limited_invoke(&vc, 0, sel);
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+ return retval;
+ }*/
+
+ if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_CANCELLED;
+ }
+
+ if (efa) {
+ eed = bm_firstfaceloop(efa)->e;
+ } else if (!eed) {
+ if (!eve || !eve->e)
+ return OPERATOR_CANCELLED;
+
+ eed = eve->e;
+ }
+
+ BMW_Init(&walker, em->bm, BMW_SHELL, 0, 0);
+ e = BMW_Begin(&walker, eed->v1);
+ for (; e; e=BMW_Step(&walker)) {
+ BM_Select(em->bm, e->v1, sel);
+ BM_Select(em->bm, e->v2, sel);
+ }
+ BMW_End(&walker);
+ EDBM_select_flush(em, SCE_SELECT_VERTEX);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_linked_pick(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Linked";
+ ot->idname= "MESH_OT_select_linked_pick";
+
+ /* api callbacks */
+ ot->invoke= select_linked_pick_invoke;
+ ot->poll= ED_operator_editmesh;
+ ot->description= "select/deselect all vertices linked to the edge under the mouse cursor.";
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
+ RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
+}
+
+
+static int select_linked_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BLI_array_declare(verts);
+ BMVert **verts = NULL;
+ BMIter iter;
+ BMVert *v;
+ BMEdge *e;
+ BMWalker walker;
+ int i, tot;
+
+ tot = 0;
+ BM_ITER_SELECT(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL)
+ if (BM_TestHFlag(v, BM_SELECT)) {
+ BLI_array_growone(verts);
+ verts[tot++] = v;
+ }
+ }
+
+ BMW_Init(&walker, em->bm, BMW_SHELL, 0, 0);
+ for (i=0; i<tot; i++) {
+ e = BMW_Begin(&walker, verts[i]);
+ for (; e; e=BMW_Step(&walker)) {
+ BM_Select(em->bm, e->v1, 1);
+ BM_Select(em->bm, e->v2, 1);
+ }
+ }
+ BMW_End(&walker);
+ EDBM_select_flush(em, SCE_SELECT_VERTEX);
+
+ BLI_array_free(verts);
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Linked All";
+ ot->idname= "MESH_OT_select_linked";
+
+ /* api callbacks */
+ ot->exec= select_linked_exec;
+ ot->poll= ED_operator_editmesh;
+ ot->description= "Select all vertices linked to the active mesh.";
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
+}
+
+/* ******************** **************** */
+
+static int select_more(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+ BMOperator bmop;
+ int usefaces = em->selectmode > SCE_SELECT_EDGE;
+
+ EDBM_InitOpf(em, &bmop, op, "regionextend geom=%hvef constrict=%d usefaces=%d",
+ BM_SELECT, 0, usefaces);
+
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
+
+ EDBM_selectmode_flush(em);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_more(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select More";
+ ot->idname= "MESH_OT_select_more";
+ ot->description= "Select more vertices, edges or faces connected to initial selection.";
+
+ /* api callbacks */
+ ot->exec= select_more;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int select_less(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+ BMOperator bmop;
+ int usefaces = em->selectmode > SCE_SELECT_EDGE;
+
+ EDBM_InitOpf(em, &bmop, op, "regionextend geom=%hvef constrict=%d usefaces=%d",
+ BM_SELECT, 1, usefaces);
+
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
+
+ EDBM_selectmode_flush(em);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_less(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Less";
+ ot->idname= "MESH_OT_select_less";
+ ot->description= "Deselect vertices, edges or faces at the boundary of each selection region.";
+
+ /* api callbacks */
+ ot->exec= select_less;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int mesh_select_nth_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ int nth = RNA_int_get(op->ptr, "nth");
+
+#if 0 //BMESH_TODO
+ if(EM_deselect_nth(em, nth) == 0) {
+ BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face.");
+ return OPERATOR_CANCELLED;
+ }
+#else
+ BKE_report(op->reports, RPT_ERROR, "Unimplemented");
+#endif
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+
+void MESH_OT_select_nth(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Nth";
+ ot->description= "";
+ ot->idname= "MESH_OT_select_nth";
+
+ /* api callbacks */
+ ot->exec= mesh_select_nth_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "nth", 2, 2, 100, "Nth Selection", "", 1, INT_MAX);
+}
+
+#if 0 //BMESH_TODO, select nth tool
+/* not that optimal!, should be nicer with bmesh */
+static void tag_face_edges(EditFace *efa)
+{
+ if(efa->v4)
+ efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;
+ else
+ efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
+}
+static int tag_face_edges_test(EditFace *efa)
+{
+ if(efa->v4)
+ return (efa->e1->tmp.l || efa->e2->tmp.l || efa->e3->tmp.l || efa->e4->tmp.l) ? 1:0;
+ else
+ return (efa->e1->tmp.l || efa->e2->tmp.l || efa->e3->tmp.l) ? 1:0;
+}
+
+void em_deselect_nth_face(EditMesh *em, int nth, EditFace *efa_act)
+{
+ EditFace *efa;
+ EditEdge *eed;
+ int ok= 1;
+
+ if(efa_act==NULL) {
+ return;
+ }
+
+ /* to detect loose edges, we put f2 flag on 1 */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->tmp.l= 0;
+ }
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ efa->tmp.l = 0;
+ }
+
+ efa_act->tmp.l = 1;
+
+ while(ok) {
+ ok = 0;
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->tmp.l==1) { /* initialize */
+ tag_face_edges(efa);
+ }
+
+ if(efa->tmp.l)
+ efa->tmp.l++;
+ }
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->tmp.l==0 && tag_face_edges_test(efa)) {
+ efa->tmp.l= 1;
+ ok = 1; /* keep looping */
+ }
+ }
+ }
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->tmp.l > 0 && efa->tmp.l % nth) {
+ EM_select_face(efa, 0);
+ }
+ }
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ EM_select_face(efa, 1);
+ }
+ }
+
+ EM_nvertices_selected(em);
+ EM_nedges_selected(em);
+ EM_nfaces_selected(em);
+}
+
+/* not that optimal!, should be nicer with bmesh */
+static void tag_edge_verts(EditEdge *eed)
+{
+ eed->v1->tmp.l= eed->v2->tmp.l= 1;
+}
+static int tag_edge_verts_test(EditEdge *eed)
+{
+ return (eed->v1->tmp.l || eed->v2->tmp.l) ? 1:0;
+}
+
+void em_deselect_nth_edge(EditMesh *em, int nth, EditEdge *eed_act)
+{
+ EditEdge *eed;
+ EditVert *eve;
+ int ok= 1;
+
+ if(eed_act==NULL) {
+ return;
+ }
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ eve->tmp.l= 0;
+ }
+
+ for (eed= em->edges.first; eed; eed= eed->next) {
+ eed->tmp.l = 0;
+ }
+
+ eed_act->tmp.l = 1;
+
+ while(ok) {
+ ok = 0;
+
+ for (eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->tmp.l==1) { /* initialize */
+ tag_edge_verts(eed);
+ }
+
+ if(eed->tmp.l)
+ eed->tmp.l++;
+ }
+
+ for (eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->tmp.l==0 && tag_edge_verts_test(eed)) {
+ eed->tmp.l= 1;
+ ok = 1; /* keep looping */
+ }
+ }
+ }
+
+ for (eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->tmp.l > 0 && eed->tmp.l % nth) {
+ EM_select_edge(eed, 0);
+ }
+ }
+ for (eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f & SELECT) {
+ EM_select_edge(eed, 1);
+ }
+ }
+
+ {
+ /* grr, should be a function */
+ EditFace *efa;
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->v4) {
+ if(efa->e1->f & efa->e2->f & efa->e3->f & efa->e4->f & SELECT );
+ else efa->f &= ~SELECT;
+ }
+ else {
+ if(efa->e1->f & efa->e2->f & efa->e3->f & SELECT );
+ else efa->f &= ~SELECT;
+ }
+ }
+ }
+
+ EM_nvertices_selected(em);
+ EM_nedges_selected(em);
+ EM_nfaces_selected(em);
+}
+
+void em_deselect_nth_vert(EditMesh *em, int nth, EditVert *eve_act)
+{
+ EditVert *eve;
+ EditEdge *eed;
+ int ok= 1;
+
+ if(eve_act==NULL) {
+ return;
+ }
+
+ for (eve= em->verts.first; eve; eve= eve->next) {
+ eve->tmp.l = 0;
+ }
+
+ eve_act->tmp.l = 1;
+
+ while(ok) {
+ ok = 0;
+
+ for (eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->tmp.l)
+ eve->tmp.l++;
+ }
+
+ for (eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->v1->tmp.l==2 && eed->v2->tmp.l==0) { /* initialize */
+ eed->v2->tmp.l= 1;
+ ok = 1; /* keep looping */
+ }
+ else if(eed->v2->tmp.l==2 && eed->v1->tmp.l==0) { /* initialize */
+ eed->v1->tmp.l= 1;
+ ok = 1; /* keep looping */
+ }
+ }
+ }
+
+ for (eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->tmp.l > 0 && eve->tmp.l % nth) {
+ eve->f &= ~SELECT;
+ }
+ }
+
+ EM_deselect_flush(em);
+
+ EM_nvertices_selected(em);
+ // EM_nedges_selected(em); // flush does these
+ // EM_nfaces_selected(em); // flush does these
+}
+#endif
+
+int EM_deselect_nth(EditMesh *em, int nth)
+{
+#if 0
+ EditSelection *ese;
+ ese = ((EditSelection*)em->selected.last);
+ if(ese) {
+ if(ese->type == EDITVERT) {
+ em_deselect_nth_vert(em, nth, (EditVert*)ese->data);
+ return 1;
+ }
+
+ if(ese->type == EDITEDGE) {
+ em_deselect_nth_edge(em, nth, (EditEdge*)ese->data);
+ return 1;
+ }
+ }
+ else {
+ EditFace *efa_act = EM_get_actFace(em, 0);
+ if(efa_act) {
+ em_deselect_nth_face(em, nth, efa_act);
+ return 1;
+ }
+ }
+
+ return 0;
+#endif
+ return 1;
+}
+
+void em_setup_viewcontext(bContext *C, ViewContext *vc)
+{
+ view3d_set_viewcontext(C, vc);
+
+ if(vc->obedit) {
+ Mesh *me= vc->obedit->data;
+ vc->em= me->edit_btmesh;
+ }
+}
+
+/* poll call for mesh operators requiring a view3d context */
+int EM_view3d_poll(bContext *C)
+{
+ if(ED_operator_editmesh(C) && ED_operator_view3d_active(C))
+ return 1;
+ return 0;
+}
+
+
+static int select_sharp_edges_exec(bContext *C, wmOperator *op)
+{
+ /* Find edges that have exactly two neighboring faces,
+ * check the angle between those faces, and if angle is
+ * small enough, select the edge
+ */
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMIter iter;
+ BMEdge *e;
+ BLI_array_declare(stack);
+ BMLoop *l1, *l2;
+ float sharp = RNA_float_get(op->ptr, "sharpness"), angle;
+
+ sharp = (sharp * M_PI) / 180.0;
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(e, BM_HIDDEN) || !e->l)
+ continue;
+
+ l1 = e->l;
+ l2 = l1->radial_next;
+
+ if (l1 == l2)
+ continue;
+
+ /* edge has exactly two neighboring faces, check angle */
+ angle = saacos(l1->f->no[0]*l2->f->no[0]+l1->f->no[1]*l2->f->no[1]+l1->f->no[2]*l2->f->no[2]);
+
+ if (fabs(angle) < sharp) {
+ BM_Select(em->bm, e, 1);
+ }
+
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_edges_select_sharp(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Sharp Edges";
+ ot->description= "Marked selected edges as sharp.";
+ ot->idname= "MESH_OT_edges_select_sharp";
+
+ /* api callbacks */
+ ot->exec= select_sharp_edges_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_float(ot->srna, "sharpness", 1.0f, 0.01f, FLT_MAX, "sharpness", "", 1.0f, 180.0f);
+}
+
+static int select_linked_flat_faces_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMIter iter, liter, liter2;
+ BMFace *f, **stack = NULL;
+ BLI_array_declare(stack);
+ BMLoop *l, *l2;
+ float sharp = RNA_float_get(op->ptr, "sharpness");
+ int i;
+
+ sharp = (sharp * M_PI) / 180.0;
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BMINDEX_SET(f, 0);
+ }
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_TestHFlag(f, BM_HIDDEN) || !BM_TestHFlag(f, BM_SELECT) || BMINDEX_GET(f))
+ continue;
+
+ BLI_array_empty(stack);
+ i = 1;
+
+ BLI_array_growone(stack);
+ stack[i-1] = f;
+
+ while (i) {
+ f = stack[i-1];
+ i--;
+
+ BM_Select(em->bm, f, 1);
+
+ BMINDEX_SET(f, 1);
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
+ BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_LOOP, l) {
+ float angle;
+
+ if (BMINDEX_GET(l2->f) || BM_TestHFlag(l2->f, BM_HIDDEN))
+ continue;
+
+ /* edge has exactly two neighboring faces, check angle */
+ angle = saacos(f->no[0]*l2->f->no[0]+f->no[1]*l2->f->no[1]+f->no[2]*l2->f->no[2]);
+
+ /* invalidate: edge too sharp */
+ if (fabs(angle) < sharp) {
+ BLI_array_growone(stack);
+ stack[i] = l2->f;
+ i++;
+ }
+ }
+ }
+ }
+ }
+
+ BLI_array_free(stack);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_faces_select_linked_flat(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Linked Flat Faces";
+ ot->description= "Select linked faces by angle.";
+ ot->idname= "MESH_OT_faces_select_linked_flat";
+
+ /* api callbacks */
+ ot->exec= select_linked_flat_faces_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_float(ot->srna, "sharpness", 1.0f, 0.01f, FLT_MAX, "sharpness", "", 1.0f, 180.0f);
+}
+
+static int select_non_manifold_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMVert *v;
+ BMEdge *e;
+ BMIter iter;
+
+ /* Selects isolated verts, and edges that do not have 2 neighboring
+ * faces
+ */
+
+ if(em->selectmode==SCE_SELECT_FACE) {
+ BKE_report(op->reports, RPT_ERROR, "Doesn't work in face selection mode");
+ return OPERATOR_CANCELLED;
+ }
+
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_TestHFlag(em->bm, BM_HIDDEN) && BM_Nonmanifold_Vert(em->bm, v))
+ BM_Select(em->bm, v, 1);
+ }
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(em->bm, BM_HIDDEN) && BM_Nonmanifold_Edge(em->bm, e))
+ BM_Select(em->bm, e, 1);
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_non_manifold(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Non Manifold";
+ ot->description= "Select all non-manifold vertices or edges.";
+ ot->idname= "MESH_OT_select_non_manifold";
+
+ /* api callbacks */
+ ot->exec= select_non_manifold_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int mesh_select_random_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMVert *eve;
+ BMEdge *eed;
+ BMFace *efa;
+ BMIter iter;
+ float randfac = RNA_float_get(op->ptr, "percent")/100.0f;
+
+ BLI_srand( BLI_rand() ); /* random seed */
+
+ if(!RNA_boolean_get(op->ptr, "extend"))
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_TestHFlag(eve, BM_HIDDEN) && BLI_frand() < randfac)
+ BM_Select(em->bm, eve, 1);
+ }
+ EDBM_selectmode_flush(em);
+ }
+ else if(em->selectmode & SCE_SELECT_EDGE) {
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(eed, BM_HIDDEN) && BLI_frand() < randfac)
+ BM_Select(em->bm, eed, 1);
+ }
+ EDBM_selectmode_flush(em);
+ }
+ else {
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(efa, BM_HIDDEN) && BLI_frand() < randfac)
+ BM_Select(em->bm, efa, 1);
+ }
+ EDBM_selectmode_flush(em);
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_random(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Random";
+ ot->description= "Randomly select vertices.";
+ ot->idname= "MESH_OT_select_random";
+
+ /* api callbacks */
+ ot->exec= mesh_select_random_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* 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", 0, "Extend Selection", "Extend selection instead of deselecting everything first.");
+}
diff --git a/source/blender/editors/mesh/bmesh_selecthistory.c b/source/blender/editors/mesh/bmesh_selecthistory.c
new file mode 100644
index 00000000000..3b7fade9c05
--- /dev/null
+++ b/source/blender/editors/mesh/bmesh_selecthistory.c
@@ -0,0 +1,126 @@
+/**
+ * $Id:
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* ********* Selection History ************ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_array.h"
+
+#include "BKE_context.h"
+#include "BKE_displist.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "RE_render_ext.h" /* externtex */
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_mesh.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "bmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "mesh_intern.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+/*these wrap equivilent bmesh functions. I'm in two minds of it we should
+ just use the bm functions directly; on the one hand, there's no real
+ need (at the moment) to wrap them, but on the other hand having these
+ wrapped avoids a confusing mess of mixing BM_ and EDBM_ namespaces.*/
+
+void EDBM_editselection_center(BMEditMesh *em, float *center, BMEditSelection *ese)
+{
+ BM_editselection_center(em->bm, center, ese);
+}
+
+void EDBM_editselection_normal(float *normal, BMEditSelection *ese)
+{
+ BM_editselection_normal(normal, ese);
+}
+
+/* Calculate a plane that is rightangles to the edge/vert/faces normal
+also make the plane run allong an axis that is related to the geometry,
+because this is used for the manipulators Y axis.*/
+void EDBM_editselection_plane(BMEditMesh *em, float *plane, BMEditSelection *ese)
+{
+ BM_editselection_plane(em->bm, plane, ese);
+}
+
+void EDBM_remove_selection(BMEditMesh *em, void *data)
+{
+ BM_remove_selection(em->bm, data);
+}
+
+void EDBM_store_selection(BMEditMesh *em, void *data)
+{
+ BM_store_selection(em->bm, data);
+}
+
+void EDBM_validate_selections(BMEditMesh *em)
+{
+ BM_validate_selections(em->bm);
+}
diff --git a/source/blender/editors/mesh/bmesh_tools.c b/source/blender/editors/mesh/bmesh_tools.c
new file mode 100644
index 00000000000..7f15056d6bd
--- /dev/null
+++ b/source/blender/editors/mesh/bmesh_tools.c
@@ -0,0 +1,4795 @@
+ /* $Id: bmesh_tools.c
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_key_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "RNA_types.h"
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_heap.h"
+#include "BLI_array.h"
+
+#include "BKE_material.h"
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+#include "BKE_texture.h"
+#include "BKE_main.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+#include "ED_view3d.h"
+#include "ED_util.h"
+#include "ED_screen.h"
+#include "ED_transform.h"
+#include "ED_object.h"
+
+#include "UI_interface.h"
+
+#include "RE_render_ext.h"
+
+#include "mesh_intern.h"
+#include "bmesh.h"
+
+#include "editbmesh_bvh.h"
+
+static void add_normal_aligned(float *nor, float *add)
+{
+ if( INPR(nor, add) < -0.9999f)
+ sub_v3_v3v3(nor, nor, add);
+ else
+ add_v3_v3v3(nor, nor, add);
+}
+
+
+static int subdivide_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ int cuts= RNA_int_get(op->ptr,"number_cuts");
+ float smooth= 0.292f*RNA_float_get(op->ptr, "smoothness");
+ float fractal= RNA_float_get(op->ptr, "fractal")/100;
+ int flag= 0;
+
+ if(smooth != 0.0f)
+ flag |= B_SMOOTH;
+ if(fractal != 0.0f)
+ flag |= B_FRACTAL;
+
+ BM_esubdivideflag(obedit, em->bm, BM_SELECT,
+ smooth, fractal,
+ ts->editbutflag|flag,
+ cuts, 0, RNA_enum_get(op->ptr, "quadcorner"),
+ RNA_boolean_get(op->ptr, "tess_single_edge"),
+ RNA_boolean_get(op->ptr, "gridfill"));
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+/* Note, these values must match delete_mesh() event values */
+static EnumPropertyItem prop_mesh_cornervert_types[] = {
+ {SUBD_INNERVERT, "INNERVERT", 0, "Inner Vert", ""},
+ {SUBD_PATH, "PATH", 0, "Path", ""},
+ {SUBD_STRAIGHT_CUT, "STRAIGHT_CUT", 0, "Straight Cut", ""},
+ {SUBD_FAN, "FAN", 0, "Fan", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+void MESH_OT_subdivide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Subdivide";
+ ot->description= "Subdivide selected edges.";
+ ot->idname= "MESH_OT_subdivide";
+
+ /* api callbacks */
+ ot->exec= subdivide_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_int(ot->srna, "number_cuts", 1, 1, 20, "Number of Cuts", "", 1, INT_MAX);
+ RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f);
+ RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1000.0f, "Smoothness", "Smoothness factor.", 0.0f, FLT_MAX);
+
+ /*props */
+ RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_STRAIGHT_CUT, "Quad Corner Type", "Method used for subdividing two adjacent edges in a quad");
+ RNA_def_boolean(ot->srna, "tess_single_edge", 0, "Tesselate Single Edge", "Adds triangles to single edges belonging to triangles or quads");
+ RNA_def_boolean(ot->srna, "gridfill", 1, "Grid Fill", "Fill Fully Selected Triangles and Quads With A Grid");
+}
+
+/* individual face extrude */
+/* will use vertex normals for extrusion directions, so *nor is unaffected */
+short EDBM_Extrude_face_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor)
+{
+ BMOIter siter;
+ BMIter liter;
+ BMFace *f;
+ BMLoop *l;
+ BMOperator bmop;
+
+ EDBM_InitOpf(em, &bmop, op, "extrude_face_indiv faces=%hf", flag);
+
+ /*deselect original verts*/
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ BMO_Exec_Op(em->bm, &bmop);
+
+ BMO_ITER(f, &siter, em->bm, &bmop, "faceout", BM_FACE) {
+ BM_Select(em->bm, f, 1);
+
+ /*set face vertex normals to face normal*/
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
+ VECCOPY(l->v->no, f->no);
+ }
+ }
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
+
+ return 's'; // s is shrink/fatten
+}
+
+#if 0
+short EDBM_Extrude_face_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor)
+ EditVert *eve, *v1, *v2, *v3, *v4;
+ EditEdge *eed;
+ EditFace *efa, *nextfa;
+
+ if(em==NULL) return 0;
+
+ /* selected edges with 1 or more selected face become faces */
+ /* selected faces each makes new faces */
+ /* always remove old faces, keeps volumes manifold */
+ /* select the new extrusion, deselect old */
+
+ /* step 1; init, count faces in edges */
+ recalc_editnormals(em);
+
+ for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; // new select flag
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->f2= 0; // amount of unselected faces
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT);
+ else {
+ efa->e1->f2++;
+ efa->e2->f2++;
+ efa->e3->f2++;
+ if(efa->e4) efa->e4->f2++;
+ }
+ }
+
+ /* step 2: make new faces from faces */
+ for(efa= em->faces.last; efa; efa= efa->prev) {
+ if(efa->f & SELECT) {
+ v1= addvertlist(em, efa->v1->co, efa->v1);
+ v2= addvertlist(em, efa->v2->co, efa->v2);
+ v3= addvertlist(em, efa->v3->co, efa->v3);
+
+ v1->f1= v2->f1= v3->f1= 1;
+ VECCOPY(v1->no, efa->n);
+ VECCOPY(v2->no, efa->n);
+ VECCOPY(v3->no, efa->n);
+ if(efa->v4) {
+ v4= addvertlist(em, efa->v4->co, efa->v4);
+ v4->f1= 1;
+ VECCOPY(v4->no, efa->n);
+ }
+ else v4= NULL;
+
+ /* side faces, clockwise */
+ addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL);
+ addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL);
+ if(efa->v4) {
+ addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL);
+ addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL);
+ }
+ else {
+ addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL);
+ }
+ /* top face */
+ addfacelist(em, v1, v2, v3, v4, efa, NULL);
+ }
+ }
+
+ /* step 3: remove old faces */
+ efa= em->faces.first;
+ while(efa) {
+ nextfa= efa->next;
+ if(efa->f & SELECT) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(em, efa);
+ }
+ efa= nextfa;
+ }
+
+ /* step 4: redo selection */
+ EM_clear_flag_all(em, SELECT);
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f1) eve->f |= SELECT;
+ }
+
+ EM_select_flush(em);
+
+ return 'n';
+}
+#endif
+
+/* extrudes individual edges */
+short EDBM_Extrude_edges_indiv(BMEditMesh *em, wmOperator *op, short flag, float *UNUSED(nor))
+{
+ BMOperator bmop;
+
+ EDBM_InitOpf(em, &bmop, op, "extrude_edge_only edges=%he", flag);
+
+ /*deselect original verts*/
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_VERT|BM_EDGE);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
+
+ return 'n'; // n is normal grab
+}
+
+#if 0
+/* nor is filled with constraint vector */
+short EDBM_Extrude_edges_indiv(BMEditMesh *em, short flag, float *nor)
+{
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+
+ for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL;
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->tmp.f = NULL;
+ eed->f2= ((eed->f & flag)!=0);
+ }
+
+ set_edge_directions_f2(em, 2);
+
+ /* sample for next loop */
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ efa->e1->tmp.f = efa;
+ efa->e2->tmp.f = efa;
+ efa->e3->tmp.f = efa;
+ if(efa->e4) efa->e4->tmp.f = efa;
+ }
+ /* make the faces */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f & flag) {
+ if(eed->v1->tmp.v == NULL)
+ eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1);
+ if(eed->v2->tmp.v == NULL)
+ eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2);
+
+ if(eed->dir==1)
+ addfacelist(em, eed->v1, eed->v2,
+ eed->v2->tmp.v, eed->v1->tmp.v,
+ eed->tmp.f, NULL);
+ else
+ addfacelist(em, eed->v2, eed->v1,
+ eed->v1->tmp.v, eed->v2->tmp.v,
+ eed->tmp.f, NULL);
+
+ /* for transform */
+ if(eed->tmp.f) {
+ efa = eed->tmp.f;
+ if (efa->f & SELECT) add_normal_aligned(nor, efa->n);
+ }
+ }
+ }
+ normalize_v3(nor);
+
+ /* set correct selection */
+ EM_clear_flag_all(em, SELECT);
+ for(eve= em->verts.last; eve; eve= eve->prev) {
+ if(eve->tmp.v) {
+ eve->tmp.v->f |= flag;
+ }
+ }
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->v1->f & eed->v2->f & flag) eed->f |= flag;
+ }
+
+ if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab
+ return 'n'; // n is for normal constraint
+}
+#endif
+
+/* extrudes individual vertices */
+short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor)
+{
+ BMOperator bmop;
+
+ EDBM_InitOpf(em, &bmop, op, "extrude_vert_indiv verts=%hv", flag);
+
+ /*deselect original verts*/
+ BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "verts", BM_SELECT, BM_VERT);
+
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_VERT);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
+
+ return 'g'; // g is grab
+}
+
+short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int flag, float *nor)
+{
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMOIter siter;
+ BMOperator extop;
+ BMVert *vert;
+ BMEdge *edge;
+ BMFace *f;
+ ModifierData *md;
+ BMHeader *el;
+
+ BMO_Init_Op(&extop, "extrudefaceregion");
+ BMO_HeaderFlag_To_Slot(bm, &extop, "edgefacein",
+ flag, BM_VERT|BM_EDGE|BM_FACE);
+
+ /* If a mirror modifier with clipping is on, we need to adjust some
+ * of the cases above to handle edges on the line of symmetry.
+ */
+ md = obedit->modifiers.first;
+ for (; md; md=md->next) {
+ if (md->type==eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ if(mmd->flag & MOD_MIR_CLIPPING) {
+ float mtx[4][4];
+ if (mmd->mirror_ob) {
+ float imtx[4][4];
+ invert_m4_m4(imtx, mmd->mirror_ob->obmat);
+ mul_m4_m4m4(mtx, obedit->obmat, imtx);
+ }
+
+ for (edge=BMIter_New(&iter,bm,BM_EDGES_OF_MESH,NULL);
+ edge; edge=BMIter_Step(&iter))
+ {
+ if(edge->head.flag & flag) {
+ float co1[3], co2[3];
+
+ copy_v3_v3(co1, edge->v1->co);
+ copy_v3_v3(co2, edge->v2->co);
+
+ if (mmd->mirror_ob) {
+ mul_v3_m4v3(co1, mtx, co1);
+ mul_v3_m4v3(co2, mtx, co2);
+ }
+
+ if (mmd->flag & MOD_MIR_AXIS_X)
+ if ( (fabs(co1[0]) < mmd->tolerance) &&
+ (fabs(co2[0]) < mmd->tolerance) )
+ BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
+
+ if (mmd->flag & MOD_MIR_AXIS_Y)
+ if ( (fabs(co1[1]) < mmd->tolerance) &&
+ (fabs(co2[1]) < mmd->tolerance) )
+ BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
+
+ if (mmd->flag & MOD_MIR_AXIS_Z)
+ if ( (fabs(co1[2]) < mmd->tolerance) &&
+ (fabs(co2[2]) < mmd->tolerance) )
+ BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
+ }
+ }
+ }
+ }
+ }
+
+ BM_ITER(vert, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BM_Select(bm, vert, 0);
+ }
+
+ BM_ITER(edge, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ BM_Select(bm, edge, 0);
+ }
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BM_Select(bm, f, 0);
+ }
+
+ BMO_Exec_Op(bm, &extop);
+
+ nor[0] = nor[1] = nor[2] = 0.0f;
+
+ BMO_ITER(el, &siter, bm, &extop, "geomout", BM_ALL) {
+ BM_Select(bm, el, 1);
+
+ if (el->type == BM_FACE) {
+ f = (BMFace*)el;
+ add_normal_aligned(nor, f->no);
+ };
+ }
+
+ normalize_v3(nor);
+
+ BMO_Finish_Op(bm, &extop);
+
+ if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab
+ return 'n'; // normal constraint
+
+}
+short EDBM_Extrude_vert(Object *obedit, BMEditMesh *em, short flag, float *nor)
+{
+ BMIter iter;
+ BMEdge *eed;
+
+ /*ensure vert flags are consistent for edge selections*/
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(eed, flag)) {
+ if (flag != BM_SELECT) {
+ BM_SetHFlag(eed->v1, flag);
+ BM_SetHFlag(eed->v2, flag);
+ } else {
+ BM_Select(em->bm, eed->v1, 1);
+ BM_Select(em->bm, eed->v2, 1);
+ }
+ } else {
+ if (BM_TestHFlag(eed->v1, flag) && BM_TestHFlag(eed->v2, flag)) {
+ if (flag != BM_SELECT)
+ BM_SetHFlag(eed, flag);
+ else BM_Select(em->bm, eed, 1);
+ }
+ }
+ }
+
+ return EDBM_Extrude_edge(obedit, em, flag, nor);
+
+}
+
+static int extrude_repeat_mesh(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ int steps = RNA_int_get(op->ptr,"steps");
+
+ float offs = RNA_float_get(op->ptr,"offset");
+ float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
+ short a;
+
+ /* dvec */
+ dvec[0]= rv3d->persinv[2][0];
+ dvec[1]= rv3d->persinv[2][1];
+ dvec[2]= rv3d->persinv[2][2];
+ normalize_v3(dvec);
+ dvec[0]*= offs;
+ dvec[1]*= offs;
+ dvec[2]*= offs;
+
+ /* base correction */
+ copy_m3_m4(bmat, obedit->obmat);
+ invert_m3_m3(tmat, bmat);
+ mul_m3_v3(tmat, dvec);
+
+ for(a=0; a<steps; a++) {
+ EDBM_Extrude_edge(obedit, em, BM_SELECT, nor);
+ //BMO_CallOpf(em->bm, "extrudefaceregion edgefacein=%hef", BM_SELECT);
+ BMO_CallOpf(em->bm, "translate vec=%v verts=%hv", (float*)dvec, BM_SELECT);
+ //extrudeflag(obedit, em, SELECT, nor);
+ //translateflag(em, SELECT, dvec);
+ }
+
+ EDBM_RecalcNormals(em);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_extrude_repeat(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Extrude Repeat Mesh";
+ ot->description= "Extrude selected vertices, edges or faces repeatedly.";
+ ot->idname= "MESH_OT_extrude_repeat";
+
+ /* api callbacks */
+ ot->exec= extrude_repeat_mesh;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, FLT_MAX);
+ RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, INT_MAX);
+}
+
+/* generic extern called extruder */
+int EDBM_Extrude_Mesh(Scene *scene, Object *obedit, BMEditMesh *em, wmOperator *op, float *norin)
+{
+ short nr, transmode= 0;
+ float stacknor[3] = {0.0f, 0.0f, 0.0f};
+ float *nor = norin ? norin : stacknor;
+
+ nor[0] = nor[1] = nor[2] = 0.0f;
+
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ if(em->bm->totvertsel==0) nr= 0;
+ else if(em->bm->totvertsel==1) nr= 4;
+ else if(em->bm->totedgesel==0) nr= 4;
+ else if(em->bm->totfacesel==0)
+ nr= 3; // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4");
+ else if(em->bm->totfacesel==1)
+ nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4");
+ else
+ nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
+ }
+ else if(em->selectmode & SCE_SELECT_EDGE) {
+ if (em->bm->totedgesel==0) nr = 0;
+
+ nr = 1;
+ /*else if (em->totedgesel==1) nr = 3;
+ else if(em->totfacesel==0) nr = 3;
+ else if(em->totfacesel==1)
+ nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3");
+ else
+ nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
+ */
+ }
+ else {
+ if (em->bm->totfacesel == 0) nr = 0;
+ else if (em->bm->totfacesel == 1) nr = 1;
+ else
+ nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
+ }
+
+ if(nr<1) return 'g';
+
+ if(nr==1 && em->selectmode & SCE_SELECT_VERTEX)
+ transmode= EDBM_Extrude_vert(obedit, em, SELECT, nor);
+ else if (nr == 1) transmode= EDBM_Extrude_edge(obedit, em, SELECT, nor);
+ else if(nr==4) transmode= EDBM_Extrude_verts_indiv(em, op, SELECT, nor);
+ else if(nr==3) transmode= EDBM_Extrude_edges_indiv(em, op, SELECT, nor);
+ else transmode= EDBM_Extrude_face_indiv(em, op, SELECT, nor);
+
+ if(transmode==0) {
+ BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude");
+ }
+ else {
+
+ /* We need to force immediate calculation here because
+ * transform may use derived objects (which are now stale).
+ *
+ * This shouldn't be necessary, derived queries should be
+ * automatically building this data if invalid. Or something.
+ */
+// DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+ object_handle_update(scene, obedit);
+
+ /* individual faces? */
+// BIF_TransformSetUndo("Extrude");
+ if(nr==2) {
+// initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR);
+// Transform();
+ }
+ else {
+// initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR);
+ if(transmode=='n') {
+ mul_m4_v3(obedit->obmat, nor);
+ sub_v3_v3v3(nor, nor, obedit->obmat[3]);
+// BIF_setSingleAxisConstraint(nor, "along normal");
+ }
+// Transform();
+ }
+ }
+
+ return transmode;
+}
+
+/* extrude without transform */
+static int mesh_extrude_region_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+
+ EDBM_Extrude_Mesh(scene, obedit, em, op, NULL);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_extrude_region(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Extrude Region";
+ ot->idname= "MESH_OT_extrude_region";
+
+ /* api callbacks */
+ //ot->invoke= mesh_extrude_region_invoke;
+ ot->exec= mesh_extrude_region_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
+}
+
+static int mesh_extrude_verts_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ float nor[3];
+
+ EDBM_Extrude_verts_indiv(em, op, BM_SELECT, nor);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_extrude_verts_indiv(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Extrude Only Vertices";
+ ot->idname= "MESH_OT_extrude_verts_indiv";
+
+ /* api callbacks */
+ ot->exec= mesh_extrude_verts_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* to give to transform */
+ RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
+}
+
+static int mesh_extrude_edges_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ float nor[3];
+
+ EDBM_Extrude_edges_indiv(em, op, BM_SELECT, nor);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_extrude_edges_indiv(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Extrude Only Edges";
+ ot->idname= "MESH_OT_extrude_edges_indiv";
+
+ /* api callbacks */
+ ot->exec= mesh_extrude_edges_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* to give to transform */
+ RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
+}
+
+static int mesh_extrude_faces_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ float nor[3];
+
+ EDBM_Extrude_face_indiv(em, op, BM_SELECT, nor);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_extrude_faces_indiv(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Extrude Individual Faces";
+ ot->idname= "MESH_OT_extrude_faces_indiv";
+
+ /* api callbacks */
+ ot->exec= mesh_extrude_faces_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
+}
+
+/* ******************** (de)select all operator **************** */
+
+void EDBM_toggle_select_all(BMEditMesh *em) /* exported for UV */
+{
+ if(em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel)
+ EDBM_clear_flag_all(em, SELECT);
+ else
+ EDBM_set_flag_all(em, SELECT);
+}
+
+static int toggle_select_all_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ EDBM_toggle_select_all(em);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select/Deselect All";
+ ot->idname= "MESH_OT_select_all";
+ ot->description= "(de)select all vertices, edges or faces.";
+
+ /* api callbacks */
+ ot->exec= toggle_select_all_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/* *************** add-click-mesh (extrude) operator ************** */
+
+static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
+{
+ ViewContext vc;
+ BMVert *v1;
+ BMIter iter;
+ float min[3], max[3];
+ int done= 0;
+
+ em_setup_viewcontext(C, &vc);
+
+ INIT_MINMAX(min, max);
+
+ BM_ITER_SELECT(v1, &iter, vc.em->bm, BM_VERTS_OF_MESH, NULL)
+ DO_MINMAX(v1->co, min, max);
+ done= 1;
+ }
+
+ /* call extrude? */
+ if(done) {
+ BMEdge *eed;
+ float vec[3], cent[3], mat[3][3];
+ float nor[3]= {0.0, 0.0, 0.0};
+
+ /* check for edges that are half selected, use for rotation */
+ done= 0;
+ BM_ITER(eed, &iter, vc.em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(eed->v1, BM_SELECT) ^ BM_TestHFlag(eed->v2, BM_SELECT)) {
+ if(BM_TestHFlag(eed->v1, BM_SELECT))
+ sub_v3_v3v3(vec, eed->v1->co, eed->v2->co);
+ else
+ sub_v3_v3v3(vec, eed->v2->co, eed->v1->co);
+ add_v3_v3v3(nor, nor, vec);
+ done= 1;
+ }
+ }
+ if(done) normalize_v3(nor);
+
+ /* center */
+ add_v3_v3v3(cent, min, max);
+ mul_v3_fl(cent, 0.5f);
+ VECCOPY(min, cent);
+
+ mul_m4_v3(vc.obedit->obmat, min); // view space
+ view3d_get_view_aligned_coordinate(&vc, min, event->mval);
+ invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
+ mul_m4_v3(vc.obedit->imat, min); // back in object space
+
+ sub_v3_v3v3(min, min, cent);
+
+ /* calculate rotation */
+ unit_m3(mat);
+ if(done) {
+ float dot;
+
+ VECCOPY(vec, min);
+ normalize_v3(vec);
+ dot= INPR(vec, nor);
+
+ if( fabs(dot)<0.999) {
+ float cross[3], si, q1[4];
+
+ cross_v3_v3v3(cross, nor, vec);
+ normalize_v3(cross);
+ dot= 0.5f*saacos(dot);
+ si= (float)sin(dot);
+ q1[0]= (float)cos(dot);
+ q1[1]= cross[0]*si;
+ q1[2]= cross[1]*si;
+ q1[3]= cross[2]*si;
+
+ quat_to_mat3( mat,q1);
+ }
+ }
+
+
+ EDBM_Extrude_edge(vc.obedit, vc.em, SELECT, nor);
+ EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
+ BM_SELECT, cent, mat);
+ EDBM_CallOpf(vc.em, op, "translate verts=%hv vec=%v",
+ BM_SELECT, min);
+ }
+ else {
+ float *curs= give_cursor(vc.scene, vc.v3d);
+ BMOperator bmop;
+ BMOIter oiter;
+
+ VECCOPY(min, curs);
+
+ view3d_get_view_aligned_coordinate(&vc, min, event->mval);
+ invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
+ mul_m4_v3(vc.obedit->imat, min); // back in object space
+
+ EDBM_InitOpf(vc.em, &bmop, op, "makevert co=%v", min);
+ BMO_Exec_Op(vc.em->bm, &bmop);
+
+ BMO_ITER(v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) {
+ BM_Select(vc.em->bm, v1, 1);
+ }
+
+ if (!EDBM_FinishOp(vc.em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+ }
+
+ //retopo_do_all();
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, vc.obedit->data);
+ DAG_id_tag_update(vc.obedit->data, OB_RECALC_DATA);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Duplicate or Extrude at 3D Cursor";
+ ot->idname= "MESH_OT_dupli_extrude_cursor";
+
+ /* api callbacks */
+ ot->invoke= dupli_extrude_cursor;
+ ot->description= "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor.";
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int delete_mesh(bContext *C, Object *obedit, wmOperator *op, int event, Scene *UNUSED(scene))
+{
+ BMEditMesh *bem = ((Mesh*)obedit->data)->edit_btmesh;
+
+ if(event<1) return OPERATOR_CANCELLED;
+
+ if(event==10 ) {
+ //"Erase Vertices";
+
+ if (!EDBM_CallOpf(bem, op, "del geom=%hv context=%i", BM_SELECT, DEL_VERTS))
+ return OPERATOR_CANCELLED;
+ }
+ else if(event==11) {
+ //"Edge Loop"
+ if (!EDBM_CallOpf(bem, op, "dissolveedgeloop edges=%he", BM_SELECT))
+ return OPERATOR_CANCELLED;
+ }
+ else if(event==7) {
+ //"Dissolve"
+ if (bem->selectmode & SCE_SELECT_FACE) {
+ if (!EDBM_CallOpf(bem, op, "dissolvefaces faces=%hf",BM_SELECT))
+ return OPERATOR_CANCELLED;
+ } else if (bem->selectmode & SCE_SELECT_EDGE) {
+ if (!EDBM_CallOpf(bem, op, "dissolveedges edges=%he",BM_SELECT))
+ return OPERATOR_CANCELLED;
+ } else if (bem->selectmode & SCE_SELECT_VERTEX) {
+ if (!EDBM_CallOpf(bem, op, "dissolveverts verts=%hv",BM_SELECT))
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else if(event==4) {
+ //Edges and Faces
+ if (!EDBM_CallOpf(bem, op, "del geom=%hef context=%i", BM_SELECT, DEL_EDGESFACES))
+ return OPERATOR_CANCELLED;
+ }
+ else if(event==1) {
+ //"Erase Edges"
+ if (!EDBM_CallOpf(bem, op, "del geom=%he context=%i", BM_SELECT, DEL_EDGES))
+ return OPERATOR_CANCELLED;
+ }
+ else if(event==2) {
+ //"Erase Faces";
+ if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%i", BM_SELECT, DEL_FACES))
+ return OPERATOR_CANCELLED;
+ }
+ else if(event==5) {
+ //"Erase Only Faces";
+ if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%d",
+ BM_SELECT, DEL_ONLYFACES))
+ return OPERATOR_CANCELLED;
+ }
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+/* Note, these values must match delete_mesh() event values */
+static EnumPropertyItem prop_mesh_delete_types[] = {
+ {7, "DISSOLVE", 0, "Dissolve", ""},
+ {10,"VERT", 0, "Vertices", ""},
+ {1, "EDGE", 0, "Edges", ""},
+ {2, "FACE", 0, "Faces", ""},
+ {11, "EDGE_LOOP", 0, "Edge Loop", ""},
+ {4, "EDGE_FACE", 0, "Edges & Faces", ""},
+ {5, "ONLY_FACE", 0, "Only Faces", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int delete_mesh_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+
+ delete_mesh(C, obedit, op, RNA_enum_get(op->ptr, "type"), scene);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Delete";
+ ot->description= "Delete selected vertices, edges or faces.";
+ ot->idname= "MESH_OT_delete";
+
+ /* api callbacks */
+ ot->invoke= WM_menu_invoke;
+ ot->exec= delete_mesh_exec;
+
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /*props */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data");
+}
+
+
+static int addedgeface_mesh_exec(bContext *C, wmOperator *op)
+{
+ BMOperator bmop;
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ if (!EDBM_InitOpf(em, &bmop, op, "contextual_create geom=%hfev", BM_SELECT))
+ return OPERATOR_CANCELLED;
+
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT, BM_FACE);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_edge_face_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Make Edge/Face";
+ ot->description= "Add an edge or face to selected.";
+ ot->idname= "MESH_OT_edge_face_add";
+
+ /* api callbacks */
+ ot->exec= addedgeface_mesh_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+}
+
+static EnumPropertyItem prop_mesh_edit_types[] = {
+ {1, "VERT", 0, "Vertices", ""},
+ {2, "EDGE", 0, "Edges", ""},
+ {3, "FACE", 0, "Faces", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int mesh_selection_type_exec(bContext *C, wmOperator *op)
+{
+
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ int type = RNA_enum_get(op->ptr,"type");
+
+ switch (type) {
+ case 1:
+ em->selectmode = SCE_SELECT_VERTEX;
+ break;
+ case 2:
+ em->selectmode = SCE_SELECT_EDGE;
+ break;
+ case 3:
+ em->selectmode = SCE_SELECT_FACE;
+ break;
+ }
+
+ EDBM_selectmode_set(em);
+ CTX_data_tool_settings(C)->selectmode = em->selectmode;
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_selection_type(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Selection Mode";
+ ot->description= "Set the selection mode type.";
+ ot->idname= "MESH_OT_selection_type";
+
+ /* api callbacks */
+ ot->invoke= WM_menu_invoke;
+ ot->exec= mesh_selection_type_exec;
+
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "type", prop_mesh_edit_types, 0, "Type", "Set the mesh selection type");
+ RNA_def_boolean(ot->srna, "inclusive", 0, "Inclusive", "Selects geometry around selected geometry, occording to selection mode");
+}
+
+/* ************************* SEAMS AND EDGES **************** */
+
+static int editbmesh_mark_seam(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Mesh *me= ((Mesh *)obedit->data);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMEdge *eed;
+ BMIter iter;
+ int clear = RNA_boolean_get(op->ptr, "clear");
+
+ /* auto-enable seams drawing */
+ if(clear==0) {
+ me->drawflag |= ME_DRAWSEAMS;
+ }
+
+ if(clear) {
+ BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
+ BM_ClearHFlag(eed, BM_SEAM);
+ }
+ }
+ else {
+ BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
+ BM_SetHFlag(eed, BM_SEAM);
+ }
+ }
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_mark_seam(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Mark Seam";
+ ot->idname= "MESH_OT_mark_seam";
+ ot->description= "(un)mark selected edges as a seam.";
+
+ /* api callbacks */
+ ot->exec= editbmesh_mark_seam;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
+}
+
+static int editbmesh_mark_sharp(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Mesh *me= ((Mesh *)obedit->data);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMEdge *eed;
+ BMIter iter;
+ int clear = RNA_boolean_get(op->ptr, "clear");
+
+ /* auto-enable sharp edge drawing */
+ if(clear == 0) {
+ me->drawflag |= ME_DRAWSHARP;
+ }
+
+ if(!clear) {
+ BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
+ BM_SetHFlag(eed, BM_SHARP);
+ }
+ } else {
+ BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
+ BM_ClearHFlag(eed, BM_SHARP);
+ }
+ }
+
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_mark_sharp(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Mark Sharp";
+ ot->idname= "MESH_OT_mark_sharp";
+ ot->description= "(un)mark selected edges as sharp.";
+
+ /* api callbacks */
+ ot->exec= editbmesh_mark_sharp;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
+}
+
+
+static int editbmesh_vert_connect(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMOperator bmop;
+ int len = 0;
+
+ BMO_InitOpf(bm, &bmop, "connectverts verts=%hv", BM_SELECT);
+ BMO_Exec_Op(bm, &bmop);
+ len = BMO_GetSlot(&bmop, "edgeout")->len;
+ BMO_Finish_Op(bm, &bmop);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+void MESH_OT_vert_connect(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Vertex Connect";
+ ot->idname= "MESH_OT_vert_connect";
+
+ /* api callbacks */
+ ot->exec= editbmesh_vert_connect;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int editbmesh_edge_split(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMOperator bmop;
+ int len = 0;
+
+ BMO_InitOpf(bm, &bmop, "edgesplit edges=%he numcuts=%d", BM_SELECT, RNA_int_get(op->ptr,"number_cuts"));
+ BMO_Exec_Op(bm, &bmop);
+ len = BMO_GetSlot(&bmop, "outsplit")->len;
+ BMO_Finish_Op(bm, &bmop);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+void MESH_OT_edge_split(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Edge Split";
+ ot->idname= "MESH_OT_edge_split";
+
+ /* api callbacks */
+ ot->exec= editbmesh_edge_split;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, INT_MAX);
+}
+
+/****************** add duplicate operator ***************/
+
+static int mesh_duplicate_exec(bContext *C, wmOperator *op)
+{
+ Object *ob= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+
+ EDBM_InitOpf(em, &bmop, op, "dupe geom=%hvef", BM_SELECT);
+
+ BMO_Exec_Op(em->bm, &bmop);
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "newout", BM_SELECT, BM_ALL);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static int mesh_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ WM_cursor_wait(1);
+ mesh_duplicate_exec(C, op);
+ WM_cursor_wait(0);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_duplicate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Duplicate";
+ ot->description= "Duplicate selected vertices, edges or faces.";
+ ot->idname= "MESH_OT_duplicate";
+
+ /* api callbacks */
+ ot->invoke= mesh_duplicate_invoke;
+ ot->exec= mesh_duplicate_exec;
+
+ ot->poll= ED_operator_editmesh;
+
+ /* to give to transform */
+ RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
+}
+
+static int flip_normals(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+
+ if (!EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_SELECT))
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_flip_normals(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Flip Normals";
+ ot->description= "Flip the direction of selected face's vertex and face normals";
+ ot->idname= "MESH_OT_flip_normals";
+
+ /* api callbacks */
+ ot->exec= flip_normals;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+float *bm_get_cd_float(CustomData *cdata, void *data, int type)
+{
+ float *f = CustomData_bmesh_get(cdata, data, type);
+
+ return f;
+}
+
+static const EnumPropertyItem direction_items[]= {
+ {DIRECTION_CW, "CW", 0, "Clockwise", ""},
+ {DIRECTION_CCW, "CCW", 0, "Counter Clockwise", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+/* only accepts 1 selected edge, or 2 selected faces */
+static int edge_rotate_selected(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMOperator bmop;
+ BMEdge *eed;
+ BMIter iter;
+ int ccw = RNA_int_get(op->ptr, "direction") == 1; // direction == 2 when clockwise and ==1 for counter CW.
+
+ if (!(em->bm->totfacesel == 2 || em->bm->totedgesel == 1)) {
+ BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
+ return OPERATOR_CANCELLED;
+ }
+
+ /*first see if we have two adjacent faces*/
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_Edge_FaceCount(eed) == 2) {
+ if ((BM_TestHFlag(eed->l->f, BM_SELECT) && BM_TestHFlag(((BMLoop*)eed->l->radial_next)->f, BM_SELECT))
+ && !(BM_TestHFlag(eed->l->f, BM_HIDDEN) || BM_TestHFlag(((BMLoop*)eed->l->radial_next)->f, BM_HIDDEN)))
+ {
+ break;
+ }
+ }
+ }
+
+ /*ok, we don't have two adjacent faces, but we do have two selected ones.
+ that's an error condition.*/
+ if (!eed && em->bm->totfacesel == 2) {
+ BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!eed) {
+ BM_ITER_SELECT(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL)
+ if (BM_TestHFlag(eed, BM_SELECT))
+ break;
+ }
+ }
+
+ /*this should never happen*/
+ if (!eed)
+ return OPERATOR_CANCELLED;
+
+ EDBM_InitOpf(em, &bmop, op, "edgerotate edges=%e ccw=%d", eed, ccw);
+ BMO_Exec_Op(em->bm, &bmop);
+
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "edgeout", BM_SELECT, BM_EDGE);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_edge_rotate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Rotate Selected Edge";
+ ot->description= "Rotate selected edge or adjoining faces.";
+ ot->idname= "MESH_OT_edge_rotate";
+
+ /* api callbacks */
+ ot->exec= edge_rotate_selected;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "direction", "direction to rotate edge around.");
+}
+
+/* pinning code */
+
+/* swap is 0 or 1, if 1 it pins not selected */
+void EDBM_pin_mesh(BMEditMesh *em, int swap)
+{
+ BMIter iter;
+ BMHeader *h;
+ int itermode;
+
+ if(em==NULL) return;
+
+ if (em->selectmode & SCE_SELECT_VERTEX)
+ itermode = BM_VERTS_OF_MESH;
+ else if (em->selectmode & SCE_SELECT_EDGE)
+ itermode = BM_EDGES_OF_MESH;
+ else
+ itermode = BM_FACES_OF_MESH;
+
+ BM_ITER(h, &iter, em->bm, itermode, NULL) {
+ if (BM_TestHFlag(h, BM_SELECT) ^ swap)
+ BM_Pin(em->bm, h, 1);
+ }
+
+ EDBM_selectmode_flush(em);
+}
+
+static int pin_mesh_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+ Mesh *me= ((Mesh *)obedit->data);
+
+ me->drawflag |= ME_DRAW_PINS;
+
+ EDBM_pin_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_pin(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Pin Selection";
+ ot->idname= "MESH_OT_pin";
+
+ /* api callbacks */
+ ot->exec= pin_mesh_exec;
+ ot->poll= ED_operator_editmesh;
+ ot->description= "Pin (un)selected vertices, edges or faces.";
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Pin unselected rather than selected.");
+}
+
+/* swap is 0 or 1, if 1 it unhides not selected */
+void EDBM_unpin_mesh(BMEditMesh *em, int swap)
+{
+ BMIter iter;
+ BMHeader *ele;
+ int itermode;
+
+ if(em==NULL) return;
+
+ if (em->selectmode & SCE_SELECT_VERTEX)
+ itermode = BM_VERTS_OF_MESH;
+ else if (em->selectmode & SCE_SELECT_EDGE)
+ itermode = BM_EDGES_OF_MESH;
+ else
+ itermode = BM_FACES_OF_MESH;
+
+ BM_ITER(ele, &iter, em->bm, itermode, NULL) {
+ if (BM_TestHFlag(ele, BM_SELECT) ^ swap)
+ BM_Pin(em->bm, ele, 0);
+ }
+
+ EDBM_selectmode_flush(em);
+}
+
+static int unpin_mesh_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+
+ EDBM_unpin_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_unpin(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Unpin Selection";
+ ot->idname= "MESH_OT_unpin";
+ ot->description= "Unpin (un)selected vertices, edges or faces.";
+
+ /* api callbacks */
+ ot->exec= unpin_mesh_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Unpin unselected rather than selected.");
+}
+
+
+/* swap is 0 or 1, if 1 it hides not selected */
+void EDBM_hide_mesh(BMEditMesh *em, int swap)
+{
+ BMIter iter;
+ BMHeader *h;
+ int itermode;
+
+ if(em==NULL) return;
+
+ if (em->selectmode & SCE_SELECT_VERTEX)
+ itermode = BM_VERTS_OF_MESH;
+ else if (em->selectmode & SCE_SELECT_EDGE)
+ itermode = BM_EDGES_OF_MESH;
+ else
+ itermode = BM_FACES_OF_MESH;
+
+ BM_ITER(h, &iter, em->bm, itermode, NULL) {
+ if (BM_TestHFlag(h, BM_SELECT) ^ swap)
+ BM_Hide(em->bm, h, 1);
+ }
+
+ /*original hide flushing comment (OUTDATED):
+ hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
+ /* - vertex hidden, always means edge is hidden too
+ - edge hidden, always means face is hidden too
+ - face hidden, only set face hide
+ - then only flush back down what's absolute hidden
+ */
+
+}
+
+static int hide_mesh_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+
+ EDBM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_hide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Hide Selection";
+ ot->idname= "MESH_OT_hide";
+
+ /* api callbacks */
+ ot->exec= hide_mesh_exec;
+ ot->poll= ED_operator_editmesh;
+ ot->description= "Hide (un)selected vertices, edges or faces.";
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
+}
+
+
+void EDBM_reveal_mesh(BMEditMesh *em)
+{
+ BMIter iter;
+ BMHeader *ele;
+ int i, types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
+ int sels[3] = {1, !(em->selectmode & SCE_SELECT_VERTEX), !(em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE))};
+
+ for (i=0; i<3; i++) {
+ BM_ITER(ele, &iter, em->bm, types[i], NULL) {
+ if (BM_TestHFlag(ele, BM_HIDDEN)) {
+ BM_Hide(em->bm, ele, 0);
+
+ if (sels[i])
+ BM_Select(em->bm, ele, 1);
+ }
+ }
+ }
+
+ EDBM_selectmode_flush(em);
+}
+
+static int reveal_mesh_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+
+ EDBM_reveal_mesh(em);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_reveal(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Reveal Hidden";
+ ot->idname= "MESH_OT_reveal";
+ ot->description= "Reveal all hidden vertices, edges and faces.";
+
+ /* api callbacks */
+ ot->exec= reveal_mesh_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int normals_make_consistent_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ if (!EDBM_CallOpf(em, op, "righthandfaces faces=%hf", BM_SELECT))
+ return OPERATOR_CANCELLED;
+
+ if (RNA_boolean_get(op->ptr, "inside"))
+ EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_SELECT);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_normals_make_consistent(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Make Normals Consistent";
+ ot->description= "Make face and vertex normals point either outside or inside the mesh";
+ ot->idname= "MESH_OT_normals_make_consistent";
+
+ /* api callbacks */
+ ot->exec= normals_make_consistent_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
+}
+
+
+
+static int do_smooth_vertex(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ ModifierData *md;
+ int mirrx=0, mirry=0, mirrz=0;
+ int i, repeat;
+
+ /* if there is a mirror modifier with clipping, flag the verts that
+ * are within tolerance of the plane(s) of reflection
+ */
+ for(md=obedit->modifiers.first; md; md=md->next) {
+ if(md->type==eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ if(mmd->flag & MOD_MIR_CLIPPING) {
+ if (mmd->flag & MOD_MIR_AXIS_X)
+ mirrx = 1;
+ if (mmd->flag & MOD_MIR_AXIS_Y)
+ mirry = 1;
+ if (mmd->flag & MOD_MIR_AXIS_Z)
+ mirrz = 1;
+ }
+ }
+ }
+
+ repeat = RNA_int_get(op->ptr,"repeat");
+ if (!repeat)
+ repeat = 1;
+
+ for (i=0; i<repeat; i++) {
+ if (!EDBM_CallOpf(em, op, "vertexsmooth verts=%hv mirror_clip_x=%d mirror_clip_y=%d mirror_clip_z=%d",
+ BM_SELECT, mirrx, mirry, mirrz))
+ {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ //BMESH_TODO: need to handle the x-axis editing option here properly.
+ //should probably make a helper function for that? I dunno.
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_vertices_smooth(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Smooth Vertex";
+ ot->description= "Flatten angles of selected vertices.";
+ ot->idname= "MESH_OT_vertices_smooth";
+
+ /* api callbacks */
+ ot->exec= do_smooth_vertex;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX);
+}
+
+
+static int bm_test_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ RegionView3D *r3d = CTX_wm_region_view3d(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMBVHTree *tree = BMBVH_NewBVH(em);
+ BMIter iter;
+ BMEdge *e;
+
+ /*hide all back edges*/
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(e, BM_SELECT))
+ continue;
+
+ if (!BMBVH_EdgeVisible(tree, e, r3d, obedit))
+ BM_Select(em->bm, e, 0);
+ }
+
+ BMBVH_FreeBVH(tree);
+
+#if 0 //uv island walker test
+ BMIter iter, liter;
+ BMFace *f;
+ BMLoop *l, *l2;
+ MLoopUV *luv;
+ BMWalker walker;
+ int i=0;
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ }
+ }
+
+ BMW_Init(&walker, em->bm, BMW_UVISLAND, 0);
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ l2 = BMW_Begin(&walker, l);
+ for (; l2; l2=BMW_Step(&walker)) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l2->head.data, CD_MLOOPUV);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
+ }
+ }
+ }
+
+ BMW_End(&walker);
+#endif
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_bm_test(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "BMesh Test Operator";
+ ot->idname= "MESH_OT_bm_test";
+
+ /* api callbacks */
+ ot->exec= bm_test_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ //RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX);
+}
+
+/********************** Smooth/Solid Operators *************************/
+
+void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
+{
+ BMIter iter;
+ BMFace *efa;
+
+ if(em==NULL) return;
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_TestHFlag(efa, BM_SELECT)) {
+ if (smooth)
+ BM_SetHFlag(efa, BM_SMOOTH);
+ else
+ BM_ClearHFlag(efa, BM_SMOOTH);
+ }
+ }
+}
+
+static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ mesh_set_smooth_faces(em, 1);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Shade Smooth";
+ ot->description= "Display faces smooth (using vertex normals).";
+ ot->idname= "MESH_OT_faces_shade_smooth";
+
+ /* api callbacks */
+ ot->exec= mesh_faces_shade_smooth_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int mesh_faces_shade_flat_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ mesh_set_smooth_faces(em, 0);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_faces_shade_flat(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Shade Flat";
+ ot->description= "Display faces flat.";
+ ot->idname= "MESH_OT_faces_shade_flat";
+
+ /* api callbacks */
+ ot->exec= mesh_faces_shade_flat_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+
+/********************** UV/Color Operators *************************/
+
+
+static const EnumPropertyItem axis_items[]= {
+ {OPUVC_AXIS_X, "X", 0, "X", ""},
+ {OPUVC_AXIS_Y, "Y", 0, "Y", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+static int mesh_rotate_uvs(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+
+ /* get the direction from RNA */
+ int dir = RNA_enum_get(op->ptr, "direction");
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "meshrotateuvs faces=%hf dir=%d", BM_SELECT, dir);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+
+ /* dependencies graph and notification stuff */
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+/* DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+*/
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+}
+
+static int mesh_reverse_uvs(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "meshreverseuvs faces=%hf", BM_SELECT);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+ /* dependencies graph and notification stuff */
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+/* DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+*/
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+}
+
+static int mesh_rotate_colors(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+
+ /* get the direction from RNA */
+ int dir = RNA_enum_get(op->ptr, "direction");
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "meshrotatecolors faces=%hf dir=%d", BM_SELECT, dir);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+
+ /* dependencies graph and notification stuff */
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+/* DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_GEOM_SELECT, ob);
+*/
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+}
+
+
+static int mesh_reverse_colors(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "meshreversecolors faces=%hf", BM_SELECT);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+#if 0
+ Scene *scene= CTX_data_scene(C);
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+
+ EditFace *efa;
+ short change = 0;
+ MCol tmpcol, *mcol;
+ int axis= RNA_enum_get(op->ptr, "axis");
+
+ if (!EM_vertColorCheck(em)) {
+ BKE_report(op->reports, RPT_ERROR, "Mesh has no color layers");
+ BKE_mesh_end_editmesh(obedit->data, em);
+ return OPERATOR_CANCELLED;
+ }
+
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
+ if (axis == AXIS_Y) {
+ tmpcol= mcol[1];
+ mcol[1]= mcol[2];
+ mcol[2]= tmpcol;
+
+ if(efa->v4) {
+ tmpcol= mcol[0];
+ mcol[0]= mcol[3];
+ mcol[3]= tmpcol;
+ }
+ } else {
+ tmpcol= mcol[0];
+ mcol[0]= mcol[1];
+ mcol[1]= tmpcol;
+
+ if(efa->v4) {
+ tmpcol= mcol[2];
+ mcol[2]= mcol[3];
+ mcol[3]= tmpcol;
+ }
+ }
+ change = 1;
+ }
+ }
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+
+ if(!change)
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+#endif
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_uvs_rotate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Rotate UVs";
+ ot->idname= "MESH_OT_uvs_rotate";
+
+ /* api callbacks */
+ ot->exec= mesh_rotate_uvs;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate UVs around.");
+}
+
+//void MESH_OT_uvs_mirror(wmOperatorType *ot)
+void MESH_OT_uvs_reverse(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Reverse UVs";
+ ot->idname= "MESH_OT_uvs_reverse";
+
+ /* api callbacks */
+ ot->exec= mesh_reverse_uvs;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around.");
+}
+
+void MESH_OT_colors_rotate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Rotate Colors";
+ ot->idname= "MESH_OT_colors_rotate";
+
+ /* api callbacks */
+ ot->exec= mesh_rotate_colors;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around.");
+}
+
+void MESH_OT_colors_reverse(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Reverse Colors";
+ ot->idname= "MESH_OT_colors_reverse";
+
+ /* api callbacks */
+ ot->exec= mesh_reverse_colors;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around.");
+}
+
+
+static int merge_firstlast(BMEditMesh *em, int first, int uvmerge, wmOperator *wmop)
+{
+ BMVert *mergevert;
+ BMEditSelection *ese;
+
+ /* do sanity check in mergemenu in edit.c ?*/
+ if(first == 0){
+ ese = em->bm->selected.last;
+ mergevert= (BMVert*)ese->data;
+ }
+ else{
+ ese = em->bm->selected.first;
+ mergevert = (BMVert*)ese->data;
+ }
+
+ if (!BM_TestHFlag(mergevert, BM_SELECT))
+ return OPERATOR_CANCELLED;
+
+ if (uvmerge) {
+ if (!EDBM_CallOpf(em, wmop, "pointmerge_facedata verts=%hv snapv=%e", BM_SELECT, mergevert))
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_SELECT, mergevert->co))
+ return OPERATOR_CANCELLED;
+
+ return OPERATOR_FINISHED;
+}
+
+static int merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob,
+ int target, int uvmerge, wmOperator *wmop)
+{
+ BMIter iter;
+ BMVert *v;
+ float *vco=NULL, co[3], cent[3] = {0.0f, 0.0f, 0.0f}, fac;
+ int i;
+
+ if (target) {
+ vco = give_cursor(scene, v3d);
+ VECCOPY(co, vco);
+ mul_m4_v3(ob->imat, co);
+ } else {
+ i = 0;
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_TestHFlag(v, BM_SELECT))
+ continue;
+ VECADD(cent, cent, v->co);
+ i++;
+ }
+
+ if (!i)
+ return OPERATOR_CANCELLED;
+
+ fac = 1.0f / (float)i;
+ mul_v3_fl(cent, fac);
+ copy_v3_v3(co, cent);
+ vco = co;
+ }
+
+ if (!vco)
+ return OPERATOR_CANCELLED;
+
+ if (uvmerge) {
+ if (!EDBM_CallOpf(em, wmop, "vert_average_facedata verts=%hv", BM_SELECT))
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_SELECT, co))
+ return OPERATOR_CANCELLED;
+
+ return OPERATOR_FINISHED;
+}
+
+static int merge_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene= CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ int status= 0, uvs= RNA_boolean_get(op->ptr, "uvs");
+
+ switch(RNA_enum_get(op->ptr, "type")) {
+ case 3:
+ status = merge_target(em, scene, v3d, obedit, 0, uvs, op);
+ break;
+ case 4:
+ status = merge_target(em, scene, v3d, obedit, 1, uvs, op);
+ break;
+ case 1:
+ status = merge_firstlast(em, 0, uvs, op);
+ break;
+ case 6:
+ status = merge_firstlast(em, 1, uvs, op);
+ break;
+ case 5:
+ status = 1;
+ if (!EDBM_CallOpf(em, op, "collapse edges=%he", BM_SELECT))
+ status = 0;
+ break;
+ }
+
+ if(!status)
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static EnumPropertyItem merge_type_items[]= {
+ {6, "FIRST", 0, "At First", ""},
+ {1, "LAST", 0, "At Last", ""},
+ {3, "CENTER", 0, "At Center", ""},
+ {4, "CURSOR", 0, "At Cursor", ""},
+ {5, "COLLAPSE", 0, "Collapse", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *ptr, int *free)
+{
+ Object *obedit;
+ EnumPropertyItem *item= NULL;
+ int totitem= 0;
+
+ if(!C) /* needed for docs */
+ return merge_type_items;
+
+ obedit= CTX_data_edit_object(C);
+ if(obedit && obedit->type == OB_MESH) {
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ if(em->bm->selected.first && em->bm->selected.last &&
+ ((BMEditSelection*)em->bm->selected.first)->type == BM_VERT && ((BMEditSelection*)em->bm->selected.last)->type == BM_VERT) {
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
+ }
+ else if(em->bm->selected.first && ((BMEditSelection*)em->bm->selected.first)->type == BM_VERT)
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
+ else if(em->bm->selected.last && ((BMEditSelection*)em->bm->selected.last)->type == BM_VERT)
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
+ }
+
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, 3);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, 4);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, 5);
+ RNA_enum_item_end(&item, &totitem);
+
+ *free= 1;
+
+ return item;
+ }
+
+ return NULL;
+}
+
+void MESH_OT_merge(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Merge";
+ ot->idname= "MESH_OT_merge";
+
+ /* api callbacks */
+ ot->exec= merge_exec;
+ ot->invoke= WM_menu_invoke;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop= RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use.");
+ RNA_def_enum_funcs(ot->prop, merge_type_itemf);
+ RNA_def_boolean(ot->srna, "uvs", 1, "UVs", "Move UVs according to merge.");
+}
+
+
+static int removedoublesflag_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMOperator bmop;
+ int count;
+
+ EDBM_InitOpf(em, &bmop, op, "finddoubles verts=%hv dist=%f",
+ BM_SELECT, RNA_float_get(op->ptr, "mergedist"));
+ BMO_Exec_Op(em->bm, &bmop);
+
+ count = BMO_CountSlotMap(em->bm, &bmop, "targetmapout");
+
+ if (!EDBM_CallOpf(em, op, "weldverts targetmap=%s", &bmop, "targetmapout")) {
+ BMO_Finish_Op(em->bm, &bmop);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+
+ /*we need a better way of reporting this, since this doesn't work
+ with the last operator panel correctly.
+ if(count)
+ {
+ sprintf(msg, "Removed %d vertices", count);
+ BKE_report(op->reports, RPT_INFO, msg);
+ }
+ */
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_remove_doubles(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Remove Doubles";
+ ot->idname= "MESH_OT_remove_doubles";
+
+ /* api callbacks */
+ ot->exec= removedoublesflag_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_float(ot->srna, "mergedist", 0.0001f, 0.000001f, 50.0f,
+ "Merge Distance",
+ "Minimum distance between elements to merge.", 0.00001, 10.0);
+}
+
+/************************ Vertex Path Operator *************************/
+
+typedef struct PathNode {
+ int u;
+ int visited;
+ ListBase edges;
+} PathNode;
+
+typedef struct PathEdge {
+ struct PathEdge *next, *prev;
+ int v;
+ float w;
+} PathEdge;
+
+
+
+int select_vertex_path_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+ BMEditSelection *sv, *ev;
+
+ /* get the type from RNA */
+ int type = RNA_enum_get(op->ptr, "type");
+
+ sv = em->bm->selected.last;
+ if( sv != NULL )
+ ev = sv->prev;
+ else return OPERATOR_CANCELLED;
+ if( ev == NULL )
+ return OPERATOR_CANCELLED;
+
+ if( sv->type != BM_VERT || ev->type != BM_VERT )
+ return OPERATOR_CANCELLED;
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "vertexshortestpath startv=%e endv=%e type=%d", sv->data, ev->data, type);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* DO NOT clear the existing selection */
+ /* EDBM_clear_flag_all(em, BM_SELECT); */
+
+ /* select the output */
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_ALL);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+ EDBM_selectmode_flush(em);
+
+ /* dependencies graph and notification stuff */
+/* DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_GEOM_SELECT, ob);
+*/
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+
+
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ EditVert *eve, *s, *t;
+ EditEdge *eed;
+ EditSelection *ese;
+ PathEdge *newpe, *currpe;
+ PathNode *currpn;
+ PathNode *Q;
+ int v, *previous, pathvert, pnindex; /*pnindex redundant?*/
+ int unbalanced, totnodes;
+ short physical;
+ float *cost;
+ Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/
+
+ s = t = NULL;
+
+ ese = ((EditSelection*)em->selected.last);
+ if(ese && ese->type == EDITVERT && ese->prev && ese->prev->type == EDITVERT){
+ physical= pupmenu("Distance Method? %t|Edge Length%x1|Topological%x0");
+
+ t = (EditVert*)ese->data;
+ s = (EditVert*)ese->prev->data;
+
+ /*need to find out if t is actually reachable by s....*/
+ for(eve=em->verts.first; eve; eve=eve->next){
+ eve->f1 = 0;
+ }
+
+ s->f1 = 1;
+
+ unbalanced = 1;
+ totnodes = 1;
+ while(unbalanced){
+ unbalanced = 0;
+ for(eed=em->edges.first; eed; eed=eed->next){
+ if(!eed->h){
+ if(eed->v1->f1 && !eed->v2->f1){
+ eed->v2->f1 = 1;
+ totnodes++;
+ unbalanced = 1;
+ }
+ else if(eed->v2->f1 && !eed->v1->f1){
+ eed->v1->f1 = 1;
+ totnodes++;
+ unbalanced = 1;
+ }
+ }
+ }
+ }
+
+ if(s->f1 && t->f1){ /* t can be reached by s */
+ Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes");
+ totnodes = 0;
+ for(eve=em->verts.first; eve; eve=eve->next){
+ if(eve->f1){
+ Q[totnodes].u = totnodes;
+ Q[totnodes].edges.first = 0;
+ Q[totnodes].edges.last = 0;
+ Q[totnodes].visited = 0;
+ eve->tmp.p = &(Q[totnodes]);
+ totnodes++;
+ }
+ else eve->tmp.p = NULL;
+ }
+
+ for(eed=em->edges.first; eed; eed=eed->next){
+ if(!eed->h){
+ if(eed->v1->f1){
+ currpn = ((PathNode*)eed->v1->tmp.p);
+
+ newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
+ newpe->v = ((PathNode*)eed->v2->tmp.p)->u;
+ if(physical){
+ newpe->w = len_v3v3(eed->v1->co, eed->v2->co);
+ }
+ else newpe->w = 1;
+ newpe->next = 0;
+ newpe->prev = 0;
+ BLI_addtail(&(currpn->edges), newpe);
+ }
+ if(eed->v2->f1){
+ currpn = ((PathNode*)eed->v2->tmp.p);
+ newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
+ newpe->v = ((PathNode*)eed->v1->tmp.p)->u;
+ if(physical){
+ newpe->w = len_v3v3(eed->v1->co, eed->v2->co);
+ }
+ else newpe->w = 1;
+ newpe->next = 0;
+ newpe->prev = 0;
+ BLI_addtail(&(currpn->edges), newpe);
+ }
+ }
+ }
+
+ heap = BLI_heap_new();
+ cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs");
+ previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices");
+
+ for(v=0; v < totnodes; v++){
+ cost[v] = 1000000;
+ previous[v] = -1; /*array of indices*/
+ }
+
+ pnindex = ((PathNode*)s->tmp.p)->u;
+ cost[pnindex] = 0;
+ BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(pnindex));
+
+ while( !BLI_heap_empty(heap) ){
+
+ pnindex = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
+ currpn = &(Q[pnindex]);
+
+ if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/
+ break;
+
+ for(currpe=currpn->edges.first; currpe; currpe=currpe->next){
+ if(!Q[currpe->v].visited){
+ if( cost[currpe->v] > (cost[currpn->u ] + currpe->w) ){
+ cost[currpe->v] = cost[currpn->u] + currpe->w;
+ previous[currpe->v] = currpn->u;
+ Q[currpe->v].visited = 1;
+ BLI_heap_insert(heap, cost[currpe->v], SET_INT_IN_POINTER(currpe->v));
+ }
+ }
+ }
+ }
+
+ pathvert = ((PathNode*)t->tmp.p)->u;
+ while(pathvert != -1){
+ for(eve=em->verts.first; eve; eve=eve->next){
+ if(eve->f1){
+ if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT;
+ }
+ }
+ pathvert = previous[pathvert];
+ }
+
+ for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges));
+ MEM_freeN(Q);
+ MEM_freeN(cost);
+ MEM_freeN(previous);
+ BLI_heap_free(heap, NULL);
+ EM_select_flush(em);
+ }
+ }
+ else {
+ BKE_mesh_end_editmesh(obedit->data, em);
+ BKE_report(op->reports, RPT_ERROR, "Path Selection requires that exactly two vertices be selected");
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+ BKE_mesh_end_editmesh(obedit->data, em);
+#endif
+}
+
+void MESH_OT_select_vertex_path(wmOperatorType *ot)
+{
+ static const EnumPropertyItem type_items[] = {
+ {VPATH_SELECT_EDGE_LENGTH, "EDGE_LENGTH", 0, "Edge Length", NULL},
+ {VPATH_SELECT_TOPOLOGICAL, "TOPOLOGICAL", 0, "Topological", NULL},
+ {0, NULL, 0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name= "Select Vertex Path";
+ ot->idname= "MESH_OT_select_vertex_path";
+
+ /* api callbacks */
+ ot->exec= select_vertex_path_exec;
+ ot->invoke= WM_menu_invoke;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "type", type_items, VPATH_SELECT_EDGE_LENGTH, "Type", "Method to compute distance.");
+}
+/********************** Rip Operator *************************/
+
+#if 0
+/* helper for below */
+static void mesh_rip_setface(EditMesh *em, EditFace *sefa)
+{
+ /* put new vertices & edges in best face */
+ if(sefa->v1->tmp.v) sefa->v1= sefa->v1->tmp.v;
+ if(sefa->v2->tmp.v) sefa->v2= sefa->v2->tmp.v;
+ if(sefa->v3->tmp.v) sefa->v3= sefa->v3->tmp.v;
+ if(sefa->v4 && sefa->v4->tmp.v) sefa->v4= sefa->v4->tmp.v;
+
+ sefa->e1= addedgelist(em, sefa->v1, sefa->v2, sefa->e1);
+ sefa->e2= addedgelist(em, sefa->v2, sefa->v3, sefa->e2);
+ if(sefa->v4) {
+ sefa->e3= addedgelist(em, sefa->v3, sefa->v4, sefa->e3);
+ sefa->e4= addedgelist(em, sefa->v4, sefa->v1, sefa->e4);
+ }
+ else
+ sefa->e3= addedgelist(em, sefa->v3, sefa->v1, sefa->e3);
+
+}
+#endif
+
+/* helper to find edge for edge_rip */
+static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *co2, short *mval)
+{
+ float vec1[3], vec2[3], mvalf[2];
+
+ view3d_project_float(ar, co1, vec1, mat);
+ view3d_project_float(ar, co2, vec2, mat);
+ mvalf[0]= (float)mval[0];
+ mvalf[1]= (float)mval[1];
+
+ return dist_to_line_segment_v2(mvalf, vec1, vec2);
+}
+
+/* based on mouse cursor position, it defines how is being ripped */
+static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ ARegion *ar= CTX_wm_region(C);
+ RegionView3D *rv3d= CTX_wm_region_view3d(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMOperator bmop;
+ BMBVHTree *bvhtree;
+ BMOIter siter;
+ BMIter iter, eiter, liter;
+ BMLoop *l;
+ BMEdge *e, *e2, *closest = NULL;
+ BMVert *v;
+ int side = 0, i, singlesel = 0;
+ float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1], 0.0f};
+ float dist = FLT_MAX, d;
+
+ view3d_get_object_project_mat(rv3d, obedit, projectMat);
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(e, BM_SELECT))
+ BMINDEX_SET(e, 1);
+ else BMINDEX_SET(e, 0);
+ }
+
+ /*handle case of one vert selected. we identify
+ the closest edge around that vert to the mouse cursor,
+ then rip the two adjacent edges in the vert fan.*/
+ if (em->bm->totvertsel == 1 && em->bm->totedgesel == 0 && em->bm->totfacesel == 0) {
+ singlesel = 1;
+
+ /*find selected vert*/
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(v, BM_SELECT))
+ break;
+ }
+
+ /*this should be impossible, but sanity checks are a good thing*/
+ if (!v)
+ return OPERATOR_CANCELLED;
+
+ /*find closest edge to mouse cursor*/
+ e2 = NULL;
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_VERT, v) {
+ d = mesh_rip_edgedist(ar, projectMat, e->v1->co, e->v2->co, event->mval);
+ if (d < dist) {
+ dist = d;
+ e2 = e;
+ }
+ }
+
+ if (!e2)
+ return OPERATOR_CANCELLED;
+
+ /*rip two adjacent edges*/
+ if (BM_Edge_FaceCount(e2) == 1) {
+ l = e2->l;
+ e = BM_OtherFaceLoop(e2, l->f, v)->e;
+
+ BMINDEX_SET(e, 1);
+ BM_SetHFlag(e, BM_SELECT);
+ } else if (BM_Edge_FaceCount(e2) == 2) {
+ l = e2->l;
+ e = BM_OtherFaceLoop(e2, l->f, v)->e;
+ BMINDEX_SET(e, 1);
+ BM_SetHFlag(e, BM_SELECT);
+
+ l = e2->l->radial_next;
+ e = BM_OtherFaceLoop(e2, l->f, v)->e;
+ BMINDEX_SET(e, 1);
+ BM_SetHFlag(e, BM_SELECT);
+ }
+
+ dist = FLT_MAX;
+ } else {
+ /*expand edge selection*/
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ e2 = NULL;
+ i = 0;
+ BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) {
+ if (BMINDEX_GET(e)) {
+ e2 = e;
+ i++;
+ }
+ }
+
+ if (i == 1 && e2->l) {
+ l = BM_OtherFaceLoop(e2, e2->l->f, v);
+ l = (BMLoop*)l->radial_next;
+ l = BM_OtherFaceLoop(l->e, l->f, v);
+
+ if (l)
+ BM_Select(em->bm, l->e, 1);
+ }
+ }
+ }
+
+ if (!EDBM_InitOpf(em, &bmop, op, "edgesplit edges=%he", BM_SELECT)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /*build bvh tree for edge visibility tests*/
+ bvhtree = BMBVH_NewBVH(em);
+
+ for (i=0; i<2; i++) {
+ BMO_ITER(e, &siter, em->bm, &bmop, i ? "edgeout2":"edgeout1", BM_EDGE) {
+ float cent[3] = {0, 0, 0}, mid[4], vec[3];
+
+ if (!BMBVH_EdgeVisible(bvhtree, e, rv3d, obedit) || !e->l)
+ continue;
+
+ /*method for calculating distance:
+
+ for each edge: calculate face center, then made a vector
+ from edge midpoint to face center. offset edge midpoint
+ by a small amount along this vector.*/
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, e->l->f) {
+ add_v3_v3v3(cent, cent, l->v->co);
+ }
+ mul_v3_fl(cent, 1.0f/(float)e->l->f->len);
+
+ add_v3_v3v3(mid, e->v1->co, e->v2->co);
+ mul_v3_fl(mid, 0.5f);
+ sub_v3_v3v3(vec, cent, mid);
+ normalize_v3(vec);
+ mul_v3_fl(vec, 0.01f);
+ add_v3_v3v3(mid, mid, vec);
+
+ /*yay we have our comparison point, now project it*/
+ view3d_project_float(ar, mid, mid, projectMat);
+
+ vec[0] = fmval[0] - mid[0];
+ vec[1] = fmval[1] - mid[1];
+ d = vec[0]*vec[0] + vec[1]*vec[1];
+
+ if (d < dist) {
+ side = i;
+ closest = e;
+ dist = d;
+ }
+ }
+ }
+
+ EDBM_clear_flag_all(em, BM_SELECT);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, side?"edgeout2":"edgeout1", BM_SELECT, BM_EDGE);
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(e, BM_SELECT))
+ BMINDEX_SET(e, 1);
+ else BMINDEX_SET(e, 0);
+ }
+
+ /*constrict edge selection again*/
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ e2 = NULL;
+ i = 0;
+ BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) {
+ if (BMINDEX_GET(e)) {
+ e2 = e;
+ i++;
+ }
+ }
+
+ if (i == 1) {
+ if (singlesel)
+ BM_Select(em->bm, v, 0);
+ else
+ BM_Select(em->bm, e2, 0);
+ }
+ }
+
+ EDBM_selectmode_flush(em);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1)) {
+ BMBVH_FreeBVH(bvhtree);
+ return OPERATOR_CANCELLED;
+ }
+
+ BMBVH_FreeBVH(bvhtree);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+#if 0 //BMESH_TODO
+ ARegion *ar= CTX_wm_region(C);
+ RegionView3D *rv3d= ar->regiondata;
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ EditVert *eve, *nextve;
+ EditEdge *eed, *seed= NULL;
+ EditFace *efa, *sefa= NULL;
+ float projectMat[4][4], vec[3], dist, mindist;
+ short doit= 1, *mval= event->mval;
+
+ /* select flush... vertices are important */
+ EM_selectmode_set(em);
+
+ view3d_get_object_project_mat(rv3d, obedit, projectMat);
+
+ /* find best face, exclude triangles and break on face select or faces with 2 edges select */
+ mindist= 1000000.0f;
+ for(efa= em->faces.first; efa; efa=efa->next) {
+ if( efa->f & 1)
+ break;
+ if(efa->v4 && faceselectedOR(efa, SELECT) ) {
+ int totsel=0;
+
+ if(efa->e1->f & SELECT) totsel++;
+ if(efa->e2->f & SELECT) totsel++;
+ if(efa->e3->f & SELECT) totsel++;
+ if(efa->e4->f & SELECT) totsel++;
+
+ if(totsel>1)
+ break;
+ view3d_project_float(ar, efa->cent, vec, projectMat);
+ dist= sqrt( (vec[0]-mval[0])*(vec[0]-mval[0]) + (vec[1]-mval[1])*(vec[1]-mval[1]) );
+ if(dist<mindist) {
+ mindist= dist;
+ sefa= efa;
+ }
+ }
+ }
+
+ if(efa) {
+ BKE_report(op->reports, RPT_ERROR, "Can't perform ripping with faces selected this way");
+ BKE_mesh_end_editmesh(obedit->data, em);
+ return OPERATOR_CANCELLED;
+ }
+ if(sefa==NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No proper selection or faces included");
+ BKE_mesh_end_editmesh(obedit->data, em);
+ return OPERATOR_CANCELLED;
+ }
+
+
+ /* duplicate vertices, new vertices get selected */
+ for(eve = em->verts.last; eve; eve= eve->prev) {
+ eve->tmp.v = NULL;
+ if(eve->f & SELECT) {
+ eve->tmp.v = addvertlist(em, eve->co, eve);
+ eve->f &= ~SELECT;
+ eve->tmp.v->f |= SELECT;
+ }
+ }
+
+ /* find the best candidate edge */
+ /* or one of sefa edges is selected... */
+ if(sefa->e1->f & SELECT) seed= sefa->e2;
+ if(sefa->e2->f & SELECT) seed= sefa->e1;
+ if(sefa->e3->f & SELECT) seed= sefa->e2;
+ if(sefa->e4 && sefa->e4->f & SELECT) seed= sefa->e3;
+
+ /* or we do the distance trick */
+ if(seed==NULL) {
+ mindist= 1000000.0f;
+ if(sefa->e1->v1->tmp.v || sefa->e1->v2->tmp.v) {
+ dist = mesh_rip_edgedist(ar, projectMat,
+ sefa->e1->v1->co,
+ sefa->e1->v2->co, mval);
+ if(dist<mindist) {
+ seed= sefa->e1;
+ mindist= dist;
+ }
+ }
+ if(sefa->e2->v1->tmp.v || sefa->e2->v2->tmp.v) {
+ dist = mesh_rip_edgedist(ar, projectMat,
+ sefa->e2->v1->co,
+ sefa->e2->v2->co, mval);
+ if(dist<mindist) {
+ seed= sefa->e2;
+ mindist= dist;
+ }
+ }
+ if(sefa->e3->v1->tmp.v || sefa->e3->v2->tmp.v) {
+ dist= mesh_rip_edgedist(ar, projectMat,
+ sefa->e3->v1->co,
+ sefa->e3->v2->co, mval);
+ if(dist<mindist) {
+ seed= sefa->e3;
+ mindist= dist;
+ }
+ }
+ if(sefa->e4 && (sefa->e4->v1->tmp.v || sefa->e4->v2->tmp.v)) {
+ dist= mesh_rip_edgedist(ar, projectMat,
+ sefa->e4->v1->co,
+ sefa->e4->v2->co, mval);
+ if(dist<mindist) {
+ seed= sefa->e4;
+ mindist= dist;
+ }
+ }
+ }
+
+ if(seed==NULL) { // never happens?
+ BKE_report(op->reports, RPT_ERROR, "No proper edge found to start");
+ BKE_mesh_end_editmesh(obedit->data, em);
+ return OPERATOR_CANCELLED;
+ }
+
+ faceloop_select(em, seed, 2); // tmp abuse for finding all edges that need duplicated, returns OK faces with f1
+
+ /* duplicate edges in the loop, with at least 1 vertex selected, needed for selection flip */
+ for(eed = em->edges.last; eed; eed= eed->prev) {
+ eed->tmp.v = NULL;
+ if((eed->v1->tmp.v) || (eed->v2->tmp.v)) {
+ EditEdge *newed;
+
+ newed= addedgelist(em, eed->v1->tmp.v?eed->v1->tmp.v:eed->v1,
+ eed->v2->tmp.v?eed->v2->tmp.v:eed->v2, eed);
+ if(eed->f & SELECT) {
+ EM_select_edge(eed, 0);
+ EM_remove_selection(em, eed, EDITEDGE);
+ EM_select_edge(newed, 1);
+ }
+ eed->tmp.v = (EditVert *)newed;
+ }
+ }
+
+ /* first clear edges to help finding neighbours */
+ for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
+
+ /* put new vertices & edges && flag in best face */
+ mesh_rip_setface(em, sefa);
+
+ /* starting with neighbours of best face, we loop over the seam */
+ sefa->f1= 2;
+ doit= 1;
+ while(doit) {
+ doit= 0;
+
+ for(efa= em->faces.first; efa; efa=efa->next) {
+ /* new vert in face */
+ if (efa->v1->tmp.v || efa->v2->tmp.v ||
+ efa->v3->tmp.v || (efa->v4 && efa->v4->tmp.v)) {
+ /* face is tagged with loop */
+ if(efa->f1==1) {
+ mesh_rip_setface(em, efa);
+ efa->f1= 2;
+ doit= 1;
+ }
+ }
+ }
+ }
+
+ /* remove loose edges, that were part of a ripped face */
+ for(eve = em->verts.first; eve; eve= eve->next) eve->f1= 0;
+ for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
+ for(efa= em->faces.first; efa; efa=efa->next) {
+ efa->e1->f1= 1;
+ efa->e2->f1= 1;
+ efa->e3->f1= 1;
+ if(efa->e4) efa->e4->f1= 1;
+ }
+
+ for(eed = em->edges.last; eed; eed= seed) {
+ seed= eed->prev;
+ if(eed->f1==0) {
+ if(eed->v1->tmp.v || eed->v2->tmp.v ||
+ (eed->v1->f & SELECT) || (eed->v2->f & SELECT)) {
+ remedge(em, eed);
+ free_editedge(em, eed);
+ eed= NULL;
+ }
+ }
+ if(eed) {
+ eed->v1->f1= 1;
+ eed->v2->f1= 1;
+ }
+ }
+
+ /* and remove loose selected vertices, that got duplicated accidentally */
+ for(eve = em->verts.first; eve; eve= nextve) {
+ nextve= eve->next;
+ if(eve->f1==0 && (eve->tmp.v || (eve->f & SELECT))) {
+ BLI_remlink(&em->verts,eve);
+ free_editvert(em, eve);
+ }
+ }
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+
+// RNA_enum_set(op->ptr, "proportional", 0);
+// RNA_boolean_set(op->ptr, "mirror", 0);
+// WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
+#endif
+}
+
+void MESH_OT_rip(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Rip";
+ ot->idname= "MESH_OT_rip";
+
+ /* api callbacks */
+ ot->invoke= mesh_rip_invoke;
+ ot->poll= EM_view3d_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* to give to transform */
+ Transform_Properties(ot, P_PROPORTIONAL);
+ RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
+}
+
+/************************ Shape Operators *************************/
+
+/*BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
+static void shape_propagate(Object *obedit, BMEditMesh *em, wmOperator *op)
+{
+ BMIter iter;
+ BMVert *eve = NULL;
+ float *co;
+ int i, totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
+
+ if (!CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
+ BKE_report(op->reports, RPT_ERROR, "Mesh does not have shape keys");
+ return;
+ }
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_TestHFlag(eve, BM_SELECT) || BM_TestHFlag(eve, BM_HIDDEN))
+ continue;
+
+ for (i=0; i<totshape; i++) {
+ co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i);
+ VECCOPY(co, eve->co);
+ }
+ }
+
+#if 0
+ //TAG Mesh Objects that share this data
+ for(base = scene->base.first; base; base = base->next){
+ if(base->object && base->object->data == me){
+ base->object->recalc = OB_RECALC_DATA;
+ }
+ }
+#endif
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+}
+
+
+static int shape_propagate_to_all_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Mesh *me= obedit->data;
+ BMEditMesh *em= me->edit_btmesh;
+
+ shape_propagate(obedit, em, op);
+
+ DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
+
+ return OPERATOR_FINISHED;
+}
+
+
+void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Shape Propagate";
+ ot->description= "Apply selected vertex locations to all other shape keys.";
+ ot->idname= "MESH_OT_shape_propagate_to_all";
+
+ /* api callbacks */
+ ot->exec= shape_propagate_to_all_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/*BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
+static int blend_from_shape_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Mesh *me= obedit->data;
+ BMEditMesh *em= me->edit_btmesh;
+ BMVert *eve;
+ BMIter iter;
+ float co[3], *sco;
+ float blend= RNA_float_get(op->ptr, "blend");
+ int shape= RNA_enum_get(op->ptr, "shape");
+ int add= RNA_int_get(op->ptr, "add");
+ int totshape;
+
+ /*sanity check*/
+ totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
+ if (totshape == 0 || shape < 0 || shape >= totshape)
+ return OPERATOR_CANCELLED;
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_TestHFlag(eve, BM_SELECT) || BM_TestHFlag(eve, BM_HIDDEN))
+ continue;
+
+ sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
+ VECCOPY(co, sco);
+
+
+ if(add) {
+ mul_v3_fl(co, blend);
+ add_v3_v3v3(eve->co, eve->co, co);
+ }
+ else
+ interp_v3_v3v3(eve->co, eve->co, co, blend);
+
+ VECCOPY(sco, co);
+ }
+
+ DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
+
+ return OPERATOR_FINISHED;
+}
+
+static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *ptr, int *free)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Mesh *me= (obedit) ? obedit->data : NULL;
+ BMEditMesh *em = me->edit_btmesh;
+ EnumPropertyItem tmp= {0, "", 0, "", ""}, *item= NULL;
+ int totitem= 0, a;
+
+ if(obedit && obedit->type == OB_MESH && CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
+ for (a=0; a<em->bm->vdata.totlayer; a++) {
+ if (em->bm->vdata.layers[a].type != CD_SHAPEKEY)
+ continue;
+
+ tmp.value= totitem;
+ tmp.identifier= em->bm->vdata.layers[a].name;
+ tmp.name= em->bm->vdata.layers[a].name;
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+ totitem++;
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *free= 1;
+
+ return item;
+}
+
+void MESH_OT_blend_from_shape(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+ static EnumPropertyItem shape_items[]= {{0, NULL, 0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name= "Blend From Shape";
+ ot->description= "Blend in shape from a shape key.";
+ ot->idname= "MESH_OT_blend_from_shape";
+
+ /* api callbacks */
+ ot->exec= blend_from_shape_exec;
+ ot->invoke= WM_operator_props_popup;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ prop= RNA_def_enum(ot->srna, "shape", shape_items, 0, "Shape", "Shape key to use for blending.");
+ RNA_def_enum_funcs(prop, shape_itemf);
+ RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor.", -2.0f, 2.0f);
+ RNA_def_boolean(ot->srna, "add", 1, "Add", "Add rather then blend between shapes.");
+}
+
+/* TODO - some way to select on an arbitrary axis */
+static int select_axis_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMEditSelection *ese = em->bm->selected.last;
+ int axis= RNA_int_get(op->ptr, "axis");
+ int mode= RNA_enum_get(op->ptr, "mode"); /* -1==aligned, 0==neg, 1==pos*/
+
+ if(ese==NULL)
+ return OPERATOR_CANCELLED;
+
+ if(ese->type==BM_VERT) {
+ BMVert *ev, *act_vert= (BMVert*)ese->data;
+ BMIter iter;
+ float value= act_vert->co[axis];
+ float limit= CTX_data_tool_settings(C)->doublimit; // XXX
+
+ if(mode==0)
+ value -= limit;
+ else if (mode==1)
+ value += limit;
+
+ BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if(!BM_TestHFlag(ev, BM_HIDDEN)) {
+ switch(mode) {
+ case -1: /* aligned */
+ if(fabs(ev->co[axis] - value) < limit)
+ BM_Select(em->bm, ev, 1);
+ break;
+ case 0: /* neg */
+ if(ev->co[axis] > value)
+ BM_Select(em->bm, ev, 1);
+ break;
+ case 1: /* pos */
+ if(ev->co[axis] < value)
+ BM_Select(em->bm, ev, 1);
+ break;
+ }
+ }
+ }
+ }
+
+ EDBM_selectmode_flush(em);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_axis(wmOperatorType *ot)
+{
+ static EnumPropertyItem axis_mode_items[] = {
+ {0, "POSITIVE", 0, "Positive Axis", ""},
+ {1, "NEGATIVE", 0, "Negative Axis", ""},
+ {-1, "ALIGNED", 0, "Aligned Axis", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name= "Select Axis";
+ ot->description= "Select all data in the mesh on a single axis.";
+ ot->idname= "MESH_OT_select_axis";
+
+ /* api callbacks */
+ ot->exec= select_axis_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting");
+ RNA_def_int(ot->srna, "axis", 0, 0, 2, "Axis", "Select the axis to compare each vertex on", 0, 2);
+}
+
+static int solidify_exec(bContext *C, wmOperator *op)
+{
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+ float nor[3] = {0,0,1};
+
+ float thickness= RNA_float_get(op->ptr, "thickness");
+
+ extrudeflag(obedit, em, SELECT, nor, 1);
+ EM_make_hq_normals(em);
+ EM_solidify(em, thickness);
+
+
+ /* update vertex normals too */
+ recalc_editnormals(em);
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+#endif
+ return OPERATOR_CANCELLED;
+}
+
+
+void MESH_OT_solidify(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+ /* identifiers */
+ ot->name= "Solidify";
+ ot->description= "Create a solid skin by extruding, compensating for sharp angles.";
+ ot->idname= "MESH_OT_solidify";
+
+ /* api callbacks */
+ ot->exec= solidify_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ prop= RNA_def_float(ot->srna, "thickness", 0.01f, -FLT_MAX, FLT_MAX, "thickness", "", -10.0f, 10.0f);
+ RNA_def_property_ui_range(prop, -10, 10, 0.1, 4);
+}
+
+#define TRAIL_POLYLINE 1 /* For future use, They don't do anything yet */
+#define TRAIL_FREEHAND 2
+#define TRAIL_MIXED 3 /* (1|2) */
+#define TRAIL_AUTO 4
+#define TRAIL_MIDPOINTS 8
+
+typedef struct CutCurve {
+ float x;
+ float y;
+} CutCurve;
+
+/* ******************************************************************** */
+/* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail
+ drawn by user.
+
+ Currently mapped to KKey when in MeshEdit mode.
+ Usage:
+ Hit Shift K, Select Centers or Exact
+ Hold LMB down to draw path, hit RETKEY.
+ ESC cancels as expected.
+
+ Contributed by Robert Wenzlaff (Det. Thorn).
+
+ 2.5 revamp:
+ - non modal (no menu before cutting)
+ - exit on mouse release
+ - polygon/segment drawing can become handled by WM cb later
+
+ bmesh port version
+*/
+
+#define KNIFE_EXACT 1
+#define KNIFE_MIDPOINT 2
+#define KNIFE_MULTICUT 3
+
+static EnumPropertyItem knife_items[]= {
+ {KNIFE_EXACT, "EXACT", 0, "Exact", ""},
+ {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""},
+ {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+/* seg_intersect() Determines if and where a mouse trail intersects an EditEdge */
+
+static float bm_seg_intersect(BMEdge *e, CutCurve *c, int len, char mode,
+ struct GHash *gh, int *isected)
+{
+#define MAXSLOPE 100000
+ float x11, y11, x12=0, y12=0, x2max, x2min, y2max;
+ float y2min, dist, lastdist=0, xdiff2, xdiff1;
+ float m1, b1, m2, b2, x21, x22, y21, y22, xi;
+ float yi, x1min, x1max, y1max, y1min, perc=0;
+ float *scr;
+ float threshold = 0.0;
+ int i;
+
+ //threshold = 0.000001; /*tolerance for vertex intersection*/
+ // XXX threshold = scene->toolsettings->select_thresh / 100;
+
+ /* Get screen coords of verts */
+ scr = BLI_ghash_lookup(gh, e->v1);
+ x21=scr[0];
+ y21=scr[1];
+
+ scr = BLI_ghash_lookup(gh, e->v2);
+ x22=scr[0];
+ y22=scr[1];
+
+ xdiff2=(x22-x21);
+ if (xdiff2) {
+ m2=(y22-y21)/xdiff2;
+ b2= ((x22*y21)-(x21*y22))/xdiff2;
+ }
+ else {
+ m2=MAXSLOPE; /* Verticle slope */
+ b2=x22;
+ }
+
+ *isected = 0;
+
+ /*check for *exact* vertex intersection first*/
+ if(mode!=KNIFE_MULTICUT){
+ for (i=0; i<len; i++){
+ if (i>0){
+ x11=x12;
+ y11=y12;
+ }
+ else {
+ x11=c[i].x;
+ y11=c[i].y;
+ }
+ x12=c[i].x;
+ y12=c[i].y;
+
+ /*test e->v1*/
+ if((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)){
+ perc = 0;
+ *isected = 1;
+ return(perc);
+ }
+ /*test e->v2*/
+ else if((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)){
+ perc = 0;
+ *isected = 2;
+ return(perc);
+ }
+ }
+ }
+
+ /*now check for edge interesect (may produce vertex intersection as well)*/
+ for (i=0; i<len; i++){
+ if (i>0){
+ x11=x12;
+ y11=y12;
+ }
+ else {
+ x11=c[i].x;
+ y11=c[i].y;
+ }
+ x12=c[i].x;
+ y12=c[i].y;
+
+ /* Perp. Distance from point to line */
+ if (m2!=MAXSLOPE) dist=(y12-m2*x12-b2);/* /sqrt(m2*m2+1); Only looking for */
+ /* change in sign. Skip extra math */
+ else dist=x22-x12;
+
+ if (i==0) lastdist=dist;
+
+ /* if dist changes sign, and intersect point in edge's Bound Box*/
+ if ((lastdist*dist)<=0){
+ xdiff1=(x12-x11); /* Equation of line between last 2 points */
+ if (xdiff1){
+ m1=(y12-y11)/xdiff1;
+ b1= ((x12*y11)-(x11*y12))/xdiff1;
+ }
+ else{
+ m1=MAXSLOPE;
+ b1=x12;
+ }
+ x2max=MAX2(x21,x22)+0.001; /* prevent missed edges */
+ x2min=MIN2(x21,x22)-0.001; /* due to round off error */
+ y2max=MAX2(y21,y22)+0.001;
+ y2min=MIN2(y21,y22)-0.001;
+
+ /* Found an intersect, calc intersect point */
+ if (m1==m2){ /* co-incident lines */
+ /* cut at 50% of overlap area*/
+ x1max=MAX2(x11, x12);
+ x1min=MIN2(x11, x12);
+ xi= (MIN2(x2max,x1max)+MAX2(x2min,x1min))/2.0;
+
+ y1max=MAX2(y11, y12);
+ y1min=MIN2(y11, y12);
+ yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0;
+ }
+ else if (m2==MAXSLOPE){
+ xi=x22;
+ yi=m1*x22+b1;
+ }
+ else if (m1==MAXSLOPE){
+ xi=x12;
+ yi=m2*x12+b2;
+ }
+ else {
+ xi=(b1-b2)/(m2-m1);
+ yi=(b1*m2-m1*b2)/(m2-m1);
+ }
+
+ /* Intersect inside bounding box of edge?*/
+ if ((xi>=x2min)&&(xi<=x2max)&&(yi<=y2max)&&(yi>=y2min)){
+ /*test for vertex intersect that may be 'close enough'*/
+ if(mode!=KNIFE_MULTICUT){
+ if(xi <= (x21 + threshold) && xi >= (x21 - threshold)){
+ if(yi <= (y21 + threshold) && yi >= (y21 - threshold)){
+ *isected = 1;
+ perc = 0;
+ break;
+ }
+ }
+ if(xi <= (x22 + threshold) && xi >= (x22 - threshold)){
+ if(yi <= (y22 + threshold) && yi >= (y22 - threshold)){
+ *isected = 2;
+ perc = 0;
+ break;
+ }
+ }
+ }
+ if ((m2<=1.0)&&(m2>=-1.0)) perc = (xi-x21)/(x22-x21);
+ else perc=(yi-y21)/(y22-y21); /*lower slope more accurate*/
+ //isect=32768.0*(perc+0.0000153); /* Percentage in 1/32768ths */
+
+ break;
+ }
+ }
+ lastdist=dist;
+ }
+ return(perc);
+}
+
+#define MAX_CUTS 2048
+
+static int knife_cut_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+ BMesh *bm = em->bm;
+ ARegion *ar= CTX_wm_region(C);
+ BMVert *bv;
+ BMIter iter;
+ BMEdge *be;
+ BMOperator bmop;
+ CutCurve curve[MAX_CUTS];
+ struct GHash *gh;
+ float isect=0.0;
+ float *scr, co[4];
+ int len=0, isected, i;
+ short numcuts=1, mode= RNA_int_get(op->ptr, "type");
+
+ /* edit-object needed for matrix, and ar->regiondata for projections to work */
+ if (ELEM3(NULL, obedit, ar, ar->regiondata))
+ return OPERATOR_CANCELLED;
+
+ if (bm->totvertsel < 2) {
+ //error("No edges are selected to operate on");
+ return OPERATOR_CANCELLED;;
+ }
+
+ /* get the cut curve */
+ RNA_BEGIN(op->ptr, itemptr, "path") {
+
+ RNA_float_get_array(&itemptr, "loc", (float *)&curve[len]);
+ len++;
+ if(len>= MAX_CUTS) break;
+ }
+ RNA_END;
+
+ if(len<2) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /*the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer*/
+ gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife cut exec");
+ for(bv=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);bv;bv=BMIter_Step(&iter)){
+ scr = MEM_mallocN(sizeof(float)*2, "Vertex Screen Coordinates");
+ VECCOPY(co, bv->co);
+ co[3]= 1.0;
+ mul_m4_v4(obedit->obmat, co);
+ project_float(ar, co, scr);
+ BLI_ghash_insert(gh, bv, scr);
+ }
+
+ BMO_Init_Op(&bmop, "esubd");
+
+ i = 0;
+ /*store percentage of edge cut for KNIFE_EXACT here.*/
+ for (be=BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); be; be=BMIter_Step(&iter)) {
+ if( BM_Selected(bm, be) ) {
+ isect= bm_seg_intersect(be, curve, len, mode, gh, &isected);
+
+ if (isect != 0.0f) {
+ if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) {
+ BMO_Insert_MapFloat(bm, &bmop,
+ "edgepercents",
+ be, isect);
+
+ }
+ BMO_SetFlag(bm, be, 1);
+ } else BMO_ClearFlag(bm, be, 1);
+ } else BMO_ClearFlag(bm, be, 1);
+ }
+
+ BMO_Flag_To_Slot(bm, &bmop, "edges", 1, BM_EDGE);
+
+ if (mode == KNIFE_MIDPOINT) numcuts = 1;
+ BMO_Set_Int(&bmop, "numcuts", numcuts);
+
+ BMO_Set_Int(&bmop, "flag", B_KNIFE);
+ BMO_Set_Int(&bmop, "quadcornertype", SUBD_STRAIGHT_CUT);
+ BMO_Set_Int(&bmop, "singleedge", 0);
+ BMO_Set_Int(&bmop, "gridfill", 0);
+
+ BMO_Set_Float(&bmop, "radius", 0);
+
+ BMO_Exec_Op(bm, &bmop);
+ BMO_Finish_Op(bm, &bmop);
+
+ BLI_ghash_free(gh, NULL, (GHashValFreeFP)WMEM_freeN);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_knife_cut(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name= "Knife Cut";
+ ot->description= "Cut selected edges and faces into parts.";
+ ot->idname= "MESH_OT_knife_cut";
+
+ ot->invoke= WM_gesture_lines_invoke;
+ ot->modal= WM_gesture_lines_modal;
+ ot->exec= knife_cut_exec;
+
+ ot->poll= EM_view3d_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", "");
+ prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
+
+ /* internal */
+ RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
+}
+
+static int mesh_separate_selected(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop)
+{
+ Base *basenew;
+ BMIter iter;
+ BMVert *v;
+ BMEdge *e;
+ Object *obedit = editbase->object;
+ Mesh *me = obedit->data;
+ BMEditMesh *em = me->edit_btmesh;
+ BMesh *bmnew;
+ int allocsize[] = {512, 512, 2048, 512};
+
+ if (!em)
+ return OPERATOR_CANCELLED;
+
+ bmnew = BM_Make_Mesh(allocsize);
+ CustomData_copy(&bmnew->vdata, &em->bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bmnew->edata, &em->bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bmnew->ldata, &em->bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bmnew->pdata, &em->bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+ CustomData_bmesh_init_pool(&bmnew->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&bmnew->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&bmnew->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&bmnew->pdata, allocsize[3]);
+
+ basenew= ED_object_add_duplicate(bmain, scene, editbase, USER_DUP_MESH); /* 0 = fully linked */
+ assign_matarar(basenew->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */
+
+ ED_base_object_select(basenew, BA_DESELECT);
+
+ EDBM_CallOpf(em, wmop, "dupe geom=%hvef dest=%p", BM_SELECT, bmnew);
+ EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_SELECT, DEL_FACES);
+
+ /*clean up any loose edges*/
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(e, BM_HIDDEN))
+ continue;
+
+ if (BM_Edge_FaceCount(e) != 0)
+ BM_Select(em->bm, e, 0); /*deselect*/
+ }
+ EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_SELECT, DEL_EDGES);
+
+ /*clean up any loose verts*/
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(v, BM_HIDDEN))
+ continue;
+
+ if (BM_Vert_EdgeCount(v) != 0)
+ BM_Select(em->bm, v, 0); /*deselect*/
+ }
+
+ EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_SELECT, DEL_VERTS);
+
+ BM_Compute_Normals(bmnew);
+ BMO_CallOpf(bmnew, "bmesh_to_mesh mesh=%p object=%p", basenew->object->data, basenew->object);
+
+ BM_Free_Mesh(bmnew);
+
+ return 1;
+}
+
+static int mesh_separate_material(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop)
+{
+ return 0;
+}
+
+static int mesh_separate_loose(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop)
+{
+ return 0;
+}
+
+static int mesh_separate_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene= CTX_data_scene(C);
+ Base *base= CTX_data_active_base(C);
+ int retval= 0, type= RNA_enum_get(op->ptr, "type");
+
+ if(type == 0)
+ retval= mesh_separate_selected(bmain, scene, base, op);
+ else if(type == 1)
+ retval= mesh_separate_material (bmain, scene, base, op);
+ else if(type == 2)
+ retval= mesh_separate_loose(bmain, scene, base, op);
+
+ if(retval) {
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data);
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+/* *************** Operator: separate parts *************/
+
+static EnumPropertyItem prop_separate_types[] = {
+ {0, "SELECTED", 0, "Selection", ""},
+ {1, "MATERIAL", 0, "By Material", ""},
+ {2, "LOOSE", 0, "By loose parts", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+void MESH_OT_separate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Separate";
+ ot->description= "Separate selected geometry into a new mesh.";
+ ot->idname= "MESH_OT_separate";
+
+ /* api callbacks */
+ ot->invoke= WM_menu_invoke;
+ ot->exec= mesh_separate_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", "");
+}
+
+
+static int fill_mesh_exec(bContext *C, wmOperator *op)
+{
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+
+ fill_mesh(em);
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+#endif
+ return OPERATOR_FINISHED;
+
+}
+
+void MESH_OT_fill(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Fill";
+ ot->idname= "MESH_OT_fill";
+
+ /* api callbacks */
+ ot->exec= fill_mesh_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int beauty_fill_exec(bContext *C, wmOperator *op)
+{
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+
+ beauty_fill(em);
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+#endif
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_beautify_fill(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Beautify Fill";
+ ot->idname= "MESH_OT_beautify_fill";
+
+ /* api callbacks */
+ ot->exec= beauty_fill_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/********************** Quad/Tri Operators *************************/
+
+static int quads_convert_to_tris_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ if (!EDBM_CallOpf(em, op, "triangulate faces=%hf", BM_SELECT))
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_quads_convert_to_tris(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Quads to Tris";
+ ot->idname= "MESH_OT_quads_convert_to_tris";
+
+ /* api callbacks */
+ ot->exec= quads_convert_to_tris_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int tris_convert_to_quads_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ int dosharp, douvs, dovcols, domaterials;
+ float limit = RNA_float_get(op->ptr, "limit");
+
+ dosharp = RNA_boolean_get(op->ptr, "sharp");
+ douvs = RNA_boolean_get(op->ptr, "uvs");
+ dovcols = RNA_boolean_get(op->ptr, "vcols");
+ domaterials = RNA_boolean_get(op->ptr, "materials");
+
+ if (!EDBM_CallOpf(em, op,
+ "join_triangles faces=%hf limit=%f compare_sharp=%i compare_uvs=%i compare_vcols=%i compare_materials=%i",
+ BM_SELECT, limit, dosharp, douvs, dovcols, domaterials))
+ {
+ return OPERATOR_CANCELLED;
+ }
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Tris to Quads";
+ ot->idname= "MESH_OT_tris_convert_to_quads";
+
+ /* api callbacks */
+ ot->exec= tris_convert_to_quads_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_float(ot->srna, "limit", 40.0f, -180.0f, 180.0f, "Max Angle", "Angle Limit in Degrees", -180, 180.0f);
+
+ RNA_def_boolean(ot->srna, "uvs", 0, "Compare UVs", "");
+ RNA_def_boolean(ot->srna, "vcols", 0, "Compare VCols", "");
+ RNA_def_boolean(ot->srna, "sharp", 0, "Compare Sharp", "");
+ RNA_def_boolean(ot->srna, "materials", 0, "Compare Materials", "");
+
+}
+
+static int edge_flip_exec(bContext *C, wmOperator *op)
+{
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+
+ edge_flip(em);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+#endif
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_edge_flip(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Edge Flip";
+ ot->idname= "MESH_OT_edge_flip";
+
+ /* api callbacks */
+ ot->exec= edge_flip_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int split_mesh(bContext *C, wmOperator *op)
+{
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+
+ WM_cursor_wait(1);
+
+ /* make duplicate first */
+ adduplicateflag(em, SELECT);
+ /* old faces have flag 128 set, delete them */
+ delfaceflag(em, 128);
+ recalc_editnormals(em);
+
+ WM_cursor_wait(0);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+#endif
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_split(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Split";
+ ot->idname= "MESH_OT_split";
+
+ /* api callbacks */
+ ot->exec= split_mesh;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+
+static int spin_mesh(bContext *C, wmOperator *op, float *dvec, int steps, float degr, int dupli )
+{
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ ToolSettings *ts= CTX_data_tool_settings(C);
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ EditVert *eve,*nextve;
+ float nor[3]= {0.0f, 0.0f, 0.0f};
+ float si, n[3], q[4], cmat[3][3], imat[3][3], tmat[3][3];
+ float cent[3], bmat[3][3];
+ float phi;
+ short a, ok= 1;
+
+ RNA_float_get_array(op->ptr, "center", cent);
+
+ /* imat and center and size */
+ copy_m3_m4(bmat, obedit->obmat);
+ invert_m3_m3(imat,bmat);
+
+ cent[0]-= obedit->obmat[3][0];
+ cent[1]-= obedit->obmat[3][1];
+ cent[2]-= obedit->obmat[3][2];
+ mul_m3_v3(imat, cent);
+
+ phi= degr*M_PI/360.0;
+ phi/= steps;
+ if(ts->editbutflag & B_CLOCKWISE) phi= -phi;
+
+ RNA_float_get_array(op->ptr, "axis", n);
+ normalize_v3(n);
+
+ q[0]= (float)cos(phi);
+ si= (float)sin(phi);
+ q[1]= n[0]*si;
+ q[2]= n[1]*si;
+ q[3]= n[2]*si;
+ quat_to_mat3( cmat,q);
+
+ mul_m3_m3m3(tmat,cmat,bmat);
+ mul_m3_m3m3(bmat,imat,tmat);
+
+ if(dupli==0)
+ if(ts->editbutflag & B_KEEPORIG)
+ adduplicateflag(em, 1);
+
+ for(a=0; a<steps; a++) {
+ if(dupli==0) ok= extrudeflag(obedit, em, SELECT, nor, 0);
+ else adduplicateflag(em, SELECT);
+
+ if(ok==0)
+ break;
+
+ rotateflag(em, SELECT, cent, bmat);
+ if(dvec) {
+ mul_m3_v3(bmat,dvec);
+ translateflag(em, SELECT, dvec);
+ }
+ }
+
+ if(ok==0) {
+ /* no vertices or only loose ones selected, remove duplicates */
+ eve= em->verts.first;
+ while(eve) {
+ nextve= eve->next;
+ if(eve->f & SELECT) {
+ BLI_remlink(&em->verts,eve);
+ free_editvert(em, eve);
+ }
+ eve= nextve;
+ }
+ }
+ else {
+ recalc_editnormals(em);
+
+ EM_fgon_flags(em);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ }
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+ return ok;
+#endif
+ return OPERATOR_CANCELLED;
+}
+
+static int spin_mesh_exec(bContext *C, wmOperator *op)
+{
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ int ok;
+
+ ok= spin_mesh(C, op, NULL, RNA_int_get(op->ptr,"steps"), RNA_float_get(op->ptr,"degrees"), RNA_boolean_get(op->ptr,"dupli"));
+ if(ok==0) {
+ BKE_report(op->reports, RPT_ERROR, "No valid vertices are selected");
+ return OPERATOR_CANCELLED;
+ }
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+#endif
+ return OPERATOR_FINISHED;
+}
+
+/* get center and axis, in global coords */
+static int spin_mesh_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+#if 0
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d= ED_view3d_context_rv3d(C);
+
+ RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d));
+ RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[2]);
+
+#endif
+ return spin_mesh_exec(C, op);
+}
+
+void MESH_OT_spin(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Spin";
+ ot->idname= "MESH_OT_spin";
+
+ /* api callbacks */
+ ot->invoke= spin_mesh_invoke;
+ ot->exec= spin_mesh_exec;
+ ot->poll= EM_view3d_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, INT_MAX);
+ RNA_def_boolean(ot->srna, "dupli", 0, "Dupli", "Make Duplicates");
+ RNA_def_float(ot->srna, "degrees", 90.0f, -FLT_MAX, FLT_MAX, "Degrees", "Degrees", -360.0f, 360.0f);
+
+ RNA_def_float_vector(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
+ RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX);
+
+}
+
+static int screw_mesh_exec(bContext *C, wmOperator *op)
+{
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ EditVert *eve,*v1=0,*v2=0;
+ EditEdge *eed;
+ float dvec[3], nor[3];
+ int steps, turns;
+
+ turns= RNA_int_get(op->ptr, "turns");
+ steps= RNA_int_get(op->ptr, "steps");
+
+ /* clear flags */
+ for(eve= em->verts.first; eve; eve= eve->next)
+ eve->f1= 0;
+
+ /* edges set flags in verts */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->v1->f & SELECT) {
+ if(eed->v2->f & SELECT) {
+ /* watch: f1 is a byte */
+ if(eed->v1->f1<2) eed->v1->f1++;
+ if(eed->v2->f1<2) eed->v2->f1++;
+ }
+ }
+ }
+ /* find two vertices with eve->f1==1, more or less is wrong */
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f1==1) {
+ if(v1==NULL) v1= eve;
+ else if(v2==NULL) v2= eve;
+ else {
+ v1= NULL;
+ break;
+ }
+ }
+ }
+ if(v1==NULL || v2==NULL) {
+ BKE_report(op->reports, RPT_ERROR, "You have to select a string of connected vertices too");
+ BKE_mesh_end_editmesh(obedit->data, em);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* calculate dvec */
+ dvec[0]= ( v1->co[0]- v2->co[0] )/steps;
+ dvec[1]= ( v1->co[1]- v2->co[1] )/steps;
+ dvec[2]= ( v1->co[2]- v2->co[2] )/steps;
+
+ VECCOPY(nor, obedit->obmat[2]);
+
+ if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.000) {
+ dvec[0]= -dvec[0];
+ dvec[1]= -dvec[1];
+ dvec[2]= -dvec[2];
+ }
+
+ if(spin_mesh(C, op, dvec, turns*steps, 360.0f*turns, 0)) {
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No valid vertices are selected");
+ BKE_mesh_end_editmesh(obedit->data, em);
+ return OPERATOR_CANCELLED;
+ }
+#endif
+ return OPERATOR_CANCELLED;
+}
+
+/* get center and axis, in global coords */
+static int screw_mesh_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+#if 0
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d= ED_view3d_context_rv3d(C);
+
+ RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d));
+ RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[1]);
+#endif
+ return screw_mesh_exec(C, op);
+}
+
+void MESH_OT_screw(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Screw";
+ ot->idname= "MESH_OT_screw";
+
+ /* api callbacks */
+ ot->invoke= screw_mesh_invoke;
+ ot->exec= screw_mesh_exec;
+ ot->poll= EM_view3d_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /*props */
+ RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, 256);
+ RNA_def_int(ot->srna, "turns", 1, 0, INT_MAX, "Turns", "Turns", 0, 256);
+
+ RNA_def_float_vector(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
+ RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX);
+}
+
+static int region_to_loop(bContext *C, wmOperator *op)
+{
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ EditEdge *eed;
+ EditFace *efa;
+ int selected= 0;
+
+ for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = 0;
+
+ for(efa=em->faces.first; efa; efa=efa->next){
+ if(efa->f&SELECT){
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ if(efa->e4)
+ efa->e4->f1++;
+
+ selected= 1;
+ }
+ }
+
+ if(!selected)
+ return OPERATOR_CANCELLED;
+
+ EM_clear_flag_all(em, SELECT);
+
+ for(eed=em->edges.first; eed; eed=eed->next){
+ if(eed->f1 == 1) EM_select_edge(eed, 1);
+ }
+
+ em->selectmode = SCE_SELECT_EDGE;
+ EM_selectmode_set(em);
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+#endif
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_region_to_loop(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Region to Loop";
+ ot->idname= "MESH_OT_region_to_loop";
+
+ /* api callbacks */
+ ot->exec= region_to_loop;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+static int loop_to_region(bContext *C, wmOperator *op)
+{
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+
+
+ EditFace *efa;
+ ListBase allcollections={NULL,NULL};
+ Collection *edgecollection;
+ int testflag;
+
+ build_edgecollection(em, &allcollections);
+
+ for(edgecollection = (Collection *)allcollections.first; edgecollection; edgecollection=edgecollection->next){
+ if(validate_loop(em, edgecollection)){
+ testflag = loop_bisect(em, edgecollection);
+ for(efa=em->faces.first; efa; efa=efa->next){
+ if(efa->f1 == testflag){
+ if(efa->f&SELECT) EM_select_face(efa, 0);
+ else EM_select_face(efa,1);
+ }
+ }
+ }
+ }
+
+ for(efa=em->faces.first; efa; efa=efa->next){ /*fix this*/
+ if(efa->f&SELECT) EM_select_face(efa,1);
+ }
+
+ freecollections(&allcollections);
+ BKE_mesh_end_editmesh(obedit->data, em);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+#endif
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_loop_to_region(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Loop to Region";
+ ot->idname= "MESH_OT_loop_to_region";
+
+ /* api callbacks */
+ ot->exec= loop_to_region;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+int select_by_number_vertices_exec(bContext *C, wmOperator *op)
+{
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+ EditFace *efa;
+ int numverts= RNA_enum_get(op->ptr, "type");
+
+ /* Selects trias/qiads or isolated verts, and edges that do not have 2 neighboring
+ * faces
+ */
+
+ /* for loose vertices/edges, we first select all, loop below will deselect */
+ if(numverts==5) {
+ EM_set_flag_all(em, SELECT);
+ }
+ else if(em->selectmode!=SCE_SELECT_FACE) {
+ BKE_report(op->reports, RPT_ERROR, "Only works in face selection mode");
+ return OPERATOR_CANCELLED;
+ }
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if (efa->e4) {
+ EM_select_face(efa, (numverts==4) );
+ }
+ else {
+ EM_select_face(efa, (numverts==3) );
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+#endif
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_by_number_vertices(wmOperatorType *ot)
+{
+ static const EnumPropertyItem type_items[]= {
+ {3, "TRIANGLES", 0, "Triangles", NULL},
+ {4, "QUADS", 0, "Triangles", NULL},
+ {5, "OTHER", 0, "Other", NULL},
+ {0, NULL, 0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name= "Select by Number of Vertices";
+ ot->description= "Select vertices or faces by vertex count.";
+ ot->idname= "MESH_OT_select_by_number_vertices";
+
+ /* api callbacks */
+ ot->exec= select_by_number_vertices_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "type", type_items, 3, "Type", "Type of elements to select.");
+}
+
+
+#define MIRROR_THRESH 1.0f
+
+int select_mirror_exec(bContext *C, wmOperator *op)
+{
+
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMBVHTree *tree = BMBVH_NewBVH(em);
+ BMVert *v1, *v2;
+ BMIter iter;
+ int extend= RNA_boolean_get(op->ptr, "extend");
+ float mirror_co[3];
+
+ BM_ITER(v1, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_TestHFlag(v1, BM_SELECT) || BM_TestHFlag(v1, BM_HIDDEN))
+ BMINDEX_SET(v1, 0);
+ else BMINDEX_SET(v1, 1);
+ }
+
+ if (!extend)
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ BM_ITER(v1, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BMINDEX_GET(v1) || BM_TestHFlag(v1, BM_HIDDEN))
+ continue;
+
+ VECCOPY(mirror_co, v1->co);
+ mirror_co[0] *= -1.0f;
+
+ v2 = BMBVH_FindClosestVertTopo(tree, mirror_co, MIRROR_THRESH, v1);
+ if (v2 && !BM_TestHFlag(v2, BM_HIDDEN))
+ BM_Select(em->bm, v2, 1);
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_mirror(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Mirror";
+ ot->description= "Select mesh items at mirrored locations.";
+ ot->idname= "MESH_OT_select_mirror";
+
+ /* api callbacks */
+ ot->exec= select_mirror_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
+}
+
+/********* qsort routines. not sure how to make these
+ work, since we aren't using linked lists for
+ geometry anymore. might need a sortof "swap"
+ function for bmesh elements. *********/
+
+typedef struct xvertsort {
+ float x;
+ BMVert *v1;
+} xvertsort;
+
+
+static int vergxco(const void *v1, const void *v2)
+{
+ const xvertsort *x1=v1, *x2=v2;
+
+ if( x1->x > x2->x ) return 1;
+ else if( x1->x < x2->x) return -1;
+ return 0;
+}
+
+struct facesort {
+ uintptr_t x;
+ struct EditFace *efa;
+};
+
+static int vergface(const void *v1, const void *v2)
+{
+ const struct facesort *x1=v1, *x2=v2;
+
+ if( x1->x > x2->x ) return 1;
+ else if( x1->x < x2->x) return -1;
+ return 0;
+}
+
+// XXX is this needed?
+/* called from buttons */
+static void xsortvert_flag__doSetX(void *userData, EditVert *UNUSED(eve), int x, int UNUSED(y), int index)
+{
+ xvertsort *sortblock = userData;
+
+ sortblock[index].x = x;
+}
+
+/* all verts with (flag & 'flag') are sorted */
+static void xsortvert_flag(bContext *C, int flag)
+{
+#if 0 //hrm, geometry isn't in linked lists anymore. . .
+ ViewContext vc;
+ BMEditMesh *em;
+ BMVert *eve;
+ BMIter iter;
+ xvertsort *sortblock;
+ ListBase tbase;
+ int i, amount;
+
+ em_setup_viewcontext(C, &vc);
+ em = vc.em;
+
+ amount = em->bm->totvert;
+ sortblock = MEM_callocN(sizeof(xvertsort)*amount,"xsort");
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if(BM_TestHFlag(eve, BM_SELECT))
+ sortblock[i].v1 = eve;
+ }
+
+ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
+ mesh_foreachScreenVert(&vc, xsortvert_flag__doSetX, sortblock, 0);
+
+ qsort(sortblock, amount, sizeof(xvertsort), vergxco);
+
+ /* make temporal listbase */
+ tbase.first= tbase.last= 0;
+ for (i=0; i<amount; i++) {
+ eve = sortblock[i].v1;
+
+ if (eve) {
+ BLI_remlink(&vc.em->verts, eve);
+ BLI_addtail(&tbase, eve);
+ }
+ }
+
+ BLI_movelisttolist(&vc.em->verts, &tbase);
+
+ MEM_freeN(sortblock);
+#endif
+
+}
+
+static int mesh_vertices_sort_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ xsortvert_flag(C, SELECT);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_vertices_sort(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Vertex Sort";
+ ot->description= "Sort vertex order";
+ ot->idname= "MESH_OT_vertices_sort";
+
+ /* api callbacks */
+ ot->exec= mesh_vertices_sort_exec;
+
+ ot->poll= EM_view3d_poll; /* uses view relative X axis to sort verts */
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+#if 0
+/* called from buttons */
+static void hashvert_flag(EditMesh *em, int flag)
+{
+ /* switch vertex order using hash table */
+ EditVert *eve;
+ struct xvertsort *sortblock, *sb, onth, *newsort;
+ ListBase tbase;
+ int amount, a, b;
+
+ /* count */
+ eve= em->verts.first;
+ amount= 0;
+ while(eve) {
+ if(eve->f & flag) amount++;
+ eve= eve->next;
+ }
+ if(amount==0) return;
+
+ /* allocate memory */
+ sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*amount,"sortremovedoub");
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & flag) {
+ sb->v1= eve;
+ sb++;
+ }
+ eve= eve->next;
+ }
+
+ BLI_srand(1);
+
+ sb= sortblock;
+ for(a=0; a<amount; a++, sb++) {
+ b= (int)(amount*BLI_drand());
+ if(b>=0 && b<amount) {
+ newsort= sortblock+b;
+ onth= *sb;
+ *sb= *newsort;
+ *newsort= onth;
+ }
+ }
+
+ /* make temporal listbase */
+ tbase.first= tbase.last= 0;
+ sb= sortblock;
+ while(amount--) {
+ eve= sb->v1;
+ BLI_remlink(&em->verts, eve);
+ BLI_addtail(&tbase, eve);
+ sb++;
+ }
+
+ BLI_movelisttolist(&em->verts, &tbase);
+
+ MEM_freeN(sortblock);
+
+}
+#endif
+
+static int mesh_vertices_randomize_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ //hashvert_flag(em, SELECT);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_vertices_randomize(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Vertex Randomize";
+ ot->description= "Randomize vertex order";
+ ot->idname= "MESH_OT_vertices_randomize";
+
+ /* api callbacks */
+ ot->exec= mesh_vertices_randomize_exec;
+
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/******end of qsort stuff ****/
+
+
+static int mesh_noise_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+ Material *ma;
+ Tex *tex;
+ BMVert *eve;
+ BMIter iter;
+ float fac= RNA_float_get(op->ptr, "factor");
+
+ if(em==NULL) return OPERATOR_FINISHED;
+
+ ma= give_current_material(obedit, obedit->actcol);
+ if(ma==0 || ma->mtex[0]==0 || ma->mtex[0]->tex==0) {
+ BKE_report(op->reports, RPT_WARNING, "Mesh has no material or texture assigned.");
+ return OPERATOR_FINISHED;
+ }
+ tex= give_current_material_texture(ma);
+
+ if(tex->type==TEX_STUCCI) {
+ float b2, vec[3];
+ float ofs= tex->turbul/200.0;
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_SELECT) && !BM_TestHFlag(eve, BM_HIDDEN)) {
+ b2= BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]);
+ if(tex->stype) ofs*=(b2*b2);
+ vec[0]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0]+ofs, eve->co[1], eve->co[2]));
+ vec[1]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1]+ofs, eve->co[2]));
+ vec[2]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]+ofs));
+
+ add_v3_v3(eve->co, vec);
+ }
+ }
+ }
+ else {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_SELECT) && !BM_TestHFlag(eve, BM_HIDDEN)) {
+ float tin, dum;
+ externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0);
+ eve->co[2]+= fac*tin;
+ }
+ }
+ }
+
+ EDBM_RecalcNormals(em);
+
+ DAG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_noise(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Noise";
+ ot->description= "Use vertex coordinate as texture coordinate";
+ ot->idname= "MESH_OT_noise";
+
+ /* api callbacks */
+ ot->exec= mesh_noise_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_float(ot->srna, "factor", 0.1f, -FLT_MAX, FLT_MAX, "Factor", "", 0.0f, 1.0f);
+}
diff --git a/source/blender/editors/mesh/bmeshutils.c b/source/blender/editors/mesh/bmeshutils.c
new file mode 100644
index 00000000000..de5b468d93c
--- /dev/null
+++ b/source/blender/editors/mesh/bmeshutils.c
@@ -0,0 +1,897 @@
+ /* $Id: bmeshutils.c
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_key_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "RNA_types.h"
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_heap.h"
+#include "BLI_array.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_key.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+
+#include "bmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+#include "ED_view3d.h"
+#include "ED_util.h"
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "editbmesh_bvh.h"
+#include "mesh_intern.h"
+
+void EDBM_RecalcNormals(BMEditMesh *em)
+{
+ BM_Compute_Normals(em->bm);
+}
+
+void EDBM_stats_update(BMEditMesh *em)
+{
+ BMIter iter;
+ BMHeader *ele;
+ int types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
+ int *tots[3];
+ int i;
+
+ tots[0] = &em->bm->totvertsel;
+ tots[1] = &em->bm->totedgesel;
+ tots[2] = &em->bm->totfacesel;
+
+ em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0;
+
+ for (i=0; i<3; i++) {
+ ele = BMIter_New(&iter, em->bm, types[i], NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(ele, BM_SELECT)) {
+ *tots[i]++;
+ }
+ }
+ }
+}
+
+int EDBM_InitOpf(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt, ...)
+{
+ BMesh *bm = em->bm;
+ va_list list;
+
+ va_start(list, fmt);
+
+ if (!BMO_VInitOpf(bm, bmop, fmt, list)) {
+ BKE_report(op->reports, RPT_ERROR,
+ "Parse error in EDBM_CallOpf");
+ va_end(list);
+ return 0;
+ }
+
+ if (!em->emcopy)
+ em->emcopy = BMEdit_Copy(em);
+ em->emcopyusers++;
+
+ va_end(list);
+
+ return 1;
+}
+
+
+/*returns 0 on error, 1 on success. executes and finishes a bmesh operator*/
+int EDBM_FinishOp(BMEditMesh *em, BMOperator *bmop, wmOperator *op, int report) {
+ char *errmsg;
+
+ BMO_Finish_Op(em->bm, bmop);
+
+ if (BMO_GetError(em->bm, &errmsg, NULL)) {
+ BMEditMesh *emcopy = em->emcopy;
+
+ if (report) BKE_report(op->reports, RPT_ERROR, errmsg);
+
+ BMEdit_Free(em);
+ *em = *emcopy;
+
+ MEM_freeN(emcopy);
+ em->emcopyusers = 0;
+ em->emcopy = NULL;
+ return 0;
+ } else {
+ em->emcopyusers--;
+ if (em->emcopyusers < 0) {
+ printf("warning: em->emcopyusers was less then zero.\n");
+ }
+
+ if (em->emcopyusers <= 0) {
+ BMEdit_Free(em->emcopy);
+ MEM_freeN(em->emcopy);
+ em->emcopy = NULL;
+ }
+ }
+
+ return 1;
+}
+
+int EDBM_CallOpf(BMEditMesh *em, wmOperator *op, const char *fmt, ...)
+{
+ BMesh *bm = em->bm;
+ BMOperator bmop;
+ va_list list;
+
+ va_start(list, fmt);
+
+ if (!BMO_VInitOpf(bm, &bmop, fmt, list)) {
+ BKE_report(op->reports, RPT_ERROR,
+ "Parse error in EDBM_CallOpf");
+ va_end(list);
+ return 0;
+ }
+
+ if (!em->emcopy)
+ em->emcopy = BMEdit_Copy(em);
+ em->emcopyusers++;
+
+ BMO_Exec_Op(bm, &bmop);
+
+ va_end(list);
+ return EDBM_FinishOp(em, &bmop, op, 1);
+}
+
+int EDBM_CallAndSelectOpf(BMEditMesh *em, wmOperator *op, const char *selectslot, const char *fmt, ...)
+{
+ BMesh *bm = em->bm;
+ BMOperator bmop;
+ va_list list;
+
+ va_start(list, fmt);
+
+ if (!BMO_VInitOpf(bm, &bmop, fmt, list)) {
+ BKE_report(op->reports, RPT_ERROR,
+ "Parse error in EDBM_CallOpf");
+ va_end(list);
+ return 0;
+ }
+
+ if (!em->emcopy)
+ em->emcopy = BMEdit_Copy(em);
+ em->emcopyusers++;
+
+ BMO_Exec_Op(bm, &bmop);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, selectslot, BM_SELECT, BM_ALL);
+
+ va_end(list);
+ return EDBM_FinishOp(em, &bmop, op, 1);
+}
+
+int EDBM_CallOpfSilent(BMEditMesh *em, const char *fmt, ...)
+{
+ BMesh *bm = em->bm;
+ BMOperator bmop;
+ va_list list;
+
+ va_start(list, fmt);
+
+ if (!BMO_VInitOpf(bm, &bmop, fmt, list)) {
+ va_end(list);
+ return 0;
+ }
+
+ if (!em->emcopy)
+ em->emcopy = BMEdit_Copy(em);
+ em->emcopyusers++;
+
+ BMO_Exec_Op(bm, &bmop);
+
+ va_end(list);
+ return EDBM_FinishOp(em, &bmop, NULL, 0);
+}
+
+void EDBM_selectmode_to_scene(Scene *scene, Object *obedit)
+{
+ BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
+
+ if (!em)
+ return;
+
+ scene->toolsettings->selectmode = em->selectmode;
+}
+
+void EDBM_MakeEditBMesh(ToolSettings *ts, Scene *scene, Object *ob)
+{
+ Mesh *me = ob->data;
+ EditMesh *em;
+ BMesh *bm;
+
+ if (!me->mpoly && me->totface) {
+ printf("yeek!! bmesh conversion issue! may lose lots of geometry!\n");
+
+ /*BMESH_TODO need to write smarter code here*/
+ bm = BKE_mesh_to_bmesh(me, ob);
+ } else {
+ bm = BKE_mesh_to_bmesh(me, ob);
+ }
+
+ me->edit_btmesh = BMEdit_Create(bm);
+ me->edit_btmesh->selectmode = ts->selectmode;
+ me->edit_btmesh->me = me;
+ me->edit_btmesh->ob = ob;
+}
+
+void EDBM_LoadEditBMesh(Scene *scene, Object *ob)
+{
+ Mesh *me = ob->data;
+ BMesh *bm = me->edit_btmesh->bm;
+
+ BMO_CallOpf(bm, "object_load_bmesh scene=%p object=%p", scene, ob);
+}
+
+void EDBM_FreeEditBMesh(BMEditMesh *tm)
+{
+ BMEdit_Free(tm);
+}
+
+void EDBM_init_index_arrays(BMEditMesh *tm, int forvert, int foredge, int forface)
+{
+ EDBM_free_index_arrays(tm);
+
+ if (forvert) {
+ BMIter iter;
+ BMVert *ele;
+ int i=0;
+
+ tm->vert_index = MEM_mallocN(sizeof(void**)*tm->bm->totvert, "tm->vert_index");
+
+ ele = BMIter_New(&iter, tm->bm, BM_VERTS_OF_MESH, NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ tm->vert_index[i++] = ele;
+ }
+ }
+
+ if (foredge) {
+ BMIter iter;
+ BMEdge *ele;
+ int i=0;
+
+ tm->edge_index = MEM_mallocN(sizeof(void**)*tm->bm->totedge, "tm->edge_index");
+
+ ele = BMIter_New(&iter, tm->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ tm->edge_index[i++] = ele;
+ }
+ }
+
+ if (forface) {
+ BMIter iter;
+ BMFace *ele;
+ int i=0;
+
+ tm->face_index = MEM_mallocN(sizeof(void**)*tm->bm->totface, "tm->face_index");
+
+ ele = BMIter_New(&iter, tm->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ tm->face_index[i++] = ele;
+ }
+ }
+}
+
+void EDBM_free_index_arrays(BMEditMesh *tm)
+{
+ if (tm->vert_index) {
+ MEM_freeN(tm->vert_index);
+ tm->vert_index = NULL;
+ }
+
+ if (tm->edge_index) {
+ MEM_freeN(tm->edge_index);
+ tm->edge_index = NULL;
+ }
+
+ if (tm->face_index) {
+ MEM_freeN(tm->face_index);
+ tm->face_index = NULL;
+ }
+}
+
+BMVert *EDBM_get_vert_for_index(BMEditMesh *tm, int index)
+{
+ return tm->vert_index?tm->vert_index[index]:NULL;
+}
+
+BMEdge *EDBM_get_edge_for_index(BMEditMesh *tm, int index)
+{
+ return tm->edge_index?tm->edge_index[index]:NULL;
+}
+
+BMFace *EDBM_get_face_for_index(BMEditMesh *tm, int index)
+{
+ return (tm->face_index && index<tm->bm->totface && index>=0) ? tm->face_index[index] : NULL;
+}
+
+/* this replaces the active flag used in uv/face mode */
+void EDBM_set_actFace(BMEditMesh *em, BMFace *efa)
+{
+ em->bm->act_face = efa;
+}
+
+BMFace *EDBM_get_actFace(BMEditMesh *em, int sloppy)
+{
+ if (em->bm->act_face) {
+ return em->bm->act_face;
+ } else if (sloppy) {
+ BMFace *efa= NULL;
+ BMEditSelection *ese;
+
+ ese = em->bm->selected.last;
+ for (; ese; ese=ese->prev){
+ if(ese->type == BM_FACE) {
+ efa = (BMFace *)ese->data;
+
+ if (BM_TestHFlag(efa, BM_HIDDEN)) efa= NULL;
+ else break;
+ }
+ }
+ if (efa==NULL) {
+ BMIter iter;
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(efa, BM_SELECT))
+ break;
+ }
+ }
+ return efa; /* can still be null */
+ }
+ return NULL;
+
+}
+
+void EDBM_select_flush(BMEditMesh *em, int selectmode)
+{
+ em->bm->selectmode = selectmode;
+ BM_SelectMode_Flush(em->bm);
+ em->bm->selectmode = em->selectmode;
+}
+
+/*BMESH_TODO*/
+void EDBM_deselect_flush(BMEditMesh *em)
+{
+}
+
+
+void EDBM_selectmode_flush(BMEditMesh *em)
+{
+ em->bm->selectmode = em->selectmode;
+ BM_SelectMode_Flush(em->bm);
+}
+
+/*EDBM_select_[more/less] are api functions, I think the uv editor
+ uses them? though the select more/less ops themselves do not.*/
+void EDBM_select_more(BMEditMesh *em)
+{
+ BMOperator bmop;
+ int usefaces = em->selectmode > SCE_SELECT_EDGE;
+
+ BMO_InitOpf(em->bm, &bmop,
+ "regionextend geom=%hvef constrict=%d usefaces=%d",
+ BM_SELECT, 0, usefaces);
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
+ BMO_Finish_Op(em->bm, &bmop);
+
+ EDBM_selectmode_flush(em);
+}
+
+void EDBM_select_less(BMEditMesh *em)
+{
+ BMOperator bmop;
+ int usefaces = em->selectmode > SCE_SELECT_EDGE;
+
+ BMO_InitOpf(em->bm, &bmop,
+ "regionextend geom=%hvef constrict=%d usefaces=%d",
+ BM_SELECT, 0, usefaces);
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
+ BMO_Finish_Op(em->bm, &bmop);
+
+ EDBM_selectmode_flush(em);
+}
+
+int EDBM_get_actSelection(BMEditMesh *em, BMEditSelection *ese)
+{
+ BMEditSelection *ese_last = em->bm->selected.last;
+ BMFace *efa = EDBM_get_actFace(em, 0);
+
+ ese->next = ese->prev = NULL;
+
+ if (ese_last) {
+ if (ese_last->type == BM_FACE) { /* if there is an active face, use it over the last selected face */
+ if (efa) {
+ ese->data = (void *)efa;
+ } else {
+ ese->data = ese_last->data;
+ }
+ ese->type = BM_FACE;
+ } else {
+ ese->data = ese_last->data;
+ ese->type = ese_last->type;
+ }
+ } else if (efa) { /* no */
+ ese->data = (void *)efa;
+ ese->type = BM_FACE;
+ } else {
+ ese->data = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+void EDBM_clear_flag_all(BMEditMesh *em, int flag)
+{
+ BMIter iter;
+ BMHeader *ele;
+ int i, type;
+
+ if (flag & BM_SELECT)
+ BM_clear_selection_history(em->bm);
+
+ for (i=0; i<3; i++) {
+ switch (i) {
+ case 0:
+ type = BM_VERTS_OF_MESH;
+ break;
+ case 1:
+ type = BM_EDGES_OF_MESH;
+ break;
+ case 2:
+ type = BM_FACES_OF_MESH;
+ break;
+ }
+
+ BM_ITER(ele, &iter, em->bm, type, NULL) {
+ if (flag & BM_SELECT) BM_Select(em->bm, ele, 0);
+ BM_ClearHFlag(ele, flag);
+ }
+ }
+}
+
+void EDBM_set_flag_all(BMEditMesh *em, int flag)
+{
+ BMIter iter;
+ BMHeader *ele;
+ int i, type;
+
+ for (i=0; i<3; i++) {
+ switch (i) {
+ case 0:
+ type = BM_VERTS_OF_MESH;
+ break;
+ case 1:
+ type = BM_EDGES_OF_MESH;
+ break;
+ case 2:
+ type = BM_FACES_OF_MESH;
+ break;
+ }
+
+ ele = BMIter_New(&iter, em->bm, type, NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ if (flag & BM_SELECT) BM_Select(em->bm, ele, 1);
+ BM_SetHFlag(ele, flag);
+ }
+ }
+}
+
+/**************-------------- Undo ------------*****************/
+
+/* for callbacks */
+
+static void *getEditMesh(bContext *C)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ if(obedit && obedit->type==OB_MESH) {
+ Mesh *me= obedit->data;
+ return me->edit_btmesh;
+ }
+ return NULL;
+}
+
+typedef struct undomesh {
+ Mesh me;
+ int selectmode;
+} undomesh;
+
+/*undo simply makes copies of a bmesh*/
+static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
+{
+ BMEditMesh *em = emv;
+ Mesh *obme = obdata;
+ undomesh *me = MEM_callocN(sizeof(undomesh), "undo Mesh");
+
+ /*make sure shape keys work*/
+ me->me.key = obme->key ? copy_key_nolib(obme->key) : NULL;
+
+ /*we recalc the tesselation here, to avoid seeding calls to
+ BMEdit_RecalcTesselation throughout the code.*/
+ BMEdit_RecalcTesselation(em);
+
+ BMO_CallOpf(em->bm, "bmesh_to_mesh mesh=%p notesselation=%i", me, 1);
+ me->selectmode = em->selectmode;
+
+ return me;
+}
+
+static void undoMesh_to_editbtMesh(void *umv, void *emv, void *obdata)
+{
+ BMEditMesh *em = emv, *em2;
+ Object ob = {0,};
+ undomesh *me = umv;
+ BMesh *bm;
+ int allocsize[4] = {512, 512, 2048, 512};
+
+ ob.data = me;
+ ob.type = OB_MESH;
+ ob.shapenr = em->bm->shapenr;
+
+ BMEdit_Free(em);
+
+ bm = BM_Make_Mesh(allocsize);
+ BMO_CallOpf(bm, "mesh_to_bmesh mesh=%p object=%p", me, &ob);
+
+ em2 = BMEdit_Create(bm);
+ *em = *em2;
+
+ em->selectmode = me->selectmode;
+
+ MEM_freeN(em2);
+}
+
+
+static void free_undo(void *umv)
+{
+ free_mesh(umv, 0);
+ MEM_freeN(umv);
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_mesh(bContext *C, const char *name)
+{
+ undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
+}
+
+/*write comment here*/
+UvVertMap *EDBM_make_uv_vert_map(BMEditMesh *em, int selected, int do_face_idx_array, float *limit)
+{
+ BMVert *ev;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ /* vars from original func */
+ UvVertMap *vmap;
+ UvMapVert *buf;
+ MTexPoly *tf;
+ MLoopUV *luv;
+ unsigned int a;
+ int totverts, i, totuv;
+
+ if (do_face_idx_array)
+ EDBM_init_index_arrays(em, 0, 0, 1);
+
+ /* we need the vert */
+ totverts=0;
+ BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(ev, totverts);
+ totverts++;
+ }
+
+ totuv = 0;
+
+ /* generate UvMapVert array */
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if(!selected || ((!BM_TestHFlag(efa, BM_HIDDEN)) && BM_TestHFlag(efa, BM_SELECT)))
+ totuv += efa->len;
+ }
+
+ if(totuv==0) {
+ if (do_face_idx_array)
+ EDBM_free_index_arrays(em);
+ return NULL;
+ }
+ vmap= (UvVertMap*)MEM_callocN(sizeof(*vmap), "UvVertMap");
+ if (!vmap) {
+ if (do_face_idx_array)
+ EDBM_free_index_arrays(em);
+ return NULL;
+ }
+
+ vmap->vert= (UvMapVert**)MEM_callocN(sizeof(*vmap->vert)*totverts, "UvMapVert*");
+ buf= vmap->buf= (UvMapVert*)MEM_callocN(sizeof(*vmap->buf)*totuv, "UvMapVert");
+
+ if (!vmap->vert || !vmap->buf) {
+ free_uv_vert_map(vmap);
+ if (do_face_idx_array)
+ EDBM_free_index_arrays(em);
+ return NULL;
+ }
+
+ a = 0;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if(!selected || ((!BM_TestHFlag(efa, BM_HIDDEN)) && BM_TestHFlag(efa, BM_SELECT))) {
+ i = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ buf->tfindex= i;
+ buf->f= a;
+ buf->separate = 0;
+
+ buf->next= vmap->vert[BMINDEX_GET(l->v)];
+ vmap->vert[BMINDEX_GET(l->v)]= buf;
+
+ buf++;
+ i++;
+ }
+ }
+
+ a++;
+ }
+
+ /* sort individual uvs for each vert */
+ a = 0;
+ BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ UvMapVert *newvlist= NULL, *vlist=vmap->vert[a];
+ UvMapVert *iterv, *v, *lastv, *next;
+ float *uv, *uv2, uvdiff[2];
+
+ while(vlist) {
+ v= vlist;
+ vlist= vlist->next;
+ v->next= newvlist;
+ newvlist= v;
+
+ efa = EDBM_get_face_for_index(em, v->f);
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+
+ l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, v->tfindex);
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ uv = luv->uv;
+
+ lastv= NULL;
+ iterv= vlist;
+
+ while(iterv) {
+ next= iterv->next;
+ efa = EDBM_get_face_for_index(em, iterv->f);
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+
+ l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ uv2 = luv->uv;
+
+ sub_v2_v2v2(uvdiff, uv2, uv);
+
+ if(fabs(uv[0]-uv2[0]) < limit[0] && fabs(uv[1]-uv2[1]) < limit[1]) {
+ if(lastv) lastv->next= next;
+ else vlist= next;
+ iterv->next= newvlist;
+ newvlist= iterv;
+ }
+ else
+ lastv=iterv;
+
+ iterv= next;
+ }
+
+ newvlist->separate = 1;
+ }
+
+ vmap->vert[a]= newvlist;
+ a++;
+ }
+
+ if (do_face_idx_array)
+ EDBM_free_index_arrays(em);
+
+ return vmap;
+}
+
+
+UvMapVert *EDBM_get_uv_map_vert(UvVertMap *vmap, unsigned int v)
+{
+ return vmap->vert[v];
+}
+
+void EDBM_free_uv_vert_map(UvVertMap *vmap)
+{
+ if (vmap) {
+ if (vmap->vert) MEM_freeN(vmap->vert);
+ if (vmap->buf) MEM_freeN(vmap->buf);
+ MEM_freeN(vmap);
+ }
+}
+
+
+/* last_sel, use em->act_face otherwise get the last selected face in the editselections
+ * at the moment, last_sel is mainly useful for gaking sure the space image dosnt flicker */
+MTexPoly *EDBM_get_active_mtexpoly(BMEditMesh *em, BMFace **act_efa, int sloppy)
+{
+ BMFace *efa = NULL;
+
+ if(!EDBM_texFaceCheck(em))
+ return NULL;
+
+ efa = EDBM_get_actFace(em, sloppy);
+
+ if (efa) {
+ if (act_efa) *act_efa = efa;
+ return CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ }
+
+ if (act_efa) *act_efa= NULL;
+ return NULL;
+}
+
+/* can we edit UV's for this mesh?*/
+int EDBM_texFaceCheck(BMEditMesh *em)
+{
+ /* some of these checks could be a touch overkill */
+ return em && em->bm->totface && CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY) &&
+ CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV);
+}
+
+int EDBM_vertColorCheck(BMEditMesh *em)
+{
+ /* some of these checks could be a touch overkill */
+ return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL);
+}
+
+
+void EDBM_CacheMirrorVerts(BMEditMesh *em)
+{
+ BMBVHTree *tree = BMBVH_NewBVH(em);
+ BMIter iter;
+ BMVert *v;
+ float invmat[4][4];
+ int li, i;
+
+ if (!em->vert_index) {
+ EDBM_init_index_arrays(em, 1, 0, 0);
+ em->mirr_free_arrays = 1;
+ }
+
+ if (!CustomData_get_layer_named(&em->bm->vdata, CD_PROP_INT, "__mirror_index")) {
+ BM_add_data_layer_named(em->bm, &em->bm->vdata, CD_PROP_INT, "__mirror_index");
+ }
+
+ li = CustomData_get_named_layer_index(&em->bm->vdata, CD_PROP_INT, "__mirror_index");
+ em->bm->vdata.layers[li].flag |= CD_FLAG_TEMPORARY;
+
+ /*multiply verts by object matrix, temporarily*/
+
+ i = 0;
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(v, i);
+ i++;
+
+ if (em->ob)
+ mul_m4_v3(em->ob->obmat, v->co);
+ }
+
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMVert *mirr;
+ int *idx = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, li);
+ float co[3] = {-v->co[0], v->co[1], v->co[2]};
+
+ //temporary for testing, check for selection
+ if (!BM_TestHFlag(v, BM_SELECT))
+ continue;
+
+ mirr = BMBVH_FindClosestVertTopo(tree, co, BM_SEARCH_MAXDIST, v);
+ if (mirr && mirr != v) {
+ *idx = BMINDEX_GET(mirr);
+ idx = CustomData_bmesh_get_layer_n(&em->bm->vdata,mirr->head.data, li);
+ *idx = BMINDEX_GET(v);
+ } else *idx = -1;
+ }
+
+ /*unmultiply by object matrix*/
+ if (em->ob) {
+ i = 0;
+ invert_m4_m4(invmat, em->ob->obmat);
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(v, i);
+ i++;
+
+ mul_m4_v3(invmat, v->co);
+ }
+
+ BMBVH_FreeBVH(tree);
+ }
+}
+
+BMVert *EDBM_GetMirrorVert(BMEditMesh *em, BMVert *v)
+{
+ int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer);
+
+ if (mirr && *mirr >=0 && *mirr < em->bm->totvert) {
+ if (!em->vert_index) {
+ printf("err: should only be called between "
+ "EDBM_CacheMirrorVerts and EDBM_EndMirrorCache");
+ return NULL;
+ }
+
+ return em->vert_index[*mirr];
+ }
+
+ return NULL;
+}
+
+void EDBM_EndMirrorCache(BMEditMesh *em)
+{
+ if (em->mirr_free_arrays) {
+ MEM_freeN(em->vert_index);
+ em->vert_index = NULL;
+ }
+}
diff --git a/source/blender/editors/mesh/editbmesh_add.c b/source/blender/editors/mesh/editbmesh_add.c
new file mode 100644
index 00000000000..de4be3b72dd
--- /dev/null
+++ b/source/blender/editors/mesh/editbmesh_add.c
@@ -0,0 +1,588 @@
+ /* $Id: bmesh_tools.c
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_key_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "RNA_types.h"
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_heap.h"
+#include "BLI_array.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+#include "ED_view3d.h"
+#include "ED_util.h"
+#include "ED_screen.h"
+#include "ED_transform.h"
+#include "ED_object.h"
+
+#include "UI_interface.h"
+
+#include "mesh_intern.h"
+#include "bmesh.h"
+
+#include "editbmesh_bvh.h"
+
+
+/* uses context to figure out transform for primitive */
+/* returns standard diameter */
+static float new_primitive_matrix(bContext *C, float *loc, float *rot, float primmat[][4])
+{
+ Object *obedit= CTX_data_edit_object(C);
+ View3D *v3d =CTX_wm_view3d(C);
+ float mat[3][3], rmat[3][3], cmat[3][3], imat[3][3];
+
+ unit_m4(primmat);
+
+ eul_to_mat3(rmat, rot);
+ invert_m3(rmat);
+
+ /* inverse transform for initial rotation and object */
+ copy_m3_m4(mat, obedit->obmat);
+ mul_m3_m3m3(cmat, rmat, mat);
+ invert_m3_m3(imat, cmat);
+ copy_m4_m3(primmat, imat);
+
+ /* center */
+ VECCOPY(primmat[3], loc);
+ VECSUB(primmat[3], primmat[3], obedit->obmat[3]);
+ invert_m3_m3(imat, mat);
+ mul_m3_v3(imat, primmat[3]);
+
+ if(v3d) return v3d->grid;
+ return 1.0f;
+}
+
+/* ********* add primitive operators ************* */
+
+static void make_prim_init(bContext *C, float *dia, float mat[][4],
+ int *state, float *loc, float *rot, int layer)
+{
+ Object *obedit= CTX_data_edit_object(C);
+
+ *state = 0;
+ if(obedit==NULL || obedit->type!=OB_MESH) {
+ obedit= ED_object_add_type(C, OB_MESH, loc, rot, FALSE, layer);
+
+ /* create editmode */
+ ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER); /* rare cases the active layer is messed up */
+ *state = 1;
+ }
+ else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+
+ *dia *= new_primitive_matrix(C, loc, rot, mat);
+}
+
+static void make_prim_finish(bContext *C, int *state, int enter_editmode)
+{
+ Object *obedit = CTX_data_edit_object(C);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ /* userdef */
+ if (*state && !enter_editmode) {
+ ED_object_exit_editmode(C, EM_FREEDATA); /* adding EM_DO_UNDO messes up operator redo */
+ }
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, obedit);
+
+}
+static int add_primitive_plane_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state;
+ int layer;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_grid xsegments=%i ysegments=%i size=%f mat=%m4", 1, 1, sqrt(2.0), mat))
+ return OPERATOR_CANCELLED;
+
+ /* BMESH_TODO make plane side this: sqrt(2.0f) - plane (diameter of 1.41 makes it unit size) */
+ make_prim_finish(C, &state, enter_editmode);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_plane_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Plane";
+ ot->description= "Construct a filled planar mesh with 4 vertices.";
+ ot->idname= "MESH_OT_primitive_plane_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_plane_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+static int add_primitive_cube_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state;
+ int layer;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit= CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout", "create_cube mat=%m4 size=%f", mat, 2.0f))
+ return OPERATOR_CANCELLED;
+
+ /* BMESH_TODO make plane side this: sqrt(2.0f) - plane (diameter of 1.41 makes it unit size) */
+ make_prim_finish(C, &state, enter_editmode);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_cube_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Cube";
+ ot->description= "Construct a cube mesh.";
+ ot->idname= "MESH_OT_primitive_cube_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_cube_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+static int add_primitive_circle_exec(bContext *C, wmOperator *op)
+{
+#if 0
+ int enter_editmode;
+ float loc[3], rot[3];
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode);
+
+ make_prim_ext(C, loc, rot, enter_editmode,
+ PRIM_CIRCLE, RNA_int_get(op->ptr, "vertices"), 0, 0,
+ RNA_float_get(op->ptr,"radius"), 0.0f, 0,
+ RNA_boolean_get(op->ptr, "fill"));
+#endif
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_circle_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Circle";
+ ot->description= "Construct a circle mesh.";
+ ot->idname= "MESH_OT_primitive_circle_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_circle_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 3, 500);
+ RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
+ RNA_def_boolean(ot->srna, "fill", 0, "Fill", "");
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state;
+ int layer;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%i depth=%f mat=%m4",
+ RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"),
+ RNA_float_get(op->ptr, "radius"), (int)RNA_boolean_get(op->ptr, "cap_end"), RNA_float_get(op->ptr, "depth"), mat))
+ return OPERATOR_CANCELLED;
+
+ make_prim_finish(C, &state, enter_editmode);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_cylinder_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Tube";
+ ot->description= "Construct a tube mesh.";
+ ot->idname= "MESH_OT_primitive_tube_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_cylinder_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 2, 500);
+ RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
+ RNA_def_float(ot->srna, "depth", 1.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
+ RNA_def_boolean(ot->srna, "cap_ends", 1, "Cap Ends", "");
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+static int add_primitive_cone_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state;
+ int layer;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%i depth=%f mat=%m4",
+ RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"),
+ 0.0f, (int)RNA_boolean_get(op->ptr, "cap_end"), RNA_float_get(op->ptr, "depth"), mat))
+ return OPERATOR_CANCELLED;
+
+ make_prim_finish(C, &state, enter_editmode);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_cone_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Cone";
+ ot->description= "Construct a conic mesh (ends filled).";
+ ot->idname= "MESH_OT_primitive_cone_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_cone_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 2, 500);
+ RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
+ RNA_def_float(ot->srna, "depth", 1.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
+ RNA_def_boolean(ot->srna, "cap_end", 0, "Cap End", "");
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+static int add_primitive_grid_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state;
+ int layer;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_grid xsegments=%i ysegments=%i size=%f mat=%m4",
+ RNA_int_get(op->ptr, "x_subdivisions"),
+ RNA_int_get(op->ptr, "y_subdivisions"),
+ RNA_float_get(op->ptr, "size"), mat))
+ {
+ return OPERATOR_CANCELLED;
+ }
+
+ make_prim_finish(C, &state, enter_editmode);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_grid_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Grid";
+ ot->description= "Construct a grid mesh.";
+ ot->idname= "MESH_OT_primitive_grid_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_grid_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_int(ot->srna, "x_subdivisions", 10, INT_MIN, INT_MAX, "X Subdivisions", "", 3, 1000);
+ RNA_def_int(ot->srna, "y_subdivisions", 10, INT_MIN, INT_MAX, "Y Subdivisions", "", 3, 1000);
+ RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, FLT_MAX);
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state;
+ int layer;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout", "create_monkey mat=%m4", mat)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ make_prim_finish(C, &state, enter_editmode);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_monkey_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Monkey";
+ ot->description= "Construct a Suzanne mesh.";
+ ot->idname= "MESH_OT_primitive_monkey_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_monkey_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+
+static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state;
+ int layer;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_uvsphere segments=%i revolutions=%i diameter=%f mat=%m4",
+ RNA_int_get(op->ptr, "rings"), RNA_int_get(op->ptr, "segments"),
+ RNA_float_get(op->ptr,"size"), mat))
+ return OPERATOR_CANCELLED;
+
+ make_prim_finish(C, &state, enter_editmode);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add UV Sphere";
+ ot->description= "Construct a UV sphere mesh.";
+ ot->idname= "MESH_OT_primitive_uv_sphere_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_uvsphere_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_int(ot->srna, "segments", 32, INT_MIN, INT_MAX, "Segments", "", 3, 500);
+ RNA_def_int(ot->srna, "rings", 24, INT_MIN, INT_MAX, "Rings", "", 3, 500);
+ RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, 100.00);
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state;
+ int layer;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_icosphere subdivisions=%i diameter=%f mat=%m4",
+ RNA_int_get(op->ptr, "subdivisions"),
+ RNA_float_get(op->ptr, "size"), mat)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ make_prim_finish(C, &state, enter_editmode);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Ico Sphere";
+ ot->description= "Construct an Icosphere mesh.";
+ ot->idname= "MESH_OT_primitive_ico_sphere_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_icosphere_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_int(ot->srna, "subdivisions", 2, 0, 6, "Subdivisions", "", 0, 8);
+ RNA_def_float(ot->srna, "size", 1.0f, 0.0f, FLT_MAX, "Size", "", 0.001f, 100.00);
+
+ ED_object_add_generic_props(ot, TRUE);
+}
diff --git a/source/blender/editors/mesh/editbmesh_bvh.c b/source/blender/editors/mesh/editbmesh_bvh.c
new file mode 100644
index 00000000000..ba1ca4a440c
--- /dev/null
+++ b/source/blender/editors/mesh/editbmesh_bvh.c
@@ -0,0 +1,715 @@
+ /* $Id:
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2010 by Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#define IN_EDITMESHBVH
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_key_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "RNA_types.h"
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_heap.h"
+#include "BLI_array.h"
+#include "BLI_kdopbvh.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+#include "ED_view3d.h"
+#include "ED_util.h"
+#include "ED_screen.h"
+#include "ED_transform.h"
+
+#include "UI_interface.h"
+
+#include "mesh_intern.h"
+#include "bmesh.h"
+
+#include "editbmesh_bvh.h"
+
+typedef struct BMBVHTree {
+ BMEditMesh *em;
+ BMesh *bm;
+ BVHTree *tree;
+ float epsilon;
+ float maxdist; //for nearest point search
+
+ /*stuff for topological vert search*/
+ BMVert *v, *curv;
+ GHash *gh;
+ float curw, curd;
+ float co[3];
+ int curtag;
+} BMBVHTree;
+
+BMBVHTree *BMBVH_NewBVH(BMEditMesh *em)
+{
+ BMBVHTree *tree = MEM_callocN(sizeof(*tree), "BMBVHTree");
+ float cos[3][3];
+ int i;
+
+ BMEdit_RecalcTesselation(em);
+
+ tree->em = em;
+ tree->bm = em->bm;
+ tree->epsilon = FLT_EPSILON*2.0f;
+
+ tree->tree = BLI_bvhtree_new(em->tottri, tree->epsilon, 8, 8);
+
+ for (i=0; i<em->tottri; i++) {
+ VECCOPY(cos[0], em->looptris[i][0]->v->co);
+ VECCOPY(cos[1], em->looptris[i][1]->v->co);
+ VECCOPY(cos[2], em->looptris[i][2]->v->co);
+
+ BLI_bvhtree_insert(tree->tree, i, (float*)cos, 3);
+ }
+
+ BLI_bvhtree_balance(tree->tree);
+
+ return tree;
+}
+
+void BMBVH_FreeBVH(BMBVHTree *tree)
+{
+ BLI_bvhtree_free(tree->tree);
+ MEM_freeN(tree);
+}
+
+/*taken from bvhutils.c*/
+static float ray_tri_intersection(const BVHTreeRay *ray, const float UNUSED(m_dist), float *v0,
+ float *v1, float *v2, float *uv, float UNUSED(e))
+{
+ float dist;
+#if 0
+ float vv1[3], vv2[3], vv3[3], cent[3];
+
+ /*expand triangle by an epsilon. this is probably a really stupid
+ way of doing it, but I'm too tired to do better work.*/
+ VECCOPY(vv1, v0);
+ VECCOPY(vv2, v1);
+ VECCOPY(vv3, v2);
+
+ add_v3_v3v3(cent, vv1, vv2);
+ add_v3_v3v3(cent, cent, vv3);
+ mul_v3_fl(cent, 1.0f/3.0f);
+
+ sub_v3_v3v3(vv1, vv1, cent);
+ sub_v3_v3v3(vv2, vv2, cent);
+ sub_v3_v3v3(vv3, vv3, cent);
+
+ mul_v3_fl(vv1, 1.0f + e);
+ mul_v3_fl(vv2, 1.0f + e);
+ mul_v3_fl(vv3, 1.0f + e);
+
+ add_v3_v3v3(vv1, vv1, cent);
+ add_v3_v3v3(vv2, vv2, cent);
+ add_v3_v3v3(vv3, vv3, cent);
+
+ if(isect_ray_tri_v3((float*)ray->origin, (float*)ray->direction, vv1, vv2, vv3, &dist, uv))
+ return dist;
+#else
+ if(isect_ray_tri_v3((float*)ray->origin, (float*)ray->direction, v0, v1, v2, &dist, uv))
+ return dist;
+#endif
+
+ return FLT_MAX;
+}
+
+static void raycallback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+ BMBVHTree *tree = userdata;
+ BMLoop **ls = tree->em->looptris[index];
+ float dist, uv[2];
+
+ if (!ls[0] || !ls[1] || !ls[2])
+ return;
+
+ dist = ray_tri_intersection(ray, hit->dist, ls[0]->v->co, ls[1]->v->co,
+ ls[2]->v->co, uv, tree->epsilon);
+ if (dist < hit->dist) {
+ hit->dist = dist;
+ hit->index = index;
+
+ VECCOPY(hit->no, ls[0]->v->no);
+
+ copy_v3_v3(hit->co, ray->direction);
+ normalize_v3(hit->co);
+ mul_v3_fl(hit->co, dist);
+ add_v3_v3(hit->co, ray->origin);
+ }
+}
+
+BMFace *BMBVH_RayCast(BMBVHTree *tree, float *co, float *dir, float *hitout)
+{
+ BVHTreeRayHit hit;
+
+ hit.dist = FLT_MAX;
+ hit.index = -1;
+
+ BLI_bvhtree_ray_cast(tree->tree, co, dir, FLT_MAX, &hit, raycallback, tree);
+ if (hit.dist != FLT_MAX && hit.index != -1) {
+ if (hitout) {
+ VECCOPY(hitout, hit.co);
+ }
+
+ return tree->em->looptris[hit.index][0]->f;
+ }
+
+ return NULL;
+}
+
+BVHTree *BMBVH_BVHTree(BMBVHTree *tree)
+{
+ return tree->tree;
+}
+
+static void vertsearchcallback(void *userdata, int index, const float *UNUSED(co), BVHTreeNearest *hit)
+{
+ BMBVHTree *tree = userdata;
+ BMLoop **ls = tree->em->looptris[index];
+ float dist, maxdist, v[3];
+ int i;
+
+ maxdist = tree->maxdist;
+
+ for (i=0; i<3; i++) {
+ sub_v3_v3v3(v, hit->co, ls[i]->v->co);
+
+ dist = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
+ if (dist < hit->dist && dist < maxdist) {
+ VECCOPY(hit->co, ls[i]->v->co);
+ VECCOPY(hit->no, ls[i]->v->no);
+ hit->dist = dist;
+ }
+ }
+}
+
+BMVert *BMBVH_FindClosestVert(BMBVHTree *tree, float *co, float maxdist)
+{
+ BVHTreeNearest hit;
+
+ VECCOPY(hit.co, co);
+ hit.dist = maxdist*5;
+ hit.index = -1;
+
+ tree->maxdist = maxdist;
+
+ BLI_bvhtree_find_nearest(tree->tree, co, &hit, vertsearchcallback, tree);
+ if (hit.dist != FLT_MAX && hit.index != -1) {
+ BMLoop **ls = tree->em->looptris[hit.index];
+ float dist, curdist = tree->maxdist, v[3];
+ int cur=0, i;
+
+ maxdist = tree->maxdist;
+
+ for (i=0; i<3; i++) {
+ sub_v3_v3v3(v, hit.co, ls[i]->v->co);
+
+ dist = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
+ if (dist < curdist) {
+ cur = i;
+ curdist = dist;
+ }
+ }
+
+ return ls[i]->v;
+ }
+
+ return NULL;
+}
+
+typedef struct walklist {
+ BMVert *v;
+ int valence;
+ int depth;
+ float w, r;
+ int totwalked;
+
+ /*state data*/
+ BMVert *lastv;
+ BMLoop *curl, *firstl;
+ BMEdge *cure;
+} walklist;
+
+
+static short winding(float *v1, float *v2, float *v3)
+/* is v3 to the right of v1-v2 ? With exception: v3==v1 || v3==v2 */
+{
+ double inp;
+
+ //inp= (v2[cox]-v1[cox])*(v1[coy]-v3[coy]) +(v1[coy]-v2[coy])*(v1[cox]-v3[cox]);
+ inp= (v2[0]-v1[0])*(v1[1]-v3[1]) +(v1[1]-v2[1])*(v1[0]-v3[0]);
+
+ if(inp<0.0) return 0;
+ else if(inp==0) {
+ if(v1[0]==v3[0] && v1[1]==v3[1]) return 0;
+ if(v2[0]==v3[0] && v2[1]==v3[1]) return 0;
+ }
+ return 1;
+}
+
+static float topo_compare(BMesh *bm, BMVert *v1, BMVert *v2)
+{
+ BMIter iter1, iter2;
+ BMEdge *e1, *e2, *cure1 = NULL, *cure2 = NULL;
+ BMLoop *l1, *l2;
+ BMVert *lastv1, *lastv2;
+ GHash *gh;
+ walklist *stack1=NULL, *stack2=NULL;
+ BLI_array_declare(stack1);
+ BLI_array_declare(stack2);
+ float vec1[3], vec2[3], minangle=FLT_MAX, w;
+ int lvl=1;
+ static int maxlevel = 3;
+
+ /*ok. see how similar v is to v2, based on topological similaritys in the local
+ topological neighborhood*/
+
+ /*step 1: find two edges, one that contains v and one that contains v2, with the
+ smallest angle between the two edges*/
+
+ BM_ITER(e1, &iter1, bm, BM_EDGES_OF_VERT, v1) {
+ BM_ITER(e2, &iter2, bm, BM_EDGES_OF_VERT, v2) {
+ float angle;
+
+ if (e1->v1 == e2->v1 || e1->v2 == e2->v2 || e1->v1 == e2->v2 || e1->v2 == e2->v1)
+ continue;
+
+ sub_v3_v3v3(vec1, BM_OtherEdgeVert(e1, v1)->co, v1->co);
+ sub_v3_v3v3(vec2, BM_OtherEdgeVert(e2, v2)->co, v2->co);
+
+ angle = fabs(angle_v3v3(vec1, vec2));
+
+ if (angle < minangle) {
+ minangle = angle;
+ cure1 = e1;
+ cure2 = e2;
+ }
+ }
+ }
+
+ if (!cure1 || !cure1->l || !cure2->l) {
+ /*just return 1.0 in this case*/
+ return 1.0f;
+ }
+
+ /*assumtions
+
+ we assume a 2-manifold mesh here. if at any time this isn't the case,
+ e.g. a hole or an edge with more then 2 faces around it, we um ignore
+ that edge I guess, and try to make the algorithm go around as necassary.*/
+
+ l1 = cure1->l;
+ l2 = cure2->l;
+
+ lastv1 = l1->v == v1 ? ((BMLoop*)l1->next)->v : ((BMLoop*)l1->prev)->v;
+ lastv2 = l2->v == v2 ? ((BMLoop*)l2->next)->v : ((BMLoop*)l2->prev)->v;
+
+ /*we can only provide meaningful comparisons if v1 and v2 have the same valence*/
+ if (BM_Vert_EdgeCount(v1) != BM_Vert_EdgeCount(v2))
+ return 1.0f; /*full mismatch*/
+
+ gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh bvh");
+
+#define SPUSH(s, d, vt, lv, e)\
+ if (BLI_array_count(s) <= lvl) BLI_array_growone(s);\
+ memset((s+lvl), 0, sizeof(*s));\
+ s[lvl].depth = d;\
+ s[lvl].v = vt;\
+ s[lvl].cure = e;\
+ s[lvl].lastv = lv;\
+ s[lvl].valence = BM_Vert_EdgeCount(vt);\
+
+ lvl = 0;
+
+ SPUSH(stack1, 0, v1, lastv1, cure1);
+ SPUSH(stack2, 0, v2, lastv2, cure2);
+
+ BLI_srand( BLI_rand() ); /* random seed */
+
+ lvl = 1;
+ while (lvl) {
+ int term = 0;
+ walklist *s1 = stack1 + lvl - 1, *s2 = stack2 + lvl - 1;
+
+ /*pop from the stack*/
+ lvl--;
+
+ if (s1->curl && s1->curl->e == s1->cure)
+ term = 1;
+ if (s2->curl && s2->curl->e == s2->cure)
+ term = 1;
+
+ /*find next case to do*/
+ if (!s1->curl)
+ s1->curl = s1->cure->l;
+ if (!s2->curl) {
+ float no1[3], no2[3], angle;
+ int wind1, wind2;
+
+ s2->curl = s2->cure->l;
+
+ /*find which of two possible faces to use*/
+ l1 = BM_OtherFaceLoop(s1->curl->e, s1->curl->f, s1->lastv);
+ l2 = BM_OtherFaceLoop(s2->curl->e, s2->curl->f, s2->lastv);
+
+ if (l1->v == s2->lastv) {
+ l1 = (BMLoop*) l1->next;
+ if (l1->v == s2->v)
+ l1 = (BMLoop*) l1->prev->prev;
+ } else if (l1->v == s2->v) {
+ l1 = (BMLoop*) l1->next;
+ if (l1->v == s2->lastv)
+ l1 = (BMLoop*) l1->prev->prev;
+ }
+
+ if (l2->v == s2->lastv) {
+ l2 = (BMLoop*) l2->next;
+ if (l2->v == s2->v)
+ l2 = (BMLoop*) l2->prev->prev;
+ } else if (l2->v == s2->v) {
+ l2 = (BMLoop*) l2->next;
+ if (l2->v == s2->lastv)
+ l2 = (BMLoop*) l2->prev->prev;
+ }
+
+ wind1 = winding(s1->v->co, s1->lastv->co, l1->v->co);
+
+ wind2 = winding(s2->v->co, s2->lastv->co, l2->v->co);
+
+ /*if angle between the two adjacent faces is greater then 90 degrees,
+ we need to flip wind2*/
+ l1 = l2;
+ l2 = s2->curl->radial_next;
+ l2 = BM_OtherFaceLoop(l2->e, l2->f, s2->lastv);
+
+ if (l2->v == s2->lastv) {
+ l2 = (BMLoop*) l2->next;
+ if (l2->v == s2->v)
+ l2 = (BMLoop*) l2->prev->prev;
+ } else if (l2->v == s2->v) {
+ l2 = (BMLoop*) l2->next;
+ if (l2->v == s2->lastv)
+ l2 = (BMLoop*) l2->prev->prev;
+ }
+
+ normal_tri_v3(no1, s2->v->co, s2->lastv->co, l1->v->co);
+ normal_tri_v3(no2, s2->v->co, s2->lastv->co, l2->v->co);
+
+ /*enforce identical winding as no1*/
+ mul_v3_fl(no2, -1.0);
+
+ angle = angle_v3v3(no1, no2);
+ if (angle > M_PI/2 - FLT_EPSILON*2)
+ wind2 = !wind2;
+
+ if (wind1 == wind2)
+ s2->curl = s2->curl->radial_next;
+ }
+
+ /*handle termination cases of having already looped through all child
+ nodes, or the valence mismatching between v1 and v2, or we hit max
+ recursion depth*/
+ term |= s1->valence != s2->valence || lvl+1 > maxlevel;
+ term |= s1->curl->radial_next == (BMLoop*)l1;
+ term |= s2->curl->radial_next == (BMLoop*)l2;
+
+ if (!term) {
+ lastv1 = s1->v;
+ lastv2 = s2->v;
+ v1 = BM_OtherEdgeVert(s1->curl->e, lastv1);
+ v2 = BM_OtherEdgeVert(s2->curl->e, lastv2);
+
+ e1 = s1->curl->e;
+ e2 = s2->curl->e;
+
+ if (!BLI_ghash_haskey(gh, v1) && !BLI_ghash_haskey(gh, v2)) {
+ /*repush the current stack item*/
+ lvl++;
+
+ //if (maxlevel % 2 == 0) {
+ BLI_ghash_insert(gh, v1, NULL);
+ BLI_ghash_insert(gh, v2, NULL);
+ //}
+
+ /*now push the child node*/
+ SPUSH(stack1, lvl, v1, lastv1, e1);
+ SPUSH(stack2, lvl, v2, lastv2, e2);
+
+ lvl++;
+
+ s1 = stack1 + lvl - 2;
+ s2 = stack2 + lvl - 2;
+ }
+
+ s1->curl = s1->curl->v == s1->v ? (BMLoop*) s1->curl->prev : (BMLoop*) s1->curl->next;
+ s2->curl = s2->curl->v == s2->v ? (BMLoop*) s2->curl->prev : (BMLoop*) s2->curl->next;
+
+ s1->curl = (BMLoop*) s1->curl->radial_next;
+ s2->curl = (BMLoop*) s2->curl->radial_next;
+ }
+
+#define WADD(stack, s)\
+ if (lvl) {/*silly attempt to make this non-commutative: randomize\
+ how much this particular weight adds to the total*/\
+ stack[lvl-1].r += r;\
+ s->w *= r;\
+ stack[lvl-1].totwalked++;\
+ stack[lvl-1].w += s->w;\
+ }
+
+ /*if no next case to do, update parent weight*/
+ if (term) {
+ float r = 0.8f + BLI_frand()*0.2f - FLT_EPSILON;
+
+ if (s1->totwalked) {
+ s1->w /= s1->r;
+ } else
+ s1->w = s1->valence == s2->valence ? 1.0f : 0.0f;
+
+ WADD(stack1, s1);
+
+ if (s2->totwalked) {
+ s2->w /= s2->r;
+ } else
+ s2->w = s1->valence == s2->valence ? 1.0f : 0.0f;
+
+ WADD(stack2, s2);
+
+ /*apply additional penalty to weight mismatch*/
+ if (s2->w != s1->w)
+ s2->w *= 0.8f;
+ }
+ }
+
+ w = (stack1[0].w + stack2[0].w)*0.5f;
+
+ BLI_array_free(stack1);
+ BLI_array_free(stack2);
+
+ BLI_ghash_free(gh, NULL, NULL);
+
+ return 1.0f - w;
+}
+
+static void vertsearchcallback_topo(void *userdata, int index, const float *UNUSED(co), BVHTreeNearest *UNUSED(hit))
+{
+ BMBVHTree *tree = userdata;
+ BMLoop **ls = tree->em->looptris[index];
+ int i;
+ float maxdist, vec[3], w;
+
+ maxdist = tree->maxdist;
+
+ for (i=0; i<3; i++) {
+ float dis;
+
+ if (BLI_ghash_haskey(tree->gh, ls[i]->v))
+ continue;
+
+ sub_v3_v3v3(vec, tree->co, ls[i]->v->co);
+ dis = dot_v3v3(vec, vec);
+
+ w = topo_compare(tree->em->bm, tree->v, ls[i]->v);
+ tree->curtag++;
+
+ if (w < tree->curw-FLT_EPSILON*4) {
+ tree->curw = w;
+ tree->curv = ls[i]->v;
+
+ sub_v3_v3v3(vec, tree->co, ls[i]->v->co);
+ tree->curd = dot_v3v3(vec, vec);
+
+ /*we deliberately check for equality using (smallest possible float)*4
+ comparison factor, to always prefer distance in cases of verts really
+ close to each other*/
+ } else if (fabs(tree->curw - w) < FLT_EPSILON*4) {
+ /*if w is equal to hitex->curw, sort by distance*/
+ sub_v3_v3v3(vec, tree->co, ls[i]->v->co);
+ dis = dot_v3v3(vec, vec);
+
+ if (dis < tree->curd) {
+ tree->curd = dis;
+ tree->curv = ls[i]->v;
+ }
+ }
+
+ BLI_ghash_insert(tree->gh, ls[i]->v, NULL);
+ }
+}
+
+BMVert *BMBVH_FindClosestVertTopo(BMBVHTree *tree, float *co, float maxdist, BMVert *sourcev)
+{
+ BVHTreeNearest hit;
+
+ memset(&hit, 0, sizeof(hit));
+
+ VECCOPY(hit.co, co);
+ VECCOPY(tree->co, co);
+ hit.index = -1;
+ hit.dist = maxdist;
+
+ tree->curw = FLT_MAX;
+ tree->curd = FLT_MAX;
+ tree->curv = NULL;
+ tree->curtag = 1;
+
+ tree->gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh bvh");
+
+ tree->maxdist = maxdist;
+ tree->v = sourcev;
+
+ BLI_bvhtree_find_nearest(tree->tree, co, &hit, vertsearchcallback_topo, tree);
+
+ BLI_ghash_free(tree->gh, NULL, NULL);
+ tree->gh = NULL;
+
+ return tree->curv;
+}
+
+
+#if 0 //BMESH_TODO: not implemented yet
+int BMBVH_VertVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d)
+{
+
+}
+#endif
+
+static BMFace *edge_ray_cast(BMBVHTree *tree, float *co, float *dir, float *hitout, BMEdge *e)
+{
+ BMFace *f = BMBVH_RayCast(tree, co, dir, hitout);
+
+ if (f && BM_Edge_In_Face(f, e))
+ return NULL;
+
+ return f;
+}
+
+void scale_point(float *c1, float *p, float s)
+{
+ sub_v3_v3(c1, p);
+ mul_v3_fl(c1, s);
+ add_v3_v3(c1, p);
+}
+
+int BMBVH_EdgeVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d, Object *obedit)
+{
+ BMFace *f;
+ float co1[3], co2[3], co3[3], dir1[4], dir2[4], dir3[4];
+ float origin[3], invmat[4][4];
+ float epsilon = 0.01f;
+
+ VECCOPY(origin, r3d->viewinv[3]);
+ invert_m4_m4(invmat, obedit->obmat);
+ mul_m4_v3(invmat, origin);
+
+ VECCOPY(co1, e->v1->co);
+ add_v3_v3v3(co2, e->v1->co, e->v2->co);
+ mul_v3_fl(co2, 0.5f);
+ VECCOPY(co3, e->v2->co);
+
+ scale_point(co1, co2, 0.99);
+ scale_point(co3, co2, 0.99);
+
+ /*ok, idea is to generate rays going from the camera origin to the
+ three points on the edge (v1, mid, v2)*/
+ sub_v3_v3v3(dir1, origin, co1);
+ sub_v3_v3v3(dir2, origin, co2);
+ sub_v3_v3v3(dir3, origin, co3);
+
+ normalize_v3(dir1);
+ normalize_v3(dir2);
+ normalize_v3(dir3);
+
+ mul_v3_fl(dir1, epsilon);
+ mul_v3_fl(dir2, epsilon);
+ mul_v3_fl(dir3, epsilon);
+
+ /*offset coordinates slightly along view vectors, to avoid
+ hitting the faces that own the edge.*/
+ add_v3_v3v3(co1, co1, dir1);
+ add_v3_v3v3(co2, co2, dir2);
+ add_v3_v3v3(co3, co3, dir3);
+
+ normalize_v3(dir1);
+ normalize_v3(dir2);
+ normalize_v3(dir3);
+
+ /*do three samplings: left, middle, right*/
+ f = edge_ray_cast(tree, co1, dir1, NULL, e);
+ if (f && !edge_ray_cast(tree, co2, dir2, NULL, e))
+ return 1;
+ else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e))
+ return 1;
+ else if (!f)
+ return 1;
+
+ return 0;
+}
diff --git a/source/blender/editors/mesh/editbmesh_bvh.h b/source/blender/editors/mesh/editbmesh_bvh.h
new file mode 100644
index 00000000000..03a616f1e87
--- /dev/null
+++ b/source/blender/editors/mesh/editbmesh_bvh.h
@@ -0,0 +1,31 @@
+#ifndef _EDITBMESH_BVH
+#define _EDITBMESH_BVH
+
+struct BMEditMesh;
+struct BMFace;
+struct BMEdge;
+struct BMVert;
+struct RegionView3D;
+struct BMBVHTree;
+struct BVHTree;
+
+#ifndef IN_EDITMESHBVH
+typedef struct BMBVHTree BMBVHTree;
+#endif
+
+struct BMBVHTree *BMBVH_NewBVH(struct BMEditMesh *em);
+void BMBVH_FreeBVH(struct BMBVHTree *tree);
+struct BVHTree *BMBVH_BVHTree(struct BMBVHTree *tree);
+
+struct BMFace *BMBVH_RayCast(struct BMBVHTree *tree, float *co, float *dir, float *hitout);
+
+int BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e,
+ struct RegionView3D *r3d, struct Object *obedit);
+
+#define BM_SEARCH_MAXDIST 0.4f
+
+/*find a vert closest to co in a sphere of radius maxdist*/
+struct BMVert *BMBVH_FindClosestVert(struct BMBVHTree *tree, float *co, float maxdist);
+struct BMVert *BMBVH_FindClosestVertTopo(struct BMBVHTree *tree, float *co,
+ float maxdist, struct BMVert *sourcev);
+#endif /* _EDITBMESH_H */
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 552f4b3b954..c692466a1ef 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
@@ -49,6 +49,7 @@
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_context.h"
+#include "BKE_tessmesh.h"
#include "BIF_gl.h"
@@ -68,40 +69,53 @@ void paintface_flush_flags(Object *ob)
{
Mesh *me= get_mesh(ob);
DerivedMesh *dm= ob->derivedFinal;
- MFace *faces, *mf, *mf_orig;
- int *index_array = NULL;
+ MPoly *faces, *mf, *mf_orig;
+ DMFaceIter *fiter;
+ int *index = NULL;
int totface;
int i;
if(me==NULL || dm==NULL)
return;
- index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX);
-
- if(!index_array)
- return;
-
- faces = dm->getFaceArray(dm);
+ fiter = dm->newFaceIter(dm);
totface = dm->getNumFaces(dm);
-
- mf= faces;
-
- for (i= 0; i<totface; i++, mf++) { /* loop over derived mesh faces */
- mf_orig= me->mface + index_array[i];
- mf->flag= mf_orig->flag;
+
+ for (i=0; !fiter->done; fiter->step(fiter), i++) {
+ index = fiter->getCDData(fiter, CD_ORIGINDEX, -1);
+ if (!index) {
+ fiter->free(fiter);
+ return;
+ }
+
+ mf_orig = me->mpoly + *index;
+ fiter->flags = mf_orig->flag;
}
+
+ fiter->free(fiter);
}
/* returns 0 if not found, otherwise 1 */
-static int facesel_face_pick(struct bContext *C, Mesh *me, short *mval, unsigned int *index, short rect)
+static int facesel_face_pick(struct bContext *C, Mesh *me, Object *ob, short *mval, unsigned int *index, short rect)
{
+ Scene *scene = CTX_data_scene(C);
ViewContext vc;
view3d_set_viewcontext(C, &vc);
- if (!me || me->totface==0)
+ if (!me || me->totpoly==0)
return 0;
-// XXX if (v3d->flag & V3D_INVALID_BACKBUF) {
+ /*we can't assume mfaces have a correct origindex layer that indices to mpolys.
+ so instead we have to regenerate the tesselation faces altogether.
+
+ the final 0, 0 paramters causes it to use the index of each mpoly, instead
+ of reading from the origindex layer.*/
+ me->totface = mesh_recalcTesselation(&me->fdata, &me->ldata, &me->pdata,
+ me->mvert, me->totface, me->totloop, me->totpoly, 0, 0);
+ mesh_update_customdata_pointers(me);
+ makeDerivedMesh(scene, ob, NULL, CD_MASK_BAREMESH);
+
+ // XXX if (v3d->flag & V3D_INVALID_BACKBUF) {
// XXX drawview.c! check_backbuf();
// XXX persp(PERSP_VIEW);
// XXX }
@@ -118,7 +132,7 @@ static int facesel_face_pick(struct bContext *C, Mesh *me, short *mval, unsigned
*index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
}
- if ((*index)<=0 || (*index)>(unsigned int)me->totface)
+ if ((*index)<=0 || (*index)>(unsigned int)me->totpoly)
return 0;
(*index)--;
@@ -128,41 +142,37 @@ static int facesel_face_pick(struct bContext *C, Mesh *me, short *mval, unsigned
/* last_sel, use em->act_face otherwise get the last selected face in the editselections
* at the moment, last_sel is mainly useful for gaking sure the space image dosnt flicker */
-MTFace *EM_get_active_mtface(EditMesh *em, EditFace **act_efa, MCol **mcol, int sloppy)
+MTexPoly *EDBM_get_active_mtface(BMEditMesh *em, BMFace **act_efa, int sloppy)
{
- EditFace *efa = NULL;
+ BMFace *efa = NULL;
+ BMLoop *l;
+ BMIter iter, liter;
- if(!EM_texFaceCheck(em))
+ if(!EDBM_texFaceCheck(em))
return NULL;
- efa = EM_get_actFace(em, sloppy);
+ efa = EDBM_get_actFace(em, sloppy);
if (efa) {
- if (mcol) {
- if (CustomData_has_layer(&em->fdata, CD_MCOL))
- *mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
- else
- *mcol = NULL;
- }
if (act_efa) *act_efa = efa;
- return CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ return CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
}
+
if (act_efa) *act_efa= NULL;
- if(mcol) *mcol = NULL;
return NULL;
}
void paintface_hide(Object *ob, const int unselected)
{
Mesh *me;
- MFace *mface;
+ MPoly *mface;
int a;
me= get_mesh(ob);
- if(me==0 || me->totface==0) return;
+ if(me==0 || me->totpoly==0) return;
- mface= me->mface;
- a= me->totface;
+ mface= me->mpoly;
+ a= me->totpoly;
while(a--) {
if((mface->flag & ME_HIDE) == 0) {
if(unselected) {
@@ -184,14 +194,14 @@ void paintface_hide(Object *ob, const int unselected)
void paintface_reveal(Object *ob)
{
Mesh *me;
- MFace *mface;
+ MPoly *mface;
int a;
me= get_mesh(ob);
- if(me==0 || me->totface==0) return;
+ if(me==0 || me->totpoly==0) return;
- mface= me->mface;
- a= me->totface;
+ mface= me->mpoly;
+ a= me->totpoly;
while(a--) {
if(mface->flag & ME_HIDE) {
mface->flag |= ME_FACE_SEL;
@@ -205,30 +215,30 @@ void paintface_reveal(Object *ob)
/* Set tface seams based on edge data, uses hash table to find seam edges. */
-static void hash_add_face(EdgeHash *ehash, MFace *mf)
+static void hash_add_face(EdgeHash *ehash, MPoly *mf, MLoop *mloop)
{
- BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL);
- BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL);
- if(mf->v4) {
- BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL);
- BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL);
- }
- else
- BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL);
+ MLoop *ml, *ml2;
+ int i;
+
+ for (i=0, ml=mloop; i<mf->totloop; i++, ml++) {
+ ml2 = mloop + (i+1) % mf->totloop;
+ BLI_edgehash_insert(ehash, ml->v, ml2->v, NULL);
+ }
}
static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index)
{
- MFace *mf;
- int a, doit=1, mark=0;
- char *linkflag;
EdgeHash *ehash, *seamhash;
+ MPoly *mf;
+ MLoop *ml;
MEdge *med;
+ char *linkflag;
+ int a, b, doit=1, mark=0;
ehash= BLI_edgehash_new();
seamhash = BLI_edgehash_new();
- linkflag= MEM_callocN(sizeof(char)*me->totface, "linkflaguv");
+ linkflag= MEM_callocN(sizeof(char)*me->totpoly, "linkflaguv");
for(med=me->medge, a=0; a < me->totedge; a++, med++)
if(med->flag & ME_SEAM)
@@ -236,17 +246,17 @@ static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int ind
if (mode==0 || mode==1) {
/* only put face under cursor in array */
- mf= ((MFace*)me->mface) + index;
- hash_add_face(ehash, mf);
+ mf= ((MPoly*)me->mpoly) + index;
+ hash_add_face(ehash, mf, me->mloop + mf->loopstart);
linkflag[index]= 1;
}
else {
/* fill array by selection */
- mf= me->mface;
- for(a=0; a<me->totface; a++, mf++) {
+ mf= me->mpoly;
+ for(a=0; a<me->totpoly; a++, mf++) {
if(mf->flag & ME_HIDE);
else if(mf->flag & ME_FACE_SEL) {
- hash_add_face(ehash, mf);
+ hash_add_face(ehash, mf, me->mloop + mf->loopstart);
linkflag[a]= 1;
}
}
@@ -256,35 +266,26 @@ static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int ind
doit= 0;
/* expand selection */
- mf= me->mface;
- for(a=0; a<me->totface; a++, mf++) {
+ mf= me->mpoly;
+ for(a=0; a<me->totpoly; a++, mf++) {
if(mf->flag & ME_HIDE)
continue;
if(!linkflag[a]) {
+ MLoop *mnextl;
mark= 0;
- if(!BLI_edgehash_haskey(seamhash, mf->v1, mf->v2))
- if(BLI_edgehash_haskey(ehash, mf->v1, mf->v2))
- mark= 1;
- if(!BLI_edgehash_haskey(seamhash, mf->v2, mf->v3))
- if(BLI_edgehash_haskey(ehash, mf->v2, mf->v3))
- mark= 1;
- if(mf->v4) {
- if(!BLI_edgehash_haskey(seamhash, mf->v3, mf->v4))
- if(BLI_edgehash_haskey(ehash, mf->v3, mf->v4))
- mark= 1;
- if(!BLI_edgehash_haskey(seamhash, mf->v4, mf->v1))
- if(BLI_edgehash_haskey(ehash, mf->v4, mf->v1))
- mark= 1;
+ ml = me->mloop + mf->loopstart;
+ for (b=0; b<mf->totloop; b++, ml++) {
+ mnextl = b < mf->totloop-1 ? ml - 1 : me->mloop + mf->loopstart;
+ if (!BLI_edgehash_haskey(seamhash, ml->v, mnextl->v))
+ if (!BLI_edgehash_haskey(ehash, ml->v, mnextl->v))
+ mark = 1;
}
- else if(!BLI_edgehash_haskey(seamhash, mf->v3, mf->v1))
- if(BLI_edgehash_haskey(ehash, mf->v3, mf->v1))
- mark = 1;
if(mark) {
linkflag[a]= 1;
- hash_add_face(ehash, mf);
+ hash_add_face(ehash, mf, me->mloop + mf->loopstart);
doit= 1;
}
}
@@ -296,24 +297,24 @@ static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int ind
BLI_edgehash_free(seamhash, NULL);
if(mode==0 || mode==2) {
- for(a=0, mf=me->mface; a<me->totface; a++, mf++)
+ for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++)
if(linkflag[a])
mf->flag |= ME_FACE_SEL;
else
mf->flag &= ~ME_FACE_SEL;
}
else if(mode==1) {
- for(a=0, mf=me->mface; a<me->totface; a++, mf++)
+ for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++)
if(linkflag[a] && (mf->flag & ME_FACE_SEL))
break;
- if (a<me->totface) {
- for(a=0, mf=me->mface; a<me->totface; a++, mf++)
+ if (a<me->totpoly) {
+ for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++)
if(linkflag[a])
mf->flag &= ~ME_FACE_SEL;
}
else {
- for(a=0, mf=me->mface; a<me->totface; a++, mf++)
+ for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++)
if(linkflag[a])
mf->flag |= ME_FACE_SEL;
}
@@ -328,7 +329,7 @@ void paintface_select_linked(bContext *UNUSED(C), Object *ob, short UNUSED(mval[
unsigned int index=0;
me = get_mesh(ob);
- if(me==0 || me->totface==0) return;
+ if(me==0 || me->totpoly==0) return;
if (mode==0 || mode==1) {
// XXX - Causes glitches, not sure why
@@ -347,28 +348,27 @@ void paintface_select_linked(bContext *UNUSED(C), Object *ob, short UNUSED(mval[
void paintface_deselect_all_visible(Object *ob, int action, short flush_flags)
{
Mesh *me;
- MFace *mface;
+ MPoly *mface;
int a;
me= get_mesh(ob);
if(me==0) return;
if(action == SEL_INVERT) {
- mface= me->mface;
- a= me->totface;
+ mface= me->mpoly;
+ a= me->totpoly;
while(a--) {
if((mface->flag & ME_HIDE) == 0) {
mface->flag ^= ME_FACE_SEL;
}
mface++;
}
- }
- else {
+ } else {
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
- mface= me->mface;
- a= me->totface;
+ mface= me->mpoly;
+ a= me->totpoly;
while(a--) {
if((mface->flag & ME_HIDE) == 0 && mface->flag & ME_FACE_SEL) {
action = SEL_DESELECT;
@@ -377,55 +377,65 @@ void paintface_deselect_all_visible(Object *ob, int action, short flush_flags)
mface++;
}
}
-
- mface= me->mface;
- a= me->totface;
- while(a--) {
- if((mface->flag & ME_HIDE) == 0) {
- switch (action) {
- case SEL_SELECT:
- mface->flag |= ME_FACE_SEL;
- break;
- case SEL_DESELECT:
- mface->flag &= ~ME_FACE_SEL;
- break;
- case SEL_INVERT:
- mface->flag ^= ME_FACE_SEL;
- break;
- }
- }
- mface++;
- }
}
- if(flush_flags) {
- paintface_flush_flags(ob);
+ //BMESH_TODO object_facesel_flush_dm(ob);
+// XXX notifier! object_tface_flags_changed(OBACT, 0);
+}
+
+void selectswap_tface(Scene *scene)
+{
+ Mesh *me;
+ MPoly *mface;
+ int a;
+
+ me= get_mesh(OBACT);
+ if(me==0) return;
+
+ mface= me->mpoly;
+ a= me->totpoly;
+ while(a--) {
+ if(mface->flag & ME_HIDE);
+ else {
+ if(mface->flag & ME_FACE_SEL) mface->flag &= ~ME_FACE_SEL;
+ else mface->flag |= ME_FACE_SEL;
+ }
}
}
int paintface_minmax(Object *ob, float *min, float *max)
{
- Mesh *me= get_mesh(ob);
- MFace *mf;
+ Mesh *me;
+ MPoly *mf;
+ MTexPoly *tf;
+ MLoop *ml;
MVert *mv;
- int a, ok=0;
- float vec[3];
+ int a, b, ok=0;
+ float vec[3], bmat[3][3];
- if(me==NULL)
- return ok;
+ me= get_mesh(ob);
+ if(!me || !me->mtpoly) return ok;
+
+ copy_m3_m4(bmat, ob->obmat);
mv= me->mvert;
- mf= me->mface;
- for (a=me->totface; a>0; a--, mf++) {
- if ((mf->flag & ME_HIDE || !(mf->flag & ME_FACE_SEL)) == 0) {
- int i= mf->v4 ? 3:2;
- do {
- mul_v3_m4v3(vec, ob->obmat, (mv + (*(&mf->v1 + i)))->co);
- DO_MINMAX(vec, min, max);
- } while (i--);
- ok= 1;
+ mf= me->mpoly;
+ tf= me->mtpoly;
+ for (a=me->totpoly; a>0; a--, mf++, tf++) {
+ if (mf->flag & ME_HIDE || !(mf->flag & ME_FACE_SEL))
+ continue;
+
+ ml = me->mloop + mf->totloop;
+ for (b=0; b<mf->totloop; b++, ml++) {
+ VECCOPY(vec, (mv+ml->v)->co);
+ mul_m3_v3(bmat, vec);
+ add_v3_v3v3(vec, vec, ob->obmat[3]);
+ DO_MINMAX(vec, min, max);
}
+
+ ok= 1;
}
+
return ok;
}
@@ -433,12 +443,12 @@ int paintface_minmax(Object *ob, float *min, float *max)
#define ME_SEAM_DONE 2 /* reuse this flag */
-static float edgetag_cut_cost(int e1, int e2, int vert)
+static float edgetag_cut_cost(BMEditMesh *em, int e1, int e2, int vert)
{
- EditVert *v = EM_get_vert_for_index(vert);
- EditEdge *eed1 = EM_get_edge_for_index(e1), *eed2 = EM_get_edge_for_index(e2);
- EditVert *v1 = EM_get_vert_for_index( (eed1->v1->tmp.l == vert)? eed1->v2->tmp.l: eed1->v1->tmp.l );
- EditVert *v2 = EM_get_vert_for_index( (eed2->v1->tmp.l == vert)? eed2->v2->tmp.l: eed2->v1->tmp.l );
+ BMVert *v = EDBM_get_vert_for_index(em, vert);
+ BMEdge *eed1 = EDBM_get_edge_for_index(em, e1), *eed2 = EDBM_get_edge_for_index(em, e2);
+ BMVert *v1 = EDBM_get_vert_for_index(em, (BMINDEX_GET(eed1->v1) == vert)? BMINDEX_GET(eed1->v2): BMINDEX_GET(eed1->v1) );
+ BMVert *v2 = EDBM_get_vert_for_index(em, (BMINDEX_GET(eed2->v1) == vert)? BMINDEX_GET(eed2->v2): BMINDEX_GET(eed2->v1) );
float cost, d1[3], d2[3];
cost = len_v3v3(v1->co, v->co);
@@ -452,19 +462,20 @@ static float edgetag_cut_cost(int e1, int e2, int vert)
return cost;
}
-static void edgetag_add_adjacent(Heap *heap, int mednum, int vertnum, int *nedges, int *edges, int *prevedge, float *cost)
+static void edgetag_add_adjacent(BMEditMesh *em, Heap *heap, int mednum, int vertnum,
+ int *nedges, int *edges, int *prevedge, float *cost)
{
int startadj, endadj = nedges[vertnum+1];
for (startadj = nedges[vertnum]; startadj < endadj; startadj++) {
int adjnum = edges[startadj];
- EditEdge *eedadj = EM_get_edge_for_index(adjnum);
+ BMEdge *eedadj = EDBM_get_edge_for_index(em, adjnum);
float newcost;
- if (eedadj->f2 & ME_SEAM_DONE)
+ if (eedadj->head.flags[0].f & ME_SEAM_DONE)
continue;
- newcost = cost[mednum] + edgetag_cut_cost(mednum, adjnum, vertnum);
+ newcost = cost[mednum] + edgetag_cut_cost(em, mednum, adjnum, vertnum);
if (cost[adjnum] > newcost) {
cost[adjnum] = newcost;
@@ -474,72 +485,94 @@ static void edgetag_add_adjacent(Heap *heap, int mednum, int vertnum, int *nedge
}
}
-void edgetag_context_set(Scene *scene, EditEdge *eed, int val)
+void edgetag_context_set(BMEditMesh *em, Scene *scene, BMEdge *eed, int val)
{
switch (scene->toolsettings->edge_mode) {
case EDGE_MODE_SELECT:
- EM_select_edge(eed, val);
+ BM_Select(em->bm, eed, val);
break;
case EDGE_MODE_TAG_SEAM:
- if (val) {eed->seam = 255;}
- else {eed->seam = 0;}
+ if (val) {BM_SetHFlag(eed, BM_SEAM);}
+ else {BM_ClearHFlag(eed, BM_SEAM);}
break;
case EDGE_MODE_TAG_SHARP:
- if (val) {eed->sharp = 1;}
- else {eed->sharp = 0;}
+ if (val) {BM_SetHFlag(eed, BM_SEAM);}
+ else {BM_ClearHFlag(eed, BM_SEAM);}
break;
- case EDGE_MODE_TAG_CREASE:
- if (val) {eed->crease = 1.0f;}
- else {eed->crease = 0.0f;}
+ case EDGE_MODE_TAG_CREASE:
+ {
+ float *crease = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE);
+
+ if (val) {*crease = 1.0f;}
+ else {*crease = 0.0f;}
break;
+ }
case EDGE_MODE_TAG_BEVEL:
- if (val) {eed->bweight = 1.0f;}
- else {eed->bweight = 0.0f;}
+ {
+ float *bweight = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_BWEIGHT);
+
+ if (val) {*bweight = 1.0f;}
+ else {*bweight = 0.0f;}
break;
+ }
}
}
-int edgetag_context_check(Scene *scene, EditEdge *eed)
+static float bm_cdata_get_single_float(BMesh *bm, CustomData *cdata, void *element, int type)
+{
+ BMHeader *ele = element;
+ float *f;
+
+ if (!CustomData_has_layer(cdata, type))
+ return 0.0f;
+
+ f = CustomData_bmesh_get(cdata, ele->data, type);
+
+ return *f;
+}
+
+int edgetag_context_check(Scene *scene, BMEditMesh *em, BMEdge *eed)
{
switch (scene->toolsettings->edge_mode) {
case EDGE_MODE_SELECT:
- return (eed->f & SELECT) ? 1 : 0;
+ return BM_TestHFlag(eed, BM_SELECT) ? 1 : 0;
case EDGE_MODE_TAG_SEAM:
- return eed->seam ? 1 : 0;
+ return BM_TestHFlag(eed, BM_SEAM);
case EDGE_MODE_TAG_SHARP:
- return eed->sharp ? 1 : 0;
+ return BM_TestHFlag(eed, BM_SHARP);
case EDGE_MODE_TAG_CREASE:
- return eed->crease ? 1 : 0;
+ return bm_cdata_get_single_float(em->bm, &em->bm->edata, eed, CD_CREASE) ? 1 : 0;
case EDGE_MODE_TAG_BEVEL:
- return eed->bweight ? 1 : 0;
+ return bm_cdata_get_single_float(em->bm, &em->bm->edata, eed, CD_BWEIGHT) ? 1 : 0;
}
return 0;
}
-int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge *target)
+int edgetag_shortest_path(Scene *scene, BMEditMesh *em, BMEdge *source, BMEdge *target)
{
- EditEdge *eed;
- EditVert *ev;
-
+ BMEdge *eed;
+ BMVert *ev;
+ BMIter iter;
Heap *heap;
float *cost;
int a, totvert=0, totedge=0, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0;
/* we need the vert */
- for (ev= em->verts.first, totvert=0; ev; ev= ev->next) {
- ev->tmp.l = totvert;
+ BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(ev, totvert);
totvert++;
}
- for (eed= em->edges.first; eed; eed = eed->next) {
- eed->f2 = 0;
- if (eed->h) {
- eed->f2 |= ME_SEAM_DONE;
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ eed->head.flags[0].f = 0;
+ if (BM_TestHFlag(eed, BM_SELECT)) {
+ eed->head.flags[0].f |= ME_SEAM_DONE;
}
- eed->tmp.l = totedge;
+
+ BMINDEX_SET(eed, totedge);
totedge++;
}
@@ -550,9 +583,9 @@ int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge
cost = MEM_mallocN(sizeof(*cost)*totedge, "SeamPathCost");
/* count edges, compute adjacent edges offsets and fill adjacent edges */
- for (eed= em->edges.first; eed; eed = eed->next) {
- nedges[eed->v1->tmp.l+1]++;
- nedges[eed->v2->tmp.l+1]++;
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ nedges[BMINDEX_GET(eed->v1)+1]++;
+ nedges[BMINDEX_GET(eed->v2)+1]++;
}
for (a=1; a<totvert; a++) {
@@ -562,107 +595,108 @@ int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge
}
nedges[0] = nedges[1] = 0;
- for (a=0, eed= em->edges.first; eed; a++, eed = eed->next) {
- edges[nedges[eed->v1->tmp.l+1]++] = a;
- edges[nedges[eed->v2->tmp.l+1]++] = a;
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ edges[nedges[BMINDEX_GET(eed->v1)+1]++] = a;
+ edges[nedges[BMINDEX_GET(eed->v2)+1]++] = a;
cost[a] = 1e20f;
prevedge[a] = -1;
+ a++;
}
/* regular dijkstra shortest path, but over edges instead of vertices */
heap = BLI_heap_new();
- BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(source->tmp.l));
- cost[source->tmp.l] = 0.0f;
-
- EM_init_index_arrays(em, 1, 1, 0);
+ BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(BMINDEX_GET(source)));
+ cost[BMINDEX_GET(source)] = 0.0f;
+ EDBM_init_index_arrays(em, 1, 1, 0);
while (!BLI_heap_empty(heap)) {
mednum = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
- eed = EM_get_edge_for_index( mednum );
+ eed = EDBM_get_edge_for_index(em, mednum);
- if (mednum == target->tmp.l)
+ if (mednum == BMINDEX_GET(target))
break;
- if (eed->f2 & ME_SEAM_DONE)
+ if (eed->head.flags[0].f & ME_SEAM_DONE)
continue;
- eed->f2 |= ME_SEAM_DONE;
+ eed->head.flags[0].f |= ME_SEAM_DONE;
- edgetag_add_adjacent(heap, mednum, eed->v1->tmp.l, nedges, edges, prevedge, cost);
- edgetag_add_adjacent(heap, mednum, eed->v2->tmp.l, nedges, edges, prevedge, cost);
+ edgetag_add_adjacent(em, heap, mednum, BMINDEX_GET(eed->v1), nedges, edges, prevedge, cost);
+ edgetag_add_adjacent(em, heap, mednum, BMINDEX_GET(eed->v2), nedges, edges, prevedge, cost);
}
-
MEM_freeN(nedges);
MEM_freeN(edges);
MEM_freeN(cost);
BLI_heap_free(heap, NULL);
- for (eed= em->edges.first; eed; eed = eed->next) {
- eed->f2 &= ~ME_SEAM_DONE;
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ eed->head.flags[0].f &= ~ME_SEAM_DONE;
}
- if (mednum != target->tmp.l) {
+ if (mednum != BMINDEX_GET(target)) {
MEM_freeN(prevedge);
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
return 0;
}
/* follow path back to source and mark as seam */
- if (mednum == target->tmp.l) {
+ if (mednum == BMINDEX_GET(target)) {
short allseams = 1;
- mednum = target->tmp.l;
+ mednum = BMINDEX_GET(target);
do {
- eed = EM_get_edge_for_index( mednum );
- if (!edgetag_context_check(scene, eed)) {
+ eed = EDBM_get_edge_for_index(em, mednum);
+ if (!edgetag_context_check(scene, em, eed)) {
allseams = 0;
break;
}
mednum = prevedge[mednum];
- } while (mednum != source->tmp.l);
+ } while (mednum != BMINDEX_GET(source));
- mednum = target->tmp.l;
+ mednum = BMINDEX_GET(target);
do {
- eed = EM_get_edge_for_index( mednum );
+ eed = EDBM_get_edge_for_index(em, mednum);
if (allseams)
- edgetag_context_set(scene, eed, 0);
+ edgetag_context_set(em, scene, eed, 0);
else
- edgetag_context_set(scene, eed, 1);
+ edgetag_context_set(em, scene, eed, 1);
mednum = prevedge[mednum];
} while (mednum != -1);
}
MEM_freeN(prevedge);
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
return 1;
}
/* *************************************** */
#if 0
-static void seam_edgehash_insert_face(EdgeHash *ehash, MFace *mf)
+static void seam_edgehash_insert_face(EdgeHash *ehash, MPoly *mf, MLoop *loopstart)
{
- BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL);
- BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL);
- if (mf->v4) {
- BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL);
- BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL);
- }
- else
- BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL);
+ MLoop *ml1, *ml2;
+ int a;
+
+ for (a=0; a<mf->totloop; a++) {
+ ml1 = loopstart + a;
+ ml2 = loopstart + (a+1) % mf->totloop;
+
+ BLI_edgehash_insert(ehash, ml1->v, ml2->v, NULL);
+ }
}
void seam_mark_clear_tface(Scene *scene, short mode)
{
Mesh *me;
- MFace *mf;
+ MPoly *mf;
+ MLoop *ml1, *ml2;
MEdge *med;
- int a;
+ int a, b;
me= get_mesh(OBACT);
- if(me==0 || me->totface==0) return;
+ if(me==0 || me->totpoly==0) return;
if (mode == 0)
mode = pupmenu("Seams%t|Mark Border Seam %x1|Clear Seam %x2");
@@ -673,9 +707,9 @@ void seam_mark_clear_tface(Scene *scene, short mode)
if (mode == 2) {
EdgeHash *ehash = BLI_edgehash_new();
- for (a=0, mf=me->mface; a<me->totface; a++, mf++)
+ for (a=0, mf=me->mpoly; a<me->totpoly; a++, mf++)
if (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL))
- seam_edgehash_insert_face(ehash, mf);
+ seam_edgehash_insert_face(ehash, mf, me->mloop + mf->loopstart);
for (a=0, med=me->medge; a<me->totedge; a++, med++)
if (BLI_edgehash_haskey(ehash, med->v1, med->v2))
@@ -688,11 +722,11 @@ void seam_mark_clear_tface(Scene *scene, short mode)
EdgeHash *ehash1 = BLI_edgehash_new();
EdgeHash *ehash2 = BLI_edgehash_new();
- for (a=0, mf=me->mface; a<me->totface; a++, mf++) {
+ for (a=0, mf=me->mpoly; a<me->totpoly; a++, mf++) {
if ((mf->flag & ME_HIDE) || !(mf->flag & ME_FACE_SEL))
- seam_edgehash_insert_face(ehash1, mf);
+ seam_edgehash_insert_face(ehash1, mf, me->mloop + mf->loopstart);
else
- seam_edgehash_insert_face(ehash2, mf);
+ seam_edgehash_insert_face(ehash2, mf, me->mloop + mf->loopstart);
}
for (a=0, med=me->medge; a<me->totedge; a++, med++)
@@ -714,21 +748,24 @@ void seam_mark_clear_tface(Scene *scene, short mode)
int paintface_mouse_select(struct bContext *C, Object *ob, short mval[2], int extend)
{
Mesh *me;
- MFace *mface, *msel;
+ MPoly *mface, *msel;
unsigned int a, index;
/* Get the face under the cursor */
me = get_mesh(ob);
- if (!facesel_face_pick(C, me, mval, &index, 1))
+ if (!facesel_face_pick(C, me, ob, mval, &index, 1))
return 0;
- msel= (((MFace*)me->mface)+index);
+ if (index >= me->totpoly || index < 0)
+ return 0;
+
+ msel= me->mpoly + index;
if (msel->flag & ME_HIDE) return 0;
/* clear flags */
- mface = me->mface;
- a = me->totface;
+ mface = me->mpoly;
+ a = me->totpoly;
if (!extend) {
while (a--) {
mface->flag &= ~ME_FACE_SEL;
@@ -756,25 +793,36 @@ int paintface_mouse_select(struct bContext *C, Object *ob, short mval[2], int ex
int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend)
{
+ Object *ob = vc->obact;
Mesh *me;
- MFace *mface;
+ MPoly *mface;
struct ImBuf *ibuf;
unsigned int *rt;
- int a, index;
char *selar;
+ int a, index;
int sx= rect->xmax-rect->xmin+1;
int sy= rect->ymax-rect->ymin+1;
-
- me= get_mesh(vc->obact);
+
+ me= get_mesh(ob);
+ if(me==0) return 0;
+ if(me->totpoly==0) return 0;
if(me==NULL || me->totface==0 || sx*sy <= 0)
return OPERATOR_CANCELLED;
- selar= MEM_callocN(me->totface+1, "selar");
+ selar= MEM_callocN(me->totpoly+1, "selar");
if (extend == 0 && select)
paintface_deselect_all_visible(vc->obact, SEL_DESELECT, FALSE);
+ if (extend == 0 && select) {
+ mface= me->mpoly;
+ for(a=1; a<=me->totpoly; a++, mface++) {
+ if((mface->flag & ME_HIDE) == 0)
+ mface->flag &= ~ME_FACE_SEL;
+ }
+ }
+
view3d_validate_backbuf(vc);
ibuf = IMB_allocImBuf(sx,sy,32,IB_rect);
@@ -791,8 +839,8 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend)
rt++;
}
- mface= me->mface;
- for(a=1; a<=me->totface; a++, mface++) {
+ mface= me->mpoly;
+ for(a=1; a<=me->totpoly; a++, mface++) {
if(selar[a]) {
if(mface->flag & ME_HIDE);
else {
diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c
deleted file mode 100644
index 3843b782d87..00000000000
--- a/source/blender/editors/mesh/editmesh.c
+++ /dev/null
@@ -1,1952 +0,0 @@
-/*
- * $Id$
- *
- * ***** 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, full recode 2002-2008
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
-#include "DNA_key_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_editVert.h"
-#include "BLI_dynstr.h"
-#include "BLI_rand.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_DerivedMesh.h"
-#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_global.h"
-#include "BKE_key.h"
-#include "BKE_main.h"
-#include "BKE_material.h"
-#include "BKE_mesh.h"
-#include "BKE_paint.h"
-#include "BKE_report.h"
-#include "BKE_multires.h"
-
-#include "ED_mesh.h"
-#include "ED_object.h"
-#include "ED_screen.h"
-#include "ED_util.h"
-#include "ED_view3d.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-/* own include */
-#include "mesh_intern.h"
-
-/*
-editmesh.c:
- - add/alloc/free data
- - hashtables
- - enter/exit editmode
-*/
-
-/* XXX */
-static void BIF_undo_push(const char *UNUSED(arg)) {}
-static void error(const char *UNUSED(arg)) {}
-
-
-/* ***************** HASH ********************* */
-
-
-#define EDHASHSIZE (512*512)
-#define EDHASH(a, b) (a % EDHASHSIZE)
-
-
-/* ************ ADD / REMOVE / FIND ****************** */
-
-static void *calloc_em(EditMesh *UNUSED(em), size_t size, size_t nr)
-{
- return calloc(size, nr);
-}
-
-/* used to bypass normal calloc with fast one */
-static void *(*callocvert)(EditMesh *, size_t, size_t) = calloc_em;
-static void *(*callocedge)(EditMesh *, size_t, size_t) = calloc_em;
-static void *(*callocface)(EditMesh *, size_t, size_t) = calloc_em;
-
-EditVert *addvertlist(EditMesh *em, float *vec, EditVert *example)
-{
- EditVert *eve;
- static int hashnr= 0;
-
- eve= callocvert(em, sizeof(EditVert), 1);
- BLI_addtail(&em->verts, eve);
- em->totvert++;
-
- if(vec) VECCOPY(eve->co, vec);
-
- eve->hash= hashnr++;
- if( hashnr>=EDHASHSIZE) hashnr= 0;
-
- /* new verts get keyindex of -1 since they did not
- * have a pre-editmode vertex order
- */
- eve->keyindex = -1;
-
- if(example) {
- CustomData_em_copy_data(&em->vdata, &em->vdata, example->data, &eve->data);
- eve->bweight = example->bweight;
- }
- else {
- CustomData_em_set_default(&em->vdata, &eve->data);
- }
-
- return eve;
-}
-
-void free_editvert (EditMesh *em, EditVert *eve)
-{
-
- EM_remove_selection(em, eve, EDITVERT);
- CustomData_em_free_block(&em->vdata, &eve->data);
- if(eve->fast==0)
- free(eve);
-
- em->totvert--;
-}
-
-
-EditEdge *findedgelist(EditMesh *em, EditVert *v1, EditVert *v2)
-{
- EditVert *v3;
- struct HashEdge *he;
-
- /* swap ? */
- if( v1 > v2) {
- v3= v2;
- v2= v1;
- v1= v3;
- }
-
- if(em->hashedgetab==NULL)
- em->hashedgetab= MEM_callocN(EDHASHSIZE*sizeof(struct HashEdge), "hashedgetab");
-
- he= em->hashedgetab + EDHASH(v1->hash, v2->hash);
-
- while(he) {
-
- if(he->eed && he->eed->v1==v1 && he->eed->v2==v2) return he->eed;
-
- he= he->next;
- }
- return 0;
-}
-
-static void insert_hashedge(EditMesh *em, EditEdge *eed)
-{
- /* assuming that eed is not in the list yet, and that a find has been done before */
-
- struct HashEdge *first, *he;
-
- first= em->hashedgetab + EDHASH(eed->v1->hash, eed->v2->hash);
-
- if( first->eed==0 ) {
- first->eed= eed;
- }
- else {
- he= &eed->hash;
- he->eed= eed;
- he->next= first->next;
- first->next= he;
- }
-}
-
-static void remove_hashedge(EditMesh *em, EditEdge *eed)
-{
- /* assuming eed is in the list */
-
- struct HashEdge *first, *he, *prev=NULL;
-
- he=first= em->hashedgetab + EDHASH(eed->v1->hash, eed->v2->hash);
-
- while(he) {
- if(he->eed == eed) {
- /* remove from list */
- if(he==first) {
- if(first->next) {
- he= first->next;
- first->eed= he->eed;
- first->next= he->next;
- }
- else he->eed= 0;
- }
- else {
- prev->next= he->next;
- }
- return;
- }
- prev= he;
- he= he->next;
- }
-}
-
-EditEdge *addedgelist(EditMesh *em, EditVert *v1, EditVert *v2, EditEdge *example)
-{
- EditVert *v3;
- EditEdge *eed;
- int swap= 0;
-
- if(v1==v2) return NULL;
- if(v1==NULL || v2==NULL) return NULL;
-
- /* swap ? */
- if(v1>v2) {
- v3= v2;
- v2= v1;
- v1= v3;
- swap= 1;
- }
-
- /* find in hashlist */
- eed= findedgelist(em, v1, v2);
-
- if(eed==NULL) {
-
- eed= (EditEdge *)callocedge(em, sizeof(EditEdge), 1);
- eed->v1= v1;
- eed->v2= v2;
- BLI_addtail(&em->edges, eed);
- eed->dir= swap;
- insert_hashedge(em, eed);
- em->totedge++;
-
- /* copy edge data:
- rule is to do this with addedgelist call, before addfacelist */
- if(example) {
- eed->crease= example->crease;
- eed->bweight= example->bweight;
- eed->sharp = example->sharp;
- eed->seam = example->seam;
- eed->h |= (example->h & EM_FGON);
- }
- }
-
- return eed;
-}
-
-void remedge(EditMesh *em, EditEdge *eed)
-{
- BLI_remlink(&em->edges, eed);
- remove_hashedge(em, eed);
-
- em->totedge--;
-}
-
-void free_editedge(EditMesh *em, EditEdge *eed)
-{
- EM_remove_selection(em, eed, EDITEDGE);
- if(eed->fast==0){
- free(eed);
- }
-}
-
-void free_editface(EditMesh *em, EditFace *efa)
-{
- EM_remove_selection(em, efa, EDITFACE);
-
- if (em->act_face==efa) {
- EM_set_actFace(em, em->faces.first == efa ? NULL : em->faces.first);
- }
-
- CustomData_em_free_block(&em->fdata, &efa->data);
- if(efa->fast==0)
- free(efa);
-
- em->totface--;
-}
-
-void free_vertlist(EditMesh *em, ListBase *edve)
-{
- EditVert *eve, *next;
-
- if (!edve) return;
-
- eve= edve->first;
- while(eve) {
- next= eve->next;
- free_editvert(em, eve);
- eve= next;
- }
- edve->first= edve->last= NULL;
- em->totvert= em->totvertsel= 0;
-}
-
-void free_edgelist(EditMesh *em, ListBase *lb)
-{
- EditEdge *eed, *next;
-
- eed= lb->first;
- while(eed) {
- next= eed->next;
- free_editedge(em, eed);
- eed= next;
- }
- lb->first= lb->last= NULL;
- em->totedge= em->totedgesel= 0;
-}
-
-void free_facelist(EditMesh *em, ListBase *lb)
-{
- EditFace *efa, *next;
-
- efa= lb->first;
- while(efa) {
- next= efa->next;
- free_editface(em, efa);
- efa= next;
- }
- lb->first= lb->last= NULL;
- em->totface= em->totfacesel= 0;
-}
-
-EditFace *addfacelist(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, EditFace *example, EditFace *exampleEdges)
-{
- EditFace *efa;
- EditEdge *e1, *e2=0, *e3=0, *e4=0;
-
- /* added sanity check... seems to happen for some tools, or for enter editmode for corrupted meshes */
- if(v1==v4 || v2==v4 || v3==v4) v4= NULL;
-
- /* add face to list and do the edges */
- if(exampleEdges) {
- e1= addedgelist(em, v1, v2, exampleEdges->e1);
- e2= addedgelist(em, v2, v3, exampleEdges->e2);
- if(v4) e3= addedgelist(em, v3, v4, exampleEdges->e3);
- else e3= addedgelist(em, v3, v1, exampleEdges->e3);
- if(v4) e4= addedgelist(em, v4, v1, exampleEdges->e4);
- }
- else {
- e1= addedgelist(em, v1, v2, NULL);
- e2= addedgelist(em, v2, v3, NULL);
- if(v4) e3= addedgelist(em, v3, v4, NULL);
- else e3= addedgelist(em, v3, v1, NULL);
- if(v4) e4= addedgelist(em, v4, v1, NULL);
- }
-
- if(v1==v2 || v2==v3 || v1==v3) return NULL;
- if(e2==0) return NULL;
-
- efa= (EditFace *)callocface(em, sizeof(EditFace), 1);
- efa->v1= v1;
- efa->v2= v2;
- efa->v3= v3;
- efa->v4= v4;
-
- efa->e1= e1;
- efa->e2= e2;
- efa->e3= e3;
- efa->e4= e4;
-
- if(example) {
- efa->mat_nr= example->mat_nr;
- efa->flag= example->flag;
- CustomData_em_copy_data(&em->fdata, &em->fdata, example->data, &efa->data);
- CustomData_em_validate_data(&em->fdata, efa->data, efa->v4 ? 4 : 3);
- }
- else {
- efa->mat_nr= em->mat_nr;
-
- CustomData_em_set_default(&em->fdata, &efa->data);
- }
-
- BLI_addtail(&em->faces, efa);
- em->totface++;
-
- if(efa->v4) {
- normal_quad_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- cent_quad_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- }
- else {
- normal_tri_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co);
- cent_tri_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co);
- }
-
- return efa;
-}
-
-/* ************************ end add/new/find ************ */
-
-/* ************************ Edit{Vert,Edge,Face} utilss ***************************** */
-
-/* some nice utility functions */
-
-EditVert *editedge_getOtherVert(EditEdge *eed, EditVert *eve)
-{
- if (eve==eed->v1) {
- return eed->v2;
- } else if (eve==eed->v2) {
- return eed->v1;
- } else {
- return NULL;
- }
-}
-
-EditVert *editedge_getSharedVert(EditEdge *eed, EditEdge *eed2)
-{
- if (eed->v1==eed2->v1 || eed->v1==eed2->v2) {
- return eed->v1;
- } else if (eed->v2==eed2->v1 || eed->v2==eed2->v2) {
- return eed->v2;
- } else {
- return NULL;
- }
-}
-
-int editedge_containsVert(EditEdge *eed, EditVert *eve)
-{
- return (eed->v1==eve || eed->v2==eve);
-}
-
-int editface_containsVert(EditFace *efa, EditVert *eve)
-{
- return (efa->v1==eve || efa->v2==eve || efa->v3==eve || (efa->v4 && efa->v4==eve));
-}
-
-int editface_containsEdge(EditFace *efa, EditEdge *eed)
-{
- return (efa->e1==eed || efa->e2==eed || efa->e3==eed || (efa->e4 && efa->e4==eed));
-}
-
-
-/* ************************ stuct EditMesh manipulation ***************************** */
-
-/* fake callocs for fastmalloc below */
-static void *calloc_fastvert(EditMesh *em, size_t UNUSED(size), size_t UNUSED(nr))
-{
- EditVert *eve= em->curvert++;
- eve->fast= 1;
- return eve;
-}
-static void *calloc_fastedge(EditMesh *em, size_t UNUSED(size), size_t UNUSED(nr))
-{
- EditEdge *eed= em->curedge++;
- eed->fast= 1;
- return eed;
-}
-static void *calloc_fastface(EditMesh *em, size_t UNUSED(size), size_t UNUSED(nr))
-{
- EditFace *efa= em->curface++;
- efa->fast= 1;
- return efa;
-}
-
-/* allocate 1 chunk for all vertices, edges, faces. These get tagged to
- prevent it from being freed
-*/
-static void init_editmesh_fastmalloc(EditMesh *em, int totvert, int totedge, int totface)
-{
- if(totvert) em->allverts= MEM_callocN(totvert*sizeof(EditVert), "allverts");
- else em->allverts= NULL;
- em->curvert= em->allverts;
-
- if(totedge==0) totedge= 4*totface; // max possible
-
- if(totedge) em->alledges= MEM_callocN(totedge*sizeof(EditEdge), "alledges");
- else em->alledges= NULL;
- em->curedge= em->alledges;
-
- if(totface) em->allfaces= MEM_callocN(totface*sizeof(EditFace), "allfaces");
- else em->allfaces= NULL;
- em->curface= em->allfaces;
-
- callocvert= calloc_fastvert;
- callocedge= calloc_fastedge;
- callocface= calloc_fastface;
-}
-
-static void end_editmesh_fastmalloc(void)
-{
- callocvert= calloc_em;
- callocedge= calloc_em;
- callocface= calloc_em;
-}
-
-/* do not free editmesh itself here */
-void free_editMesh(EditMesh *em)
-{
- if(em==NULL) return;
-
- if(em->verts.first) free_vertlist(em, &em->verts);
- if(em->edges.first) free_edgelist(em, &em->edges);
- if(em->faces.first) free_facelist(em, &em->faces);
- if(em->selected.first) BLI_freelistN(&(em->selected));
-
- CustomData_free(&em->vdata, 0);
- CustomData_free(&em->fdata, 0);
-
- if(em->derivedFinal) {
- if (em->derivedFinal!=em->derivedCage) {
- em->derivedFinal->needsFree= 1;
- em->derivedFinal->release(em->derivedFinal);
- }
- em->derivedFinal= NULL;
- }
- if(em->derivedCage) {
- em->derivedCage->needsFree= 1;
- em->derivedCage->release(em->derivedCage);
- em->derivedCage= NULL;
- }
-
- /* DEBUG: hashtabs are slowest part of enter/exit editmode. here a testprint */
-#if 0
- if(em->hashedgetab) {
- HashEdge *he, *hen;
- int a, used=0, max=0, nr;
- he= em->hashedgetab;
- for(a=0; a<EDHASHSIZE; a++, he++) {
- if(he->eed) used++;
- hen= he->next;
- nr= 0;
- while(hen) {
- nr++;
- hen= hen->next;
- }
- if(max<nr) max= nr;
- }
- printf("hastab used %d max %d\n", used, max);
- }
-#endif
- if(em->hashedgetab) MEM_freeN(em->hashedgetab);
- em->hashedgetab= NULL;
-
- if(em->allverts) MEM_freeN(em->allverts);
- if(em->alledges) MEM_freeN(em->alledges);
- if(em->allfaces) MEM_freeN(em->allfaces);
-
- em->allverts= em->curvert= NULL;
- em->alledges= em->curedge= NULL;
- em->allfaces= em->curface= NULL;
-
- mesh_octree_table(NULL, NULL, NULL, 'e');
- mesh_mirrtopo_table(NULL, 'e');
-
- em->totvert= em->totedge= em->totface= 0;
-
-// XXX if(em->retopo_paint_data) retopo_free_paint_data(em->retopo_paint_data);
- em->retopo_paint_data= NULL;
- em->act_face = NULL;
-}
-
-static void editMesh_set_hash(EditMesh *em)
-{
- EditEdge *eed;
-
- if(em->hashedgetab) MEM_freeN(em->hashedgetab);
- em->hashedgetab= NULL;
-
- for(eed=em->edges.first; eed; eed= eed->next) {
- if( findedgelist(em, eed->v1, eed->v2)==NULL )
- insert_hashedge(em, eed);
- }
-
-}
-
-
-/* ************************ IN & OUT EDITMODE ***************************** */
-
-
-static void edge_normal_compare(EditEdge *eed, EditFace *efa1)
-{
- EditFace *efa2;
- float cent1[3], cent2[3];
- float inp;
-
- efa2 = eed->tmp.f;
- if(efa1==efa2) return;
-
- inp= efa1->n[0]*efa2->n[0] + efa1->n[1]*efa2->n[1] + efa1->n[2]*efa2->n[2];
- if(inp<0.999 && inp >-0.999) eed->f2= 1;
-
- if(efa1->v4) cent_quad_v3(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co, efa1->v4->co);
- else cent_tri_v3(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co);
- if(efa2->v4) cent_quad_v3(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co, efa2->v4->co);
- else cent_tri_v3(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co);
-
- sub_v3_v3v3(cent1, cent2, cent1);
- normalize_v3(cent1);
- inp= cent1[0]*efa1->n[0] + cent1[1]*efa1->n[1] + cent1[2]*efa1->n[2];
-
- if(inp < -0.001 ) eed->f1= 1;
-}
-
-#if 0
-typedef struct {
- EditEdge *eed;
- float noLen,no[3];
- int adjCount;
-} EdgeDrawFlagInfo;
-
-static int edgeDrawFlagInfo_cmp(const void *av, const void *bv)
-{
- const EdgeDrawFlagInfo *a = av;
- const EdgeDrawFlagInfo *b = bv;
-
- if (a->noLen<b->noLen) return -1;
- else if (a->noLen>b->noLen) return 1;
- else return 0;
-}
-#endif
-
-static void edge_drawflags(Mesh *me, EditMesh *em)
-{
- EditVert *eve;
- EditEdge *eed, *e1, *e2, *e3, *e4;
- EditFace *efa;
-
- /* - count number of times edges are used in faces: 0 en 1 time means draw edge
- * - edges more than 1 time used: in *tmp.f is pointer to first face
- * - check all faces, when normal differs to much: draw (flag becomes 1)
- */
-
- /* later on: added flags for 'cylinder' and 'sphere' intersection tests in old
- game engine (2.04)
- */
-
- recalc_editnormals(em);
-
- /* init */
- eve= em->verts.first;
- while(eve) {
- eve->f1= 1; /* during test it's set at zero */
- eve= eve->next;
- }
- eed= em->edges.first;
- while(eed) {
- eed->f2= eed->f1= 0;
- eed->tmp.f = 0;
- eed= eed->next;
- }
-
- efa= em->faces.first;
- while(efa) {
- e1= efa->e1;
- e2= efa->e2;
- e3= efa->e3;
- e4= efa->e4;
- if(e1->f2<4) e1->f2+= 1;
- if(e2->f2<4) e2->f2+= 1;
- if(e3->f2<4) e3->f2+= 1;
- if(e4 && e4->f2<4) e4->f2+= 1;
-
- if(e1->tmp.f == 0) e1->tmp.f = (void *) efa;
- if(e2->tmp.f == 0) e2->tmp.f = (void *) efa;
- if(e3->tmp.f ==0) e3->tmp.f = (void *) efa;
- if(e4 && (e4->tmp.f == 0)) e4->tmp.f = (void *) efa;
-
- efa= efa->next;
- }
-
- if(me->drawflag & ME_ALLEDGES) {
- efa= em->faces.first;
- while(efa) {
- if(efa->e1->f2>=2) efa->e1->f2= 1;
- if(efa->e2->f2>=2) efa->e2->f2= 1;
- if(efa->e3->f2>=2) efa->e3->f2= 1;
- if(efa->e4 && efa->e4->f2>=2) efa->e4->f2= 1;
-
- efa= efa->next;
- }
- }
- else {
-
- /* handle single-edges for 'test cylinder flag' (old engine) */
-
- eed= em->edges.first;
- while(eed) {
- if(eed->f2==1) eed->f1= 1;
- eed= eed->next;
- }
-
- /* all faces, all edges with flag==2: compare normal */
- efa= em->faces.first;
- while(efa) {
- if(efa->e1->f2==2) edge_normal_compare(efa->e1, efa);
- else efa->e1->f2= 1;
- if(efa->e2->f2==2) edge_normal_compare(efa->e2, efa);
- else efa->e2->f2= 1;
- if(efa->e3->f2==2) edge_normal_compare(efa->e3, efa);
- else efa->e3->f2= 1;
- if(efa->e4) {
- if(efa->e4->f2==2) edge_normal_compare(efa->e4, efa);
- else efa->e4->f2= 1;
- }
- efa= efa->next;
- }
-
- /* sphere collision flag */
-
- eed= em->edges.first;
- while(eed) {
- if(eed->f1!=1) {
- eed->v1->f1= eed->v2->f1= 0;
- }
- eed= eed->next;
- }
-
- }
-}
-
-/* turns Mesh into editmesh */
-void make_editMesh(Scene *scene, Object *ob)
-{
- Mesh *me= ob->data;
- MFace *mface;
- MVert *mvert;
- MSelect *mselect;
- KeyBlock *actkey;
- EditMesh *em;
- EditVert *eve, **evlist, *eve1, *eve2, *eve3, *eve4;
- EditFace *efa, *efa_last_sel= NULL;
- EditEdge *eed;
- EditSelection *ese;
- float *co, (*keyco)[3]= NULL;
- int tot, a, eekadoodle= 0;
- const short is_paint_sel= paint_facesel_test(ob);
-
- if(me->edit_mesh==NULL)
- me->edit_mesh= MEM_callocN(sizeof(EditMesh), "editmesh");
- else
- /* because of reload */
- free_editMesh(me->edit_mesh);
-
- em= me->edit_mesh;
-
- em->selectmode= scene->toolsettings->selectmode; // warning needs to be synced
- em->act_face = NULL;
- em->totvert= tot= me->totvert;
- em->totedge= me->totedge;
- em->totface= me->totface;
-
- if(tot==0) {
- return;
- }
-
- if(ob->actcol > 0)
- em->mat_nr= ob->actcol-1;
-
- /* initialize fastmalloc for editmesh */
- init_editmesh_fastmalloc(em, me->totvert, me->totedge, me->totface);
-
- actkey = ob_get_keyblock(ob);
- if(actkey) {
- /* undo-ing in past for previous editmode sessions gives corrupt 'keyindex' values */
- undo_editmode_clear();
- keyco= actkey->data;
- em->shapenr= ob->shapenr;
- }
-
- /* make editverts */
- CustomData_copy(&me->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
- mvert= me->mvert;
-
- evlist= (EditVert **)MEM_mallocN(tot*sizeof(void *),"evlist");
- for(a=0; a<tot; a++, mvert++) {
-
- co= mvert->co;
-
- /* edit the shape key coordinate if available */
- if(keyco && a < actkey->totelem)
- co= keyco[a];
-
- eve= addvertlist(em, co, NULL);
- evlist[a]= eve;
-
- /* face select sets selection in next loop */
- if(!is_paint_sel)
- eve->f |= (mvert->flag & 1);
-
- if (mvert->flag & ME_HIDE) eve->h= 1;
- eve->no[0]= mvert->no[0]/32767.0;
- eve->no[1]= mvert->no[1]/32767.0;
- eve->no[2]= mvert->no[2]/32767.0;
-
- eve->bweight= ((float)mvert->bweight)/255.0f;
-
- /* lets overwrite the keyindex of the editvert
- * with the order it used to be in before
- * editmode
- */
- eve->keyindex = a;
-
- CustomData_to_em_block(&me->vdata, &em->vdata, a, &eve->data);
- }
-
- if(actkey && actkey->totelem!=me->totvert);
- else {
- MEdge *medge= me->medge;
-
- CustomData_copy(&me->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0);
- /* make edges */
- for(a=0; a<me->totedge; a++, medge++) {
- eed= addedgelist(em, evlist[medge->v1], evlist[medge->v2], NULL);
- /* eed can be zero when v1 and v2 are identical, dxf import does this... */
- if(eed) {
- eed->crease= ((float)medge->crease)/255.0f;
- eed->bweight= ((float)medge->bweight)/255.0f;
-
- if(medge->flag & ME_SEAM) eed->seam= 1;
- if(medge->flag & ME_SHARP) eed->sharp = 1;
- if(medge->flag & SELECT) eed->f |= SELECT;
- if(medge->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines!
- if(medge->flag & ME_HIDE) eed->h |= 1;
- if(em->selectmode==SCE_SELECT_EDGE)
- EM_select_edge(eed, eed->f & SELECT); // force edge selection to vertices, seems to be needed ...
- CustomData_to_em_block(&me->edata,&em->edata, a, &eed->data);
- }
- }
-
- CustomData_copy(&me->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
-
- /* make faces */
- mface= me->mface;
-
- for(a=0; a<me->totface; a++, mface++) {
- eve1= evlist[mface->v1];
- eve2= evlist[mface->v2];
- if(!mface->v3) eekadoodle= 1;
- eve3= evlist[mface->v3];
- if(mface->v4) eve4= evlist[mface->v4]; else eve4= NULL;
-
- efa= addfacelist(em, eve1, eve2, eve3, eve4, NULL, NULL);
-
- if(efa) {
- CustomData_to_em_block(&me->fdata, &em->fdata, a, &efa->data);
-
- efa->mat_nr= mface->mat_nr;
- efa->flag= mface->flag & ~ME_HIDE;
-
- /* select and hide face flag */
- if(mface->flag & ME_HIDE) {
- efa->h= 1;
- } else {
- if (a==me->act_face) {
- EM_set_actFace(em, efa);
- }
-
- /* dont allow hidden and selected */
- if(mface->flag & ME_FACE_SEL) {
- efa->f |= SELECT;
-
- if(is_paint_sel) {
- EM_select_face(efa, 1); /* flush down */
- }
-
- efa_last_sel= efa;
- }
- }
- }
- }
- }
-
- if(EM_get_actFace(em, 0)==NULL && efa_last_sel) {
- EM_set_actFace(em, efa_last_sel);
- }
-
- if(eekadoodle)
- error("This Mesh has old style edgecodes, please put it in the bugtracker!");
-
- MEM_freeN(evlist);
-
- end_editmesh_fastmalloc(); // resets global function pointers
-
- if(me->mselect){
- //restore editselections
- EM_init_index_arrays(em, 1,1,1);
- mselect = me->mselect;
-
- for(a=0; a<me->totselect; a++, mselect++){
- /*check if recorded selection is still valid, if so copy into editmesh*/
- if( (mselect->type == EDITVERT && me->mvert[mselect->index].flag & SELECT) || (mselect->type == EDITEDGE && me->medge[mselect->index].flag & SELECT) || (mselect->type == EDITFACE && me->mface[mselect->index].flag & ME_FACE_SEL) ){
- ese = MEM_callocN(sizeof(EditSelection), "Edit Selection");
- ese->type = mselect->type;
- if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(mselect->index); else
- if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(mselect->index); else
- if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(mselect->index);
- BLI_addtail(&(em->selected),ese);
- }
- }
- EM_free_index_arrays();
- }
- /* this creates coherent selections. also needed for older files */
- EM_selectmode_set(em);
- /* paranoia check to enforce hide rules */
- EM_hide_reset(em);
- /* sets helper flags which arent saved */
- EM_fgon_flags(em);
-
- if (EM_get_actFace(em, 0)==NULL) {
- EM_set_actFace(em, em->faces.first ); /* will use the first face, this is so we alwats have an active face */
- }
-}
-
-/* makes Mesh out of editmesh */
-void load_editMesh(Scene *scene, Object *obedit)
-{
- Mesh *me= obedit->data;
- MVert *mvert, *oldverts;
- MEdge *medge;
- MFace *mface;
- MSelect *mselect;
- EditMesh *em= me->edit_mesh;
- EditVert *eve;
- EditFace *efa, *efa_act;
- EditEdge *eed;
- EditSelection *ese;
- float *fp, *newkey, *oldkey, nor[3];
- int i, a, ototvert;
-
- /* this one also tests of edges are not in faces: */
- /* eed->f2==0: not in face, f2==1: draw it */
- /* eed->f1 : flag for dynaface (cylindertest, old engine) */
- /* eve->f1 : flag for dynaface (sphere test, old engine) */
- /* eve->f2 : being used in vertexnormals */
- edge_drawflags(me, em);
-
- EM_stats_update(em);
-
- /* new Vertex block */
- if(em->totvert==0) mvert= NULL;
- else mvert= MEM_callocN(em->totvert*sizeof(MVert), "loadeditMesh vert");
-
- /* new Edge block */
- if(em->totedge==0) medge= NULL;
- else medge= MEM_callocN(em->totedge*sizeof(MEdge), "loadeditMesh edge");
-
- /* new Face block */
- if(em->totface==0) mface= NULL;
- else mface= MEM_callocN(em->totface*sizeof(MFace), "loadeditMesh face");
-
- /* lets save the old verts just in case we are actually working on
- * a key ... we now do processing of the keys at the end */
- oldverts= me->mvert;
- ototvert= me->totvert;
-
- /* don't free this yet */
- CustomData_set_layer(&me->vdata, CD_MVERT, NULL);
-
- /* free custom data */
- CustomData_free(&me->vdata, me->totvert);
- CustomData_free(&me->edata, me->totedge);
- CustomData_free(&me->fdata, me->totface);
-
- /* add new custom data */
- me->totvert= em->totvert;
- me->totedge= em->totedge;
- me->totface= em->totface;
-
- CustomData_copy(&em->vdata, &me->vdata, CD_MASK_MESH, CD_CALLOC, me->totvert);
- CustomData_copy(&em->edata, &me->edata, CD_MASK_MESH, CD_CALLOC, me->totedge);
- CustomData_copy(&em->fdata, &me->fdata, CD_MASK_MESH, CD_CALLOC, me->totface);
-
- CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
- CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
- CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, mface, me->totface);
- mesh_update_customdata_pointers(me);
-
- /* the vertices, use ->tmp.l as counter */
- eve= em->verts.first;
- a= 0;
-
- while(eve) {
- VECCOPY(mvert->co, eve->co);
-
- /* vertex normal */
- VECCOPY(nor, eve->no);
- mul_v3_fl(nor, 32767.0);
- VECCOPY(mvert->no, nor);
-
- /* note: it used to remove me->dvert when it was not in use, cancelled
- that... annoying when you have a fresh vgroup */
- CustomData_from_em_block(&em->vdata, &me->vdata, eve->data, a);
-
- eve->tmp.l = a++; /* counter */
-
- mvert->flag= 0;
- mvert->flag |= (eve->f & SELECT);
- if (eve->h) mvert->flag |= ME_HIDE;
-
- mvert->bweight= (char)(255.0*eve->bweight);
-
- eve= eve->next;
- mvert++;
- }
-
- /* the edges */
- a= 0;
- eed= em->edges.first;
- while(eed) {
- medge->v1= (unsigned int) eed->v1->tmp.l;
- medge->v2= (unsigned int) eed->v2->tmp.l;
-
- medge->flag= (eed->f & SELECT) | ME_EDGERENDER;
- if(eed->f2<2) medge->flag |= ME_EDGEDRAW;
- if(eed->f2==0) medge->flag |= ME_LOOSEEDGE;
- if(eed->sharp) medge->flag |= ME_SHARP;
- if(eed->seam) medge->flag |= ME_SEAM;
- if(eed->h & EM_FGON) medge->flag |= ME_FGON; // different defines yes
- if(eed->h & 1) medge->flag |= ME_HIDE;
-
- medge->crease= (char)(255.0*eed->crease);
- medge->bweight= (char)(255.0*eed->bweight);
- CustomData_from_em_block(&em->edata, &me->edata, eed->data, a);
-
- eed->tmp.l = a++;
-
- medge++;
- eed= eed->next;
- }
-
- /* the faces */
- a = 0;
- efa= em->faces.first;
- efa_act= EM_get_actFace(em, 0);
- i = 0;
- me->act_face = -1;
- while(efa) {
- mface= &((MFace *) me->mface)[i];
-
- mface->v1= (unsigned int) efa->v1->tmp.l;
- mface->v2= (unsigned int) efa->v2->tmp.l;
- mface->v3= (unsigned int) efa->v3->tmp.l;
- if (efa->v4) mface->v4 = (unsigned int) efa->v4->tmp.l;
-
- mface->mat_nr= efa->mat_nr;
-
- mface->flag= efa->flag;
- /* bit 0 of flag is already taken for smooth... */
-
- if(efa->h) {
- mface->flag |= ME_HIDE;
- mface->flag &= ~ME_FACE_SEL;
- } else {
- if(efa->f & 1) mface->flag |= ME_FACE_SEL;
- else mface->flag &= ~ME_FACE_SEL;
- }
-
- /* watch: efa->e1->f2==0 means loose edge */
-
- if(efa->e1->f2==1) {
- efa->e1->f2= 2;
- }
- if(efa->e2->f2==1) {
- efa->e2->f2= 2;
- }
- if(efa->e3->f2==1) {
- efa->e3->f2= 2;
- }
- if(efa->e4 && efa->e4->f2==1) {
- efa->e4->f2= 2;
- }
-
- CustomData_from_em_block(&em->fdata, &me->fdata, efa->data, i);
-
- /* no index '0' at location 3 or 4 */
- test_index_face(mface, &me->fdata, i, efa->v4?4:3);
-
- if (efa_act == efa)
- me->act_face = a;
-
- efa->tmp.l = a++;
- i++;
- efa= efa->next;
- }
-
- /* patch hook indices and vertex parents */
- {
- Object *ob;
- ModifierData *md;
- EditVert **vertMap = NULL;
- int j;
-
- for (ob=G.main->object.first; ob; ob=ob->id.next) {
- if (ob->parent==ob && ELEM(ob->partype, PARVERT1,PARVERT3)) {
-
- /* duplicate code from below, make it function later...? */
- if (!vertMap) {
- vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap");
-
- for (eve=em->verts.first; eve; eve=eve->next) {
- if (eve->keyindex!=-1)
- vertMap[eve->keyindex] = eve;
- }
- }
- if(ob->par1 < ototvert) {
- eve = vertMap[ob->par1];
- if(eve) ob->par1= eve->tmp.l;
- }
- if(ob->par2 < ototvert) {
- eve = vertMap[ob->par2];
- if(eve) ob->par2= eve->tmp.l;
- }
- if(ob->par3 < ototvert) {
- eve = vertMap[ob->par3];
- if(eve) ob->par3= eve->tmp.l;
- }
-
- }
- if (ob->data==me) {
- for (md=ob->modifiers.first; md; md=md->next) {
- if (md->type==eModifierType_Hook) {
- HookModifierData *hmd = (HookModifierData*) md;
-
- if (!vertMap) {
- vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap");
-
- for (eve=em->verts.first; eve; eve=eve->next) {
- if (eve->keyindex!=-1)
- vertMap[eve->keyindex] = eve;
- }
- }
-
- for (i=j=0; i<hmd->totindex; i++) {
- if(hmd->indexar[i] < ototvert) {
- eve = vertMap[hmd->indexar[i]];
-
- if (eve) {
- hmd->indexar[j++] = eve->tmp.l;
- }
- }
- else j++;
- }
-
- hmd->totindex = j;
- }
- }
- }
- }
-
- if (vertMap) MEM_freeN(vertMap);
- }
-
- /* are there keys? */
- if(me->key) {
- KeyBlock *currkey;
- KeyBlock *actkey= BLI_findlink(&me->key->block, em->shapenr-1);
-
- float (*ofs)[3] = NULL;
-
- /* editing the base key should update others */
- if(me->key->type==KEY_RELATIVE && oldverts) {
- int act_is_basis = 0;
- /* find if this key is a basis for any others */
- for(currkey = me->key->block.first; currkey; currkey= currkey->next) {
- if(em->shapenr-1 == currkey->relative) {
- act_is_basis = 1;
- break;
- }
- }
-
- if(act_is_basis) { /* active key is a base */
- i=0;
- ofs= MEM_callocN(sizeof(float) * 3 * em->totvert, "currkey->data");
- eve= em->verts.first;
- mvert = me->mvert;
- while(eve) {
- if(eve->keyindex>=0)
- VECSUB(ofs[i], mvert->co, oldverts[eve->keyindex].co);
-
- eve= eve->next;
- i++;
- mvert++;
- }
- }
- }
-
-
- /* Lets reorder the key data so that things line up roughly
- * with the way things were before editmode */
- currkey = me->key->block.first;
- while(currkey) {
- int apply_offset = (ofs && (currkey != actkey) && (em->shapenr-1 == currkey->relative));
-
- fp= newkey= MEM_callocN(me->key->elemsize*em->totvert, "currkey->data");
- oldkey = currkey->data;
-
- eve= em->verts.first;
-
- i = 0;
- mvert = me->mvert;
- while(eve) {
- if (eve->keyindex >= 0 && eve->keyindex < currkey->totelem) { // valid old vertex
- if(currkey == actkey) {
- if(actkey == me->key->refkey) {
- VECCOPY(fp, mvert->co);
- }
- else {
- VECCOPY(fp, mvert->co);
- if(oldverts) {
- VECCOPY(mvert->co, oldverts[eve->keyindex].co);
- }
- }
- }
- else {
- if(oldkey) {
- VECCOPY(fp, oldkey + 3 * eve->keyindex);
- }
- }
- }
- else {
- VECCOPY(fp, mvert->co);
- }
-
- /* propagate edited basis offsets to other shapes */
- if(apply_offset) {
- VECADD(fp, fp, ofs[i]);
- }
-
- fp+= 3;
- ++i;
- ++mvert;
- eve= eve->next;
- }
- currkey->totelem= em->totvert;
- if(currkey->data) MEM_freeN(currkey->data);
- currkey->data = newkey;
-
- currkey= currkey->next;
- }
-
- if(ofs) MEM_freeN(ofs);
- }
-
- if(oldverts) MEM_freeN(oldverts);
-
- i = 0;
- for(ese=em->selected.first; ese; ese=ese->next) i++;
- me->totselect = i;
- if(i==0) mselect= NULL;
- else mselect= MEM_callocN(i*sizeof(MSelect), "loadeditMesh selections");
-
- if(me->mselect) MEM_freeN(me->mselect);
- me->mselect= mselect;
-
- for(ese=em->selected.first; ese; ese=ese->next){
- mselect->type = ese->type;
- if(ese->type == EDITVERT) mselect->index = ((EditVert*)ese->data)->tmp.l;
- else if(ese->type == EDITEDGE) mselect->index = ((EditEdge*)ese->data)->tmp.l;
- else if(ese->type == EDITFACE) mselect->index = ((EditFace*)ese->data)->tmp.l;
- mselect++;
- }
-
- /* to be sure: clear ->tmp.l pointers */
- eve= em->verts.first;
- while(eve) {
- eve->tmp.l = 0;
- eve= eve->next;
- }
-
- eed= em->edges.first;
- while(eed) {
- eed->tmp.l = 0;
- eed= eed->next;
- }
-
- efa= em->faces.first;
- while(efa) {
- efa->tmp.l = 0;
- efa= efa->next;
- }
-
- /* remake softbody of all users */
- if(me->id.us>1) {
- Base *base;
- for(base= scene->base.first; base; base= base->next)
- if(base->object->data==me)
- base->object->recalc |= OB_RECALC_DATA;
- }
-
- mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
-
- /* topology could be changed, ensure mdisps are ok */
- multires_topology_changed(scene, obedit);
-}
-
-void remake_editMesh(Scene *scene, Object *ob)
-{
- make_editMesh(scene, ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- BIF_undo_push("Undo all changes");
-}
-
-/* *************** Operator: separate parts *************/
-
-static EnumPropertyItem prop_separate_types[] = {
- {0, "SELECTED", 0, "Selection", ""},
- {1, "MATERIAL", 0, "By Material", ""},
- {2, "LOOSE", 0, "By loose parts", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-/* return 1: success */
-static int mesh_separate_selected(wmOperator *op, Main *bmain, Scene *scene, Base *editbase)
-{
- EditMesh *em, *emnew;
- EditVert *eve, *v1;
- EditEdge *eed, *e1;
- EditFace *efa, *f1;
- Object *obedit;
- Mesh *me, *menew;
- Base *basenew;
-
- if(editbase==NULL) return 0;
-
- obedit= editbase->object;
- me= obedit->data;
- em= BKE_mesh_get_editmesh(me);
- if(me->key) {
- BKE_report(op->reports, RPT_WARNING, "Can't separate mesh with shape keys.");
- BKE_mesh_end_editmesh(me, em);
- return 0;
- }
-
- if(em->selected.first)
- BLI_freelistN(&(em->selected)); /* clear the selection order */
-
- EM_selectmode_set(em); // enforce full consistent selection flags
-
- EM_stats_update(em);
-
- if(em->totvertsel==0) {
- BKE_mesh_end_editmesh(me, em);
- return 0;
- }
-
- /* we are going to work as follows:
- * 1. add a linked duplicate object: this will be the new one, we remember old pointer
- * 2. give new object empty mesh and put in editmode
- * 3: do a split if needed on current editmesh.
- * 4. copy over: all NOT selected verts, edges, faces
- * 5. call load_editMesh() on the new object
- */
-
- /* 1 */
- basenew= ED_object_add_duplicate(bmain, scene, editbase, 0); /* 0 = fully linked */
- ED_base_object_select(basenew, BA_DESELECT);
-
- /* 2 */
- basenew->object->data= menew= add_mesh(me->id.name+2); /* empty */
- assign_matarar(basenew->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */
- me->id.us--;
- make_editMesh(scene, basenew->object);
- emnew= menew->edit_mesh;
- CustomData_copy(&em->vdata, &emnew->vdata, CD_MASK_EDITMESH, CD_DEFAULT, 0);
- CustomData_copy(&em->edata, &emnew->edata, CD_MASK_EDITMESH, CD_DEFAULT, 0);
- CustomData_copy(&em->fdata, &emnew->fdata, CD_MASK_EDITMESH, CD_DEFAULT, 0);
-
- /* 3 */
- /* SPLIT: first make duplicate */
- adduplicateflag(em, SELECT);
- /* SPLIT: old faces have 3x flag 128 set, delete these ones */
- delfaceflag(em, 128);
- /* since we do tricky things with verts/edges/faces, this makes sure all is selected coherent */
- EM_selectmode_set(em);
-
- /* 4 */
- /* move over: everything that is selected */
- for(eve= em->verts.first; eve; eve= v1) {
- v1= eve->next;
- if(eve->f & SELECT) {
- BLI_remlink(&em->verts, eve);
- BLI_addtail(&emnew->verts, eve);
- }
- }
-
- for(eed= em->edges.first; eed; eed= e1) {
- e1= eed->next;
- if(eed->f & SELECT) {
- BLI_remlink(&em->edges, eed);
- BLI_addtail(&emnew->edges, eed);
- }
- }
-
- for(efa= em->faces.first; efa; efa= f1) {
- f1= efa->next;
- if (efa == em->act_face && (efa->f & SELECT)) {
- EM_set_actFace(em, NULL);
- }
-
- if(efa->f & SELECT) {
- BLI_remlink(&em->faces, efa);
- BLI_addtail(&emnew->faces, efa);
- }
- }
-
- /* 5 */
- load_editMesh(scene, basenew->object);
- free_editMesh(emnew);
- MEM_freeN(menew->edit_mesh);
- menew->edit_mesh= NULL;
-
- /* hashedges are invalid now, make new! */
- editMesh_set_hash(em);
-
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
- DAG_id_tag_update(&basenew->object->id, OB_RECALC_DATA);
-
- BKE_mesh_end_editmesh(me, em);
-
- return 1;
-}
-
-/* return 1: success */
-static int mesh_separate_material(wmOperator *op, Main *bmain, Scene *scene, Base *editbase)
-{
- Mesh *me= editbase->object->data;
- EditMesh *em= BKE_mesh_get_editmesh(me);
- unsigned char curr_mat;
-
- for (curr_mat = 1; curr_mat < editbase->object->totcol; ++curr_mat) {
- /* clear selection, we're going to use that to select material group */
- EM_clear_flag_all(em, SELECT);
- /* select the material */
- EM_select_by_material(em, curr_mat);
- /* and now separate */
- if(0==mesh_separate_selected(op, bmain, scene, editbase)) {
- BKE_mesh_end_editmesh(me, em);
- return 0;
- }
- }
-
- BKE_mesh_end_editmesh(me, em);
- return 1;
-}
-
-/* return 1: success */
-static int mesh_separate_loose(wmOperator *op, Main *bmain, Scene *scene, Base *editbase)
-{
- Mesh *me;
- EditMesh *em;
- int doit= 1;
-
- me= editbase->object->data;
- em= BKE_mesh_get_editmesh(me);
-
- if(me->key) {
- error("Can't separate with vertex keys");
- BKE_mesh_end_editmesh(me, em);
- return 0;
- }
-
- EM_clear_flag_all(em, SELECT);
-
- while(doit) {
- /* Select a random vert to start with */
- EditVert *eve;
- int tot;
-
- /* check if all verts that are visible have been done */
- for(eve=em->verts.first; eve; eve= eve->next)
- if(!eve->h) break;
- if(eve==NULL) break; /* only hidden verts left, quit early */
-
- /* first non hidden vert */
- eve->f |= SELECT;
-
- selectconnected_mesh_all(em);
-
- /* don't separate the very last part */
- for(eve=em->verts.first; eve; eve= eve->next)
- if((eve->f & SELECT)==0) break;
- if(eve==NULL) break;
-
- tot= BLI_countlist(&em->verts);
-
- /* and now separate */
- doit= mesh_separate_selected(op, bmain, scene, editbase);
-
- /* with hidden verts this can happen */
- if(tot == BLI_countlist(&em->verts))
- break;
- }
-
- BKE_mesh_end_editmesh(me, em);
- return 1;
-}
-
-
-static int mesh_separate_exec(bContext *C, wmOperator *op)
-{
- Main *bmain= CTX_data_main(C);
- Scene *scene= CTX_data_scene(C);
- Base *base= CTX_data_active_base(C);
- int retval= 0, type= RNA_enum_get(op->ptr, "type");
-
- if(type == 0)
- retval= mesh_separate_selected(op, bmain, scene, base);
- else if(type == 1)
- retval= mesh_separate_material(op, bmain, scene, base);
- else if(type == 2)
- retval= mesh_separate_loose(op, bmain, scene, base);
-
- if(retval) {
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data);
-
- // XXX: new object was created, but selection wasn't actually changed
- // need this for outliner update without adding new ND. nazgul.
- WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
-
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-void MESH_OT_separate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Separate";
- ot->description= "Separate selected geometry into a new mesh";
- ot->idname= "MESH_OT_separate";
-
- /* api callbacks */
- ot->invoke= WM_menu_invoke;
- ot->exec= mesh_separate_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- ot->prop= RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", "");
-}
-
-
-/* ******************************************** */
-
-/* *************** UNDO ***************************** */
-/* new mesh undo, based on pushing editmesh data itself */
-/* reuses same code as for global and curve undo... unify that (ton) */
-
-/* only one 'hack', to save memory it doesn't store the first push, but does a remake editmesh */
-
-/* a compressed version of editmesh data */
-
-typedef struct EditVertC
-{
- float no[3];
- float co[3];
- unsigned char f, h;
- short bweight;
- int keyindex;
-} EditVertC;
-
-typedef struct EditEdgeC
-{
- int v1, v2;
- unsigned char f, h, seam, sharp, pad;
- short crease, bweight, fgoni;
-} EditEdgeC;
-
-typedef struct EditFaceC
-{
- int v1, v2, v3, v4;
- unsigned char flag, f, h, fgonf, pad1;
- short mat_nr;
-} EditFaceC;
-
-typedef struct EditSelectionC{
- short type;
- int index;
-}EditSelectionC;
-
-typedef struct UndoMesh {
- EditVertC *verts;
- EditEdgeC *edges;
- EditFaceC *faces;
- EditSelectionC *selected;
- int totvert, totedge, totface, totsel;
- int selectmode, shapenr;
- char retopo_mode;
- CustomData vdata, edata, fdata;
-} UndoMesh;
-
-/* for callbacks */
-
-static void free_undoMesh(void *umv)
-{
- UndoMesh *um= umv;
-
- if(um->verts) MEM_freeN(um->verts);
- if(um->edges) MEM_freeN(um->edges);
- if(um->faces) MEM_freeN(um->faces);
- if(um->selected) MEM_freeN(um->selected);
-// XXX if(um->retopo_paint_data) retopo_free_paint_data(um->retopo_paint_data);
- CustomData_free(&um->vdata, um->totvert);
- CustomData_free(&um->edata, um->totedge);
- CustomData_free(&um->fdata, um->totface);
- MEM_freeN(um);
-}
-
-static void *editMesh_to_undoMesh(void *emv)
-{
- EditMesh *em= (EditMesh *)emv;
- UndoMesh *um;
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
- EditSelection *ese;
- EditVertC *evec=NULL;
- EditEdgeC *eedc=NULL;
- EditFaceC *efac=NULL;
- EditSelectionC *esec=NULL;
- int a;
-
- um= MEM_callocN(sizeof(UndoMesh), "undomesh");
-
- um->selectmode = em->selectmode;
- um->shapenr = em->shapenr;
-
- for(eve=em->verts.first; eve; eve= eve->next) um->totvert++;
- for(eed=em->edges.first; eed; eed= eed->next) um->totedge++;
- for(efa=em->faces.first; efa; efa= efa->next) um->totface++;
- for(ese=em->selected.first; ese; ese=ese->next) um->totsel++;
- /* malloc blocks */
-
- if(um->totvert) evec= um->verts= MEM_callocN(um->totvert*sizeof(EditVertC), "allvertsC");
- if(um->totedge) eedc= um->edges= MEM_callocN(um->totedge*sizeof(EditEdgeC), "alledgesC");
- if(um->totface) efac= um->faces= MEM_callocN(um->totface*sizeof(EditFaceC), "allfacesC");
- if(um->totsel) esec= um->selected= MEM_callocN(um->totsel*sizeof(EditSelectionC), "allselections");
-
- if(um->totvert) CustomData_copy(&em->vdata, &um->vdata, CD_MASK_EDITMESH, CD_CALLOC, um->totvert);
- if(um->totedge) CustomData_copy(&em->edata, &um->edata, CD_MASK_EDITMESH, CD_CALLOC, um->totedge);
- if(um->totface) CustomData_copy(&em->fdata, &um->fdata, CD_MASK_EDITMESH, CD_CALLOC, um->totface);
-
- /* now copy vertices */
- a = 0;
- for(eve=em->verts.first; eve; eve= eve->next, evec++, a++) {
- VECCOPY(evec->co, eve->co);
- VECCOPY(evec->no, eve->no);
-
- evec->f= eve->f;
- evec->h= eve->h;
- evec->keyindex= eve->keyindex;
- eve->tmp.l = a; /*store index*/
- evec->bweight= (short)(eve->bweight*255.0);
-
- CustomData_from_em_block(&em->vdata, &um->vdata, eve->data, a);
- }
-
- /* copy edges */
- a = 0;
- for(eed=em->edges.first; eed; eed= eed->next, eedc++, a++) {
- eedc->v1= (int)eed->v1->tmp.l;
- eedc->v2= (int)eed->v2->tmp.l;
- eedc->f= eed->f;
- eedc->h= eed->h;
- eedc->seam= eed->seam;
- eedc->sharp= eed->sharp;
- eedc->crease= (short)(eed->crease*255.0);
- eedc->bweight= (short)(eed->bweight*255.0);
- eedc->fgoni= eed->fgoni;
- eed->tmp.l = a; /*store index*/
- CustomData_from_em_block(&em->edata, &um->edata, eed->data, a);
-
- }
-
- /* copy faces */
- a = 0;
- for(efa=em->faces.first; efa; efa= efa->next, efac++, a++) {
- efac->v1= (int)efa->v1->tmp.l;
- efac->v2= (int)efa->v2->tmp.l;
- efac->v3= (int)efa->v3->tmp.l;
- if(efa->v4) efac->v4= (int)efa->v4->tmp.l;
- else efac->v4= -1;
-
- efac->mat_nr= efa->mat_nr;
- efac->flag= efa->flag;
- efac->f= efa->f;
- efac->h= efa->h;
- efac->fgonf= efa->fgonf;
-
- efa->tmp.l = a; /*store index*/
-
- CustomData_from_em_block(&em->fdata, &um->fdata, efa->data, a);
- }
-
- a = 0;
- for(ese=em->selected.first; ese; ese=ese->next, esec++){
- esec->type = ese->type;
- if(ese->type == EDITVERT) a = esec->index = ((EditVert*)ese->data)->tmp.l;
- else if(ese->type == EDITEDGE) a = esec->index = ((EditEdge*)ese->data)->tmp.l;
- else if(ese->type == EDITFACE) a = esec->index = ((EditFace*)ese->data)->tmp.l;
- }
-
-// XXX um->retopo_paint_data= retopo_paint_data_copy(em->retopo_paint_data);
-// um->retopo_mode= scene->toolsettings->retopo_mode;
-
- return um;
-}
-
-static void undoMesh_to_editMesh(void *umv, void *emv)
-{
- EditMesh *em= (EditMesh *)emv;
- UndoMesh *um= (UndoMesh *)umv;
- EditVert *eve, **evar=NULL;
- EditEdge *eed;
- EditFace *efa;
- EditSelection *ese;
- EditVertC *evec;
- EditEdgeC *eedc;
- EditFaceC *efac;
- EditSelectionC *esec;
- int a=0;
-
- free_editMesh(em);
-
- /* malloc blocks */
- memset(em, 0, sizeof(EditMesh));
-
- em->selectmode = um->selectmode;
- em->shapenr = um->shapenr;
-
- init_editmesh_fastmalloc(em, um->totvert, um->totedge, um->totface);
-
- CustomData_free(&em->vdata, 0);
- CustomData_free(&em->edata, 0);
- CustomData_free(&em->fdata, 0);
-
- CustomData_copy(&um->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
- CustomData_copy(&um->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0);
- CustomData_copy(&um->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
-
- /* now copy vertices */
-
- if(um->totvert) evar= MEM_mallocN(um->totvert*sizeof(EditVert *), "vertex ar");
- for(a=0, evec= um->verts; a<um->totvert; a++, evec++) {
- eve= addvertlist(em, evec->co, NULL);
- evar[a]= eve;
-
- VECCOPY(eve->no, evec->no);
- eve->f= evec->f;
- eve->h= evec->h;
- eve->keyindex= evec->keyindex;
- eve->bweight= ((float)evec->bweight)/255.0f;
-
- CustomData_to_em_block(&um->vdata, &em->vdata, a, &eve->data);
- }
-
- /* copy edges */
- for(a=0, eedc= um->edges; a<um->totedge; a++, eedc++) {
- eed= addedgelist(em, evar[eedc->v1], evar[eedc->v2], NULL);
-
- eed->f= eedc->f;
- eed->h= eedc->h;
- eed->seam= eedc->seam;
- eed->sharp= eedc->sharp;
- eed->fgoni= eedc->fgoni;
- eed->crease= ((float)eedc->crease)/255.0f;
- eed->bweight= ((float)eedc->bweight)/255.0f;
- CustomData_to_em_block(&um->edata, &em->edata, a, &eed->data);
- }
-
- /* copy faces */
- for(a=0, efac= um->faces; a<um->totface; a++, efac++) {
- if(efac->v4 != -1)
- efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], evar[efac->v4], NULL, NULL);
- else
- efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], NULL, NULL ,NULL);
-
- efa->mat_nr= efac->mat_nr;
- efa->flag= efac->flag;
- efa->f= efac->f;
- efa->h= efac->h;
- efa->fgonf= efac->fgonf;
-
- CustomData_to_em_block(&um->fdata, &em->fdata, a, &efa->data);
- }
-
- end_editmesh_fastmalloc();
- if(evar) MEM_freeN(evar);
-
- em->totvert = um->totvert;
- em->totedge = um->totedge;
- em->totface = um->totface;
- /*restore stored editselections*/
- if(um->totsel){
- EM_init_index_arrays(em, 1,1,1);
- for(a=0, esec= um->selected; a<um->totsel; a++, esec++){
- ese = MEM_callocN(sizeof(EditSelection), "Edit Selection");
- ese->type = esec->type;
- if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(esec->index); else
- if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(esec->index); else
- if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(esec->index);
- BLI_addtail(&(em->selected),ese);
- }
- EM_free_index_arrays();
- }
-
- /* restore total selections */
- EM_nvertices_selected(em);
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-
-// XXX retopo_free_paint();
-// em->retopo_paint_data= retopo_paint_data_copy(um->retopo_paint_data);
-// scene->toolsettings->retopo_mode= um->retopo_mode;
-// if(scene->toolsettings->retopo_mode) {
-// XXX if(G.vd->depths) G.vd->depths->damaged= 1;
-// retopo_queue_updates(G.vd);
-// retopo_paint_view_update(G.vd);
-// }
-
-}
-
-static void *getEditMesh(bContext *C)
-{
- Object *obedit= CTX_data_edit_object(C);
- if(obedit && obedit->type==OB_MESH) {
- Mesh *me= obedit->data;
- return me->edit_mesh;
- }
- return NULL;
-}
-
-/* and this is all the undo system needs to know */
-void undo_push_mesh(bContext *C, const char *name)
-{
- undo_editmode_push(C, name, getEditMesh, free_undoMesh, undoMesh_to_editMesh, editMesh_to_undoMesh, NULL);
-}
-
-
-
-/* *************** END UNDO *************/
-
-static EditVert **g_em_vert_array = NULL;
-static EditEdge **g_em_edge_array = NULL;
-static EditFace **g_em_face_array = NULL;
-
-void EM_init_index_arrays(EditMesh *em, int forVert, int forEdge, int forFace)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
- int i;
-
- if (forVert) {
- em->totvert= BLI_countlist(&em->verts);
-
- if(em->totvert) {
- g_em_vert_array = MEM_mallocN(sizeof(*g_em_vert_array)*em->totvert, "em_v_arr");
-
- for (i=0,eve=em->verts.first; eve; i++,eve=eve->next)
- g_em_vert_array[i] = eve;
- }
- }
-
- if (forEdge) {
- em->totedge= BLI_countlist(&em->edges);
-
- if(em->totedge) {
- g_em_edge_array = MEM_mallocN(sizeof(*g_em_edge_array)*em->totedge, "em_e_arr");
-
- for (i=0,eed=em->edges.first; eed; i++,eed=eed->next)
- g_em_edge_array[i] = eed;
- }
- }
-
- if (forFace) {
- em->totface= BLI_countlist(&em->faces);
-
- if(em->totface) {
- g_em_face_array = MEM_mallocN(sizeof(*g_em_face_array)*em->totface, "em_f_arr");
-
- for (i=0,efa=em->faces.first; efa; i++,efa=efa->next)
- g_em_face_array[i] = efa;
- }
- }
-}
-
-void EM_free_index_arrays(void)
-{
- if (g_em_vert_array) MEM_freeN(g_em_vert_array);
- if (g_em_edge_array) MEM_freeN(g_em_edge_array);
- if (g_em_face_array) MEM_freeN(g_em_face_array);
- g_em_vert_array = NULL;
- g_em_edge_array = NULL;
- g_em_face_array = NULL;
-}
-
-EditVert *EM_get_vert_for_index(int index)
-{
- return g_em_vert_array?g_em_vert_array[index]:NULL;
-}
-
-EditEdge *EM_get_edge_for_index(int index)
-{
- return g_em_edge_array?g_em_edge_array[index]:NULL;
-}
-
-EditFace *EM_get_face_for_index(int index)
-{
- return g_em_face_array?g_em_face_array[index]:NULL;
-}
-
-/* can we edit UV's for this mesh?*/
-int EM_texFaceCheck(EditMesh *em)
-{
- /* some of these checks could be a touch overkill */
- if ( (em) &&
- (em->faces.first) &&
- (CustomData_has_layer(&em->fdata, CD_MTFACE)))
- return 1;
- return 0;
-}
-
-/* can we edit colors for this mesh?*/
-int EM_vertColorCheck(EditMesh *em)
-{
- /* some of these checks could be a touch overkill */
- if ( (em) &&
- (em->faces.first) &&
- (CustomData_has_layer(&em->fdata, CD_MCOL)))
- return 1;
- return 0;
-}
-
-
-void em_setup_viewcontext(bContext *C, ViewContext *vc)
-{
- view3d_set_viewcontext(C, vc);
-
- if(vc->obedit) {
- Mesh *me= vc->obedit->data;
- vc->em= me->edit_mesh;
- }
-}
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
deleted file mode 100644
index 08b2ff5c0ad..00000000000
--- a/source/blender/editors/mesh/editmesh_add.c
+++ /dev/null
@@ -1,1768 +0,0 @@
-/*
- * $Id$
- *
- * ***** 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) 2004 by Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-
-#include "RNA_define.h"
-#include "RNA_access.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_editVert.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_library.h"
-#include "BKE_mesh.h"
-#include "BKE_report.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_mesh.h"
-#include "ED_screen.h"
-#include "ED_transform.h"
-#include "ED_view3d.h"
-#include "ED_object.h"
-
-#include "mesh_intern.h"
-
-/* bpymenu removed XXX */
-
-/* XXX */
-#define add_numbut(a, b, c, d, e, f, g) {}
-/* XXX */
-
-static float icovert[12][3] = {
- {0.0f,0.0f,-200.0f},
- {144.72f, -105.144f,-89.443f},
- {-55.277f, -170.128,-89.443f},
- {-178.885f,0.0f,-89.443f},
- {-55.277f,170.128f,-89.443f},
- {144.72f,105.144f,-89.443f},
- {55.277f,-170.128f,89.443f},
- {-144.72f,-105.144f,89.443f},
- {-144.72f,105.144f,89.443f},
- {55.277f,170.128f,89.443f},
- {178.885f,0.0f,89.443f},
- {0.0f,0.0f,200.0f}
-};
-static short icoface[20][3] = {
- {1,0,2},
- {1,0,5},
- {2,0,3},
- {3,0,4},
- {4,0,5},
- {1,5,10},
- {2,1,6},
- {3,2,7},
- {4,3,8},
- {5,4,9},
- {10,1,6},
- {6,2,7},
- {7,3,8},
- {8,4,9},
- {9,5,10},
- {6,10,11},
- {7,6,11},
- {8,7,11},
- {9,8,11},
- {10,9,11}
-};
-
-/* *************** add-click-mesh (extrude) operator ************** */
-
-static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
-{
- ViewContext vc;
- EditVert *eve;
- float min[3], max[3];
- int done= 0;
- short use_proj;
-
- em_setup_viewcontext(C, &vc);
-
- use_proj= (vc.scene->toolsettings->snap_flag & SCE_SNAP) && (vc.scene->toolsettings->snap_mode==SCE_SNAP_MODE_FACE);
-
- invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
-
- INIT_MINMAX(min, max);
-
- for(eve= vc.em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
- DO_MINMAX(eve->co, min, max);
- done= 1;
- }
- }
-
- /* call extrude? */
- if(done) {
- short rot_src= RNA_boolean_get(op->ptr, "rotate_source");
- EditEdge *eed;
- float vec[3], cent[3], mat[3][3];
- float nor[3]= {0.0, 0.0, 0.0};
-
- /* 2D normal calc */
- float mval_f[2];
-
- mval_f[0]= (float)event->mval[0];
- mval_f[1]= (float)event->mval[1];
-
- done= 0;
-
- /* calculate the normal for selected edges */
- for(eed= vc.em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- float co1[3], co2[3];
- mul_v3_m4v3(co1, vc.obedit->obmat, eed->v1->co);
- mul_v3_m4v3(co2, vc.obedit->obmat, eed->v2->co);
- project_float_noclip(vc.ar, co1, co1);
- project_float_noclip(vc.ar, co2, co2);
-
- /* 2D rotate by 90d while adding.
- * (x, y) = (y, -x)
- *
- * accumulate the screenspace normal in 2D,
- * with screenspace edge length weighting the result. */
- if(line_point_side_v2(co1, co2, mval_f) >= 0.0f) {
- nor[0] += (co1[1] - co2[1]);
- nor[1] += -(co1[0] - co2[0]);
- }
- else {
- nor[0] += (co2[1] - co1[1]);
- nor[1] += -(co2[0] - co1[0]);
- }
- done= 1;
- }
- }
-
- if(done) {
- float view_vec[3], cross[3];
-
- /* convert the 2D nomal into 3D */
- mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */
- mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */
-
- /* correct the normal to be aligned on the view plane */
- copy_v3_v3(view_vec, vc.rv3d->viewinv[2]);
- mul_mat3_m4_v3(vc.obedit->imat, view_vec);
- cross_v3_v3v3(cross, nor, view_vec);
- cross_v3_v3v3(nor, view_vec, cross);
- normalize_v3(nor);
- }
-
- /* center */
- mid_v3_v3v3(cent, min, max);
- copy_v3_v3(min, cent);
-
- mul_m4_v3(vc.obedit->obmat, min); // view space
- view3d_get_view_aligned_coordinate(&vc, min, event->mval);
- mul_m4_v3(vc.obedit->imat, min); // back in object space
-
- sub_v3_v3(min, cent);
-
- /* calculate rotation */
- unit_m3(mat);
- if(done) {
- float dot;
-
- copy_v3_v3(vec, min);
- normalize_v3(vec);
- dot= INPR(vec, nor);
-
- if( fabs(dot)<0.999) {
- float cross[3], si, q1[4];
-
- cross_v3_v3v3(cross, nor, vec);
- normalize_v3(cross);
- dot= 0.5f*saacos(dot);
-
- /* halve the rotation if its applied twice */
- if(rot_src) dot *= 0.5f;
-
- si= (float)sin(dot);
- q1[0]= (float)cos(dot);
- q1[1]= cross[0]*si;
- q1[2]= cross[1]*si;
- q1[3]= cross[2]*si;
- quat_to_mat3( mat,q1);
- }
- }
-
- if(rot_src) {
- rotateflag(vc.em, SELECT, cent, mat);
- /* also project the source, for retopo workflow */
- if(use_proj)
- EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);
- }
-
- extrudeflag(vc.obedit, vc.em, SELECT, nor, 0);
- rotateflag(vc.em, SELECT, cent, mat);
- translateflag(vc.em, SELECT, min);
-
- recalc_editnormals(vc.em);
- }
- else if(vc.em->selectmode & SCE_SELECT_VERTEX) {
-
- float mat[3][3],imat[3][3];
- float *curs= give_cursor(vc.scene, vc.v3d);
-
- copy_v3_v3(min, curs);
- view3d_get_view_aligned_coordinate(&vc, min, event->mval);
-
- eve= addvertlist(vc.em, 0, NULL);
-
- copy_m3_m4(mat, vc.obedit->obmat);
- invert_m3_m3(imat, mat);
-
- copy_v3_v3(eve->co, min);
- mul_m3_v3(imat, eve->co);
- sub_v3_v3v3(eve->co, eve->co, vc.obedit->obmat[3]);
-
- eve->f= SELECT;
- }
-
- if(use_proj)
- EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);
-
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, vc.obedit->data);
- DAG_id_tag_update(vc.obedit->data, 0);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Duplicate or Extrude at 3D Cursor";
- ot->description= "Duplicate and extrude selected vertices, edges or faces towards 3D Cursor";
- ot->idname= "MESH_OT_dupli_extrude_cursor";
-
- /* api callbacks */
- ot->invoke= dupli_extrude_cursor;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "rotate_source", 1, "Rotate Source", "Rotate initial selection giving better shape");
-}
-
-
-/* ********************** */
-
-/* selected faces get hidden edges */
-static int make_fgon(EditMesh *em, wmOperator *op, int make)
-{
- EditFace *efa;
- EditEdge *eed;
- EditVert *eve;
- float *nor=NULL; // reference
- int done=0;
-
- if(make==0) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- efa->fgonf= 0;
- efa->e1->h &= ~EM_FGON;
- efa->e2->h &= ~EM_FGON;
- efa->e3->h &= ~EM_FGON;
- if(efa->e4) efa->e4->h &= ~EM_FGON;
- done= 1;
- }
- }
- EM_fgon_flags(em); // redo flags and indices for fgons
-
- return done;
- }
-
- /* tagging edges. rule is:
- - edge used by exactly 2 selected faces
- - no vertices allowed with only tagged edges (return)
- - face normals are allowed to difffer
-
- */
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0; // amount of selected
- eed->f2= 0; // amount of unselected
- }
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- if(nor==NULL) nor= efa->n;
- if(efa->e1->f1 < 3) efa->e1->f1++;
- if(efa->e2->f1 < 3) efa->e2->f1++;
- if(efa->e3->f1 < 3) efa->e3->f1++;
- if(efa->e4 && efa->e4->f1 < 3) efa->e4->f1++;
- }
- else {
- if(efa->e1->f2 < 3) efa->e1->f2++;
- if(efa->e2->f2 < 3) efa->e2->f2++;
- if(efa->e3->f2 < 3) efa->e3->f2++;
- if(efa->e4 && efa->e4->f2 < 3) efa->e4->f2++;
- }
- }
- // now eed->f1 becomes tagged edge
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f1==2 && eed->f2==0) eed->f1= 1;
- else eed->f1= 0;
- }
-
- // no vertices allowed with only tagged edges
- for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f1) {
- eed->v1->f1 |= 1;
- eed->v2->f1 |= 1;
- }
- else {
- eed->v1->f1 |= 2;
- eed->v2->f1 |= 2;
- }
- }
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f1==1) break;
- }
- if(eve) {
- BKE_report(op->reports, RPT_WARNING, "Cannot make a polygon with interior vertices");
- return 0;
- }
-
- // check for faces
- if(nor==NULL) {
- BKE_report(op->reports, RPT_WARNING, "No faces were selected to make FGon");
- return 0;
- }
-
- // and there we go
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f1) {
- eed->h |= EM_FGON;
- done= 1;
- }
- }
-
- if(done)
- EM_fgon_flags(em); // redo flags and indices for fgons
- return done;
-}
-
-static int make_fgon_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- if( make_fgon(em, op, 1) ) {
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
- }
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
-}
-
-void MESH_OT_fgon_make(struct wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Make F-gon";
- ot->description= "Make fgon from selected faces";
- ot->idname= "MESH_OT_fgon_make";
-
- /* api callbacks */
- ot->exec= make_fgon_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static int clear_fgon_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- if( make_fgon(em, op, 0) ) {
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
- }
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
-}
-
-void MESH_OT_fgon_clear(struct wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Clear F-gon";
- ot->description= "Clear fgon from selected face";
- ot->idname= "MESH_OT_fgon_clear";
-
- /* api callbacks */
- ot->exec= clear_fgon_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-/* precondition; 4 vertices selected, check for 4 edges and create face */
-static EditFace *addface_from_edges(EditMesh *em)
-{
- EditEdge *eed, *eedar[4]={NULL, NULL, NULL, NULL};
- EditVert *v1=NULL, *v2=NULL, *v3=NULL, *v4=NULL;
- int a;
-
- /* find the 4 edges */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if( (eed->f & SELECT) || (eed->v1->f & eed->v2->f & SELECT) ) {
- if(eedar[0]==NULL) eedar[0]= eed;
- else if(eedar[1]==NULL) eedar[1]= eed;
- else if(eedar[2]==NULL) eedar[2]= eed;
- else eedar[3]= eed;
-
- }
- }
-
-
- if(eedar[3]) {
- /* first 2 points */
- v1= eedar[0]->v1;
- v2= eedar[0]->v2;
-
- /* find the 2 edges connected to first edge */
- for(a=1; a<4; a++) {
- if( eedar[a]->v1 == v2) v3= eedar[a]->v2;
- else if(eedar[a]->v2 == v2) v3= eedar[a]->v1;
- else if( eedar[a]->v1 == v1) v4= eedar[a]->v2;
- else if(eedar[a]->v2 == v1) v4= eedar[a]->v1;
- }
-
- /* verify if last edge exists */
- if(v3 && v4) {
- for(a=1; a<4; a++) {
- if( eedar[a]->v1==v3 && eedar[a]->v2==v4) break;
- if( eedar[a]->v2==v3 && eedar[a]->v1==v4) break;
- }
- if(a!=4) {
- return addfacelist(em, v1, v2, v3, v4, NULL, NULL);
- }
- }
- }
- return NULL;
-}
-
-/* ******************************* */
-
-/* this also allows to prevent triangles being made in quads */
-static int compareface_overlaps(EditFace *vl1, EditFace *vl2)
-{
- EditVert *v1, *v2, *v3, *v4;
- int equal= 0;
-
- v1= vl2->v1;
- v2= vl2->v2;
- v3= vl2->v3;
- v4= vl2->v4;
-
- if(vl1==vl2) return 0;
-
- if(v4==NULL && vl1->v4==NULL) {
- if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1) equal++;
- if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2) equal++;
- if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3) equal++;
- }
- else {
- if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1 || vl1->v4==v1) equal++;
- if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2 || vl1->v4==v2) equal++;
- if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3 || vl1->v4==v3) equal++;
- if(vl1->v1==v4 || vl1->v2==v4 || vl1->v3==v4 || vl1->v4==v4) equal++;
- }
-
- if(v4 && vl1->v4) {
- if(equal==4) return 1;
- }
- else
- if(equal>=3) return 1;
-
- return 0;
-}
-
-/* checks for existence, and for tria overlapping inside quad */
-static EditFace *exist_face_overlaps(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4)
-{
- EditFace *efa, efatest;
-
- efatest.v1= v1;
- efatest.v2= v2;
- efatest.v3= v3;
- efatest.v4= v4;
-
- efa= em->faces.first;
- while(efa) {
- if(compareface_overlaps(&efatest, efa)) return efa;
- efa= efa->next;
- }
- return NULL;
-}
-
-/* will be new face smooth or solid? depends on smoothness of face neighbours
- * of new face, if function return 1, then new face will be smooth, when functio
- * will return zero, then new face will be solid */
-static void fix_new_face(EditMesh *em, EditFace *eface)
-{
- struct EditFace *efa;
- struct EditEdge *eed=NULL;
- struct EditVert *v1 = eface->v1, *v2 = eface->v2, *v3 = eface->v3, *v4 = eface->v4;
- struct EditVert *ev1=NULL, *ev2=NULL;
- short smooth=0; /* "total smoothnes" of faces in neighbourhood */
- short coef; /* "weight" of smoothness */
- short count=0; /* number of edges with same direction as eface */
- short vi00=0, vi01=0, vi10=0, vi11=0; /* vertex indexes */
-
- efa = em->faces.first;
-
- while(efa) {
-
- if(efa==eface) {
- efa = efa->next;
- continue;
- }
-
- coef = 0;
- ev1 = ev2 = NULL;
- eed = NULL;
-
- if(efa->v1==v1 || efa->v2==v1 || efa->v3==v1 || efa->v4==v1) {
- ev1 = v1;
- coef++;
- }
- if(efa->v1==v2 || efa->v2==v2 || efa->v3==v2 || efa->v4==v2) {
- if(ev1) ev2 = v2;
- else ev1 = v2;
- coef++;
- }
- if(efa->v1==v3 || efa->v2==v3 || efa->v3==v3 || efa->v4==v3) {
- if(coef<2) {
- if(ev1) ev2 = v3;
- else ev1 = v3;
- }
- coef++;
- }
- if((v4) && (efa->v1==v4 || efa->v2==v4 || efa->v3==v4 || efa->v4==v4)) {
- if(ev1 && coef<2) ev2 = v4;
- coef++;
- }
-
- /* "democracy" of smoothness */
- if(efa->flag & ME_SMOOTH)
- smooth += coef;
- else
- smooth -= coef;
-
- /* try to find edge using vertexes ev1 and ev2 */
- if((ev1) && (ev2) && (ev1!=ev2)) eed = findedgelist(em, ev1, ev2);
-
- /* has bordering edge of efa same direction as edge of eface ? */
- if(eed) {
- if(eed->v1==v1) vi00 = 1;
- else if(eed->v1==v2) vi00 = 2;
- else if(eed->v1==v3) vi00 = 3;
- else if(v4 && eed->v1==v4) vi00 = 4;
-
- if(eed->v2==v1) vi01 = 1;
- else if(eed->v2==v2) vi01 = 2;
- else if(eed->v2==v3) vi01 = 3;
- else if(v4 && eed->v2==v4) vi01 = 4;
-
- if(v4) {
- if(vi01==1 && vi00==4) vi00 = 0;
- if(vi01==4 && vi00==1) vi01 = 0;
- }
- else {
- if(vi01==1 && vi00==3) vi00 = 0;
- if(vi01==3 && vi00==1) vi01 = 0;
- }
-
- if(eed->v1==efa->v1) vi10 = 1;
- else if(eed->v1==efa->v2) vi10 = 2;
- else if(eed->v1==efa->v3) vi10 = 3;
- else if(efa->v4 && eed->v1==efa->v4) vi10 = 4;
-
- if(eed->v2==efa->v1) vi11 = 1;
- else if(eed->v2==efa->v2) vi11 = 2;
- else if(eed->v2==efa->v3) vi11 = 3;
- else if(efa->v4 && eed->v2==efa->v4) vi11 = 4;
-
- if(efa->v4) {
- if(vi11==1 && vi10==4) vi10 = 0;
- if(vi11==4 && vi10==1) vi11 = 0;
- }
- else {
- if(vi11==1 && vi10==3) vi10 = 0;
- if(vi11==3 && vi10==1) vi11 = 0;
- }
-
- if(((vi00>vi01) && (vi10>vi11)) ||
- ((vi00<vi01) && (vi10<vi11)))
- count++;
- else
- count--;
- }
-
- efa = efa->next;
- }
-
- /* set up smoothness according voting of face in neighbourhood */
- if(smooth >= 0)
- eface->flag |= ME_SMOOTH;
- else
- eface->flag &= ~ME_SMOOTH;
-
- /* flip face, when too much "face normals" in neighbourhood is different */
- if(count > 0) {
- flipface(em, eface);
- }
-}
-
-/* only adds quads or trias when there's edges already */
-static void addfaces_from_edgenet(EditMesh *em)
-{
- EditVert *eve1, *eve2, *eve3, *eve4;
-
- for(eve1= em->verts.first; eve1; eve1= eve1->next) {
- for(eve2= em->verts.first; (eve1->f & 1) && eve2; eve2= eve2->next) {
- if(findedgelist(em, eve1,eve2)) {
- for(eve3= em->verts.first; (eve2->f & 1) && eve3; eve3= eve3->next) {
- if((eve2!=eve3 && (eve3->f & 1) && findedgelist(em, eve1,eve3))) {
- EditEdge *sh_edge= NULL;
- EditVert *sh_vert= NULL;
-
- sh_edge= findedgelist(em, eve2,eve3);
-
- if(sh_edge) { /* Add a triangle */
- if(!exist_face_overlaps(em, eve1,eve2,eve3,NULL))
- fix_new_face(em, addfacelist(em, eve1,eve2,eve3,NULL,NULL,NULL));
- }
- else { /* Check for a shared vertex */
- for(eve4= em->verts.first; eve4; eve4= eve4->next) {
- if(eve4!=eve1 && eve4!=eve2 && eve4!=eve3 && (eve4->f & 1) &&
- !findedgelist(em, eve1,eve4) && findedgelist(em, eve2,eve4) &&
- findedgelist(em, eve3,eve4)) {
- sh_vert= eve4;
- break;
- }
- }
-
- if(sh_vert) {
- if(sh_vert) {
- if(!exist_face_overlaps(em, eve1,eve2,eve4,eve3))
- fix_new_face(em, addfacelist(em, eve1,eve2,eve4,eve3,NULL,NULL));
- }
- }
- }
- }
- }
- }
- }
- }
-
- EM_select_flush(em);
-
-// XXX DAG_id_tag_update(obedit->data, 0);
-}
-
-static void addedgeface_mesh(EditMesh *em, wmOperator *op)
-{
- EditVert *eve, *neweve[4];
- EditEdge *eed;
- EditFace *efa;
- short amount=0;
-
- /* how many selected ? */
- if(em->selectmode & SCE_SELECT_EDGE) {
- /* in edge mode finding selected vertices means flushing down edge codes... */
- /* can't make face with only edge selection info... */
- EM_selectmode_set(em);
- }
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
- amount++;
- if(amount>4) break;
- neweve[amount-1]= eve;
- }
- }
-
- if(amount==2) {
- eed= addedgelist(em, neweve[0], neweve[1], NULL);
- EM_select_edge(eed, 1);
-
- // XXX DAG_id_tag_update(obedit->data, 0);
- return;
- }
- else if(amount > 4) {
- addfaces_from_edgenet(em);
- return;
- }
- else if(amount<2) {
- BKE_report(op->reports, RPT_WARNING, "More vertices are needed to make an edge/face");
- return;
- }
-
- efa= NULL; // check later
-
- if(amount==3) {
-
- if(exist_face_overlaps(em, neweve[0], neweve[1], neweve[2], NULL)==0) {
- efa= addfacelist(em, neweve[0], neweve[1], neweve[2], 0, NULL, NULL);
- EM_select_face(efa, 1);
- }
- else BKE_report(op->reports, RPT_WARNING, "The selected vertices already form a face");
- }
- else if(amount==4) {
- /* this test survives when theres 2 triangles */
- if(exist_face(em, neweve[0], neweve[1], neweve[2], neweve[3])==0) {
- int tria= 0;
-
- /* remove trias if they exist, 4 cases.... */
- if(exist_face(em, neweve[0], neweve[1], neweve[2], NULL)) tria++;
- if(exist_face(em, neweve[0], neweve[1], neweve[3], NULL)) tria++;
- if(exist_face(em, neweve[0], neweve[2], neweve[3], NULL)) tria++;
- if(exist_face(em, neweve[1], neweve[2], neweve[3], NULL)) tria++;
-
- if(tria==2) join_triangles(em);
- else if(exist_face_overlaps(em, neweve[0], neweve[1], neweve[2], neweve[3])==0) {
- /* If there are 4 Verts, But more selected edges, we need to call addfaces_from_edgenet */
- EditEdge *eedcheck;
- int count;
- count = 0;
- for(eedcheck= em->edges.first; eedcheck; eedcheck= eedcheck->next) {
- if(eedcheck->f & SELECT) {
- count++;
- }
- }
-
- if(count++ > 4){
- addfaces_from_edgenet(em);
- return;
- } else {
- /* if 4 edges exist, we just create the face, convex or not */
- efa= addface_from_edges(em);
- if(efa==NULL) {
-
- /* the order of vertices can be anything, 6 cases to check */
- if( convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co) ) {
- efa= addfacelist(em, neweve[0], neweve[1], neweve[2], neweve[3], NULL, NULL);
- }
- else if( convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co) ) {
- efa= addfacelist(em, neweve[0], neweve[2], neweve[3], neweve[1], NULL, NULL);
- }
- else if( convex(neweve[0]->co, neweve[2]->co, neweve[1]->co, neweve[3]->co) ) {
- efa= addfacelist(em, neweve[0], neweve[2], neweve[1], neweve[3], NULL, NULL);
- }
- else if( convex(neweve[0]->co, neweve[1]->co, neweve[3]->co, neweve[2]->co) ) {
- efa= addfacelist(em, neweve[0], neweve[1], neweve[3], neweve[2], NULL, NULL);
- }
- else if( convex(neweve[0]->co, neweve[3]->co, neweve[2]->co, neweve[1]->co) ) {
- efa= addfacelist(em, neweve[0], neweve[3], neweve[2], neweve[1], NULL, NULL);
- }
- else if( convex(neweve[0]->co, neweve[3]->co, neweve[1]->co, neweve[2]->co) ) {
- efa= addfacelist(em, neweve[0], neweve[3], neweve[1], neweve[2], NULL, NULL);
- }
- else BKE_report(op->reports, RPT_WARNING, "cannot find nice quad from concave set of vertices");
-
- }
- }
- }
- else BKE_report(op->reports, RPT_WARNING, "The selected vertices already form a face");
- }
- else BKE_report(op->reports, RPT_WARNING, "The selected vertices already form a face");
- }
-
- if(efa) {
- EM_select_face(efa, 1);
-
- fix_new_face(em, efa);
-
- recalc_editnormals(em);
- }
- }
-
-static int addedgeface_mesh_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- addedgeface_mesh(em, op);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_edge_face_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Make Edge/Face";
- ot->description= "Add an edge or face to selected";
- ot->idname= "MESH_OT_edge_face_add";
-
- /* api callbacks */
- ot->exec= addedgeface_mesh_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
-}
-
-
-
-/* ************************ primitives ******************* */
-
-// HACK: these can also be found in cmoview.tga.c, but are here so that they can be found by linker
-// this hack is only used so that scons+mingw + split-sources hack works
- // ------------------------------- start copied code
-/* these are not the monkeys you are looking for */
-static int monkeyo= 4;
-static int monkeynv= 271;
-static int monkeynf= 250;
-static signed char monkeyv[271][3]= {
-{-71,21,98},{-63,12,88},{-57,7,74},{-82,-3,79},{-82,4,92},
-{-82,17,100},{-92,21,102},{-101,12,95},{-107,7,83},
-{-117,31,84},{-109,31,95},{-96,31,102},{-92,42,102},
-{-101,50,95},{-107,56,83},{-82,66,79},{-82,58,92},
-{-82,46,100},{-71,42,98},{-63,50,88},{-57,56,74},
-{-47,31,72},{-55,31,86},{-67,31,97},{-66,31,99},
-{-70,43,100},{-82,48,103},{-93,43,105},{-98,31,105},
-{-93,20,105},{-82,31,106},{-82,15,103},{-70,20,100},
-{-127,55,95},{-127,45,105},{-127,-87,94},{-127,-41,100},
-{-127,-24,102},{-127,-99,92},{-127,52,77},{-127,73,73},
-{-127,115,-70},{-127,72,-109},{-127,9,-106},{-127,-49,-45},
-{-101,-24,72},{-87,-56,73},{-82,-89,73},{-80,-114,68},
-{-85,-121,67},{-104,-124,71},{-127,-126,74},{-71,-18,68},
-{-46,-5,69},{-21,19,57},{-17,55,76},{-36,62,80},
-{-64,77,88},{-86,97,94},{-107,92,97},{-119,63,96},
-{-106,53,99},{-111,39,98},{-101,12,95},{-79,2,90},
-{-64,8,86},{-47,24,83},{-45,38,83},{-50,48,85},
-{-72,56,92},{-95,60,97},{-127,-98,94},{-113,-92,94},
-{-112,-107,91},{-119,-113,89},{-127,-114,88},{-127,-25,96},
-{-127,-18,95},{-114,-19,95},{-111,-29,96},{-116,-37,95},
-{-76,-6,86},{-48,7,80},{-34,26,77},{-32,48,84},
-{-39,53,93},{-71,70,102},{-87,82,107},{-101,79,109},
-{-114,55,108},{-111,-13,104},{-100,-57,91},{-95,-90,88},
-{-93,-105,85},{-97,-117,81},{-106,-119,81},{-127,-121,82},
-{-127,6,93},{-127,27,98},{-85,61,95},{-106,18,96},
-{-110,27,97},{-112,-88,94},{-117,-57,96},{-127,-57,96},
-{-127,-42,95},{-115,-35,100},{-110,-29,102},{-113,-17,100},
-{-122,-16,100},{-127,-26,106},{-121,-19,104},{-115,-20,104},
-{-113,-29,106},{-117,-32,103},{-127,-37,103},{-94,-40,71},
-{-106,-31,91},{-104,-40,91},{-97,-32,71},{-127,-112,88},
-{-121,-111,88},{-115,-105,91},{-115,-95,93},{-127,-100,84},
-{-115,-96,85},{-115,-104,82},{-121,-109,81},{-127,-110,81},
-{-105,28,100},{-103,20,99},{-84,55,97},{-92,54,99},
-{-73,51,99},{-55,45,89},{-52,37,88},{-53,25,87},
-{-66,13,92},{-79,8,95},{-98,14,100},{-104,38,100},
-{-100,48,100},{-97,46,97},{-102,38,97},{-96,16,97},
-{-79,11,93},{-68,15,90},{-57,27,86},{-56,36,86},
-{-59,43,87},{-74,50,96},{-91,51,98},{-84,52,96},
-{-101,22,96},{-102,29,96},{-113,59,78},{-102,85,79},
-{-84,88,76},{-65,71,71},{-40,58,63},{-25,52,59},
-{-28,21,48},{-50,0,53},{-71,-12,60},{-127,115,37},
-{-127,126,-10},{-127,-25,-86},{-127,-59,24},{-127,-125,59},
-{-127,-103,44},{-127,-73,41},{-127,-62,36},{-18,30,7},
-{-17,41,-6},{-28,34,-56},{-68,56,-90},{-33,-6,9},
-{-51,-16,-21},{-45,-1,-55},{-84,7,-85},{-97,-45,52},
-{-104,-53,33},{-90,-91,49},{-95,-64,50},{-85,-117,51},
-{-109,-97,47},{-111,-69,46},{-106,-121,56},{-99,-36,55},
-{-100,-29,60},{-101,-22,64},{-100,-50,21},{-89,-40,-34},
-{-83,-19,-69},{-69,111,-49},{-69,119,-9},{-69,109,30},
-{-68,67,55},{-34,52,43},{-46,58,36},{-45,90,7},
-{-25,72,16},{-25,79,-15},{-45,96,-25},{-45,87,-57},
-{-25,69,-46},{-48,42,-75},{-65,3,-70},{-22,42,-26},
-{-75,-22,19},{-72,-25,-27},{-13,52,-30},{-28,-18,-16},
-{6,-13,-42},{37,7,-55},{46,41,-54},{31,65,-54},
-{4,61,-40},{3,53,-37},{25,56,-50},{35,37,-52},
-{28,10,-52},{5,-5,-39},{-21,-9,-17},{-9,46,-28},
-{-6,39,-37},{-14,-3,-27},{6,0,-47},{25,12,-57},
-{31,32,-57},{23,46,-56},{4,44,-46},{-19,37,-27},
-{-20,22,-35},{-30,12,-35},{-22,11,-35},{-19,2,-35},
-{-23,-2,-35},{-34,0,-9},{-35,-3,-22},{-35,5,-24},
-{-25,26,-27},{-13,31,-34},{-13,30,-41},{-23,-2,-41},
-{-18,2,-41},{-21,10,-41},{-29,12,-41},{-19,22,-41},
-{6,42,-53},{25,44,-62},{34,31,-63},{28,11,-62},
-{7,0,-54},{-14,-2,-34},{-5,37,-44},{-13,14,-42},
-{-7,8,-43},{1,16,-47},{-4,22,-45},{3,30,-48},
-{8,24,-49},{15,27,-50},{12,35,-50},{4,56,-62},
-{33,60,-70},{48,38,-64},{41,7,-68},{6,-11,-63},
-{-26,-16,-42},{-17,49,-49},
-};
-
-static signed char monkeyf[250][4]= {
-{27,4,5,26}, {25,4,5,24}, {3,6,5,4}, {1,6,5,2}, {5,6,7,4},
-{3,6,7,2}, {5,8,7,6}, {3,8,7,4}, {7,8,9,6},
-{5,8,9,4}, {7,10,9,8}, {5,10,9,6}, {9,10,11,8},
-{7,10,11,6}, {9,12,11,10}, {7,12,11,8}, {11,6,13,12},
-{5,4,13,12}, {3,-2,13,12}, {-3,-4,13,12}, {-5,-10,13,12},
-{-11,-12,14,12}, {-13,-18,14,13}, {-19,4,5,13}, {10,12,4,4},
-{10,11,9,9}, {8,7,9,9}, {7,5,6,6}, {6,3,4,4},
-{5,1,2,2}, {4,-1,0,0}, {3,-3,-2,-2}, {22,67,68,23},
-{20,65,66,21}, {18,63,64,19}, {16,61,62,17}, {14,59,60,15},
-{12,19,48,57}, {18,19,48,47}, {18,19,48,47}, {18,19,48,47},
-{18,19,48,47}, {18,19,48,47}, {18,19,48,47}, {18,19,48,47},
-{18,19,48,47}, {18,-9,-8,47}, {18,27,45,46}, {26,55,43,44},
-{24,41,42,54}, {22,39,40,23}, {20,37,38,21}, {18,35,36,19},
-{16,33,34,17}, {14,31,32,15}, {12,39,30,13}, {11,48,45,38},
-{8,36,-19,9}, {8,-20,44,47}, {42,45,46,43}, {18,19,40,39},
-{16,17,38,37}, {14,15,36,35}, {32,44,43,33}, {12,33,32,42},
-{19,44,43,42}, {40,41,42,-27}, {8,9,39,-28}, {15,43,42,16},
-{13,43,42,14}, {11,43,42,12}, {9,-30,42,10}, {37,12,38,-32},
-{-33,37,45,46}, {-33,40,41,39}, {38,40,41,37}, {36,40,41,35},
-{34,40,41,33}, {36,39,38,37}, {35,40,39,38}, {1,2,14,21},
-{1,2,40,13}, {1,2,40,39}, {1,24,12,39}, {-34,36,38,11},
-{35,38,36,37}, {-37,8,35,37}, {-11,-12,-45,40}, {-11,-12,39,38},
-{-11,-12,37,36}, {-11,-12,35,34}, {33,34,40,41}, {33,34,38,39},
-{33,34,36,37}, {33,-52,34,35}, {33,37,36,34}, {33,35,34,34},
-{8,7,37,36}, {-32,7,35,46}, {-34,-33,45,46}, {4,-33,43,34},
-{-34,-33,41,42}, {-34,-33,39,40}, {-34,-33,37,38}, {-34,-33,35,36},
-{-34,-33,33,34}, {-34,-33,31,32}, {-34,-4,28,30}, {-5,-34,28,27},
-{-35,-44,36,27}, {26,35,36,45}, {24,25,44,45}, {25,23,44,42},
-{25,24,41,40}, {25,24,39,38}, {25,24,37,36}, {25,24,35,34},
-{25,24,33,32}, {25,24,31,30}, {15,24,29,38}, {25,24,27,26},
-{23,12,37,26}, {11,12,35,36}, {-86,-59,36,-80}, {-60,-61,36,35},
-{-62,-63,36,35}, {-64,-65,36,35}, {-66,-67,36,35}, {-68,-69,36,35},
-{-70,-71,36,35}, {-72,-73,36,35}, {-74,-75,36,35}, {42,43,53,58},
-{40,41,57,56}, {38,39,55,57}, {-81,-80,37,56}, {-83,-82,55,52},
-{-85,-84,51,49}, {-87,-86,48,49}, {47,50,51,48}, {46,48,51,49},
-{43,46,49,44}, {-92,-91,45,42}, {-23,49,50,-20}, {-94,40,48,-24},
-{-96,-22,48,49}, {-97,48,21,-90}, {-100,36,50,23}, {22,49,48,-100},
-{-101,47,46,22}, {21,45,35,25}, {33,34,44,41}, {13,14,28,24},
-{-107,26,30,-106}, {14,46,45,15}, {14,44,43,-110}, {-111,42,23,-110},
-{6,7,45,46}, {45,44,47,46}, {45,46,47,48}, {47,46,49,48},
-{17,49,47,48}, {17,36,46,48}, {35,36,44,45}, {35,36,40,43},
-{35,36,38,39}, {-4,-3,37,35}, {-123,34,33,1}, {-9,-8,-7,-6},
-{-10,-7,32,-125}, {-127,-11,-126,-126}, {-7,-6,5,31}, {4,5,33,30},
-{4,39,33,32}, {4,35,32,38}, {20,21,39,38}, {4,37,38,5},
-{-11,-10,36,3}, {-11,15,14,35}, {13,16,34,34}, {-13,14,13,13},
-{-3,1,30,29}, {-3,28,29,1}, {-2,31,28,-1}, {12,13,27,30},
-{-2,26,12,12}, {35,29,42,36}, {34,35,36,33}, {32,35,36,31},
-{30,35,36,29}, {28,35,36,27}, {26,35,36,25}, {34,39,38,35},
-{32,39,38,33}, {30,39,38,31}, {28,39,38,29}, {26,39,38,27},
-{25,31,32,38}, {-18,-17,45,44}, {-18,17,28,44}, {-24,-20,42,-23},
-{11,35,27,14}, {25,28,39,41}, {37,41,40,38}, {34,40,36,35},
-{32,40,39,33}, {30,39,31,40}, {21,29,39,22}, {-31,37,28,4},
-{-32,33,35,36}, {32,33,34,34}, {18,35,36,48}, {34,25,40,35},
-{24,25,38,39}, {24,25,36,37}, {24,25,34,35}, {24,25,32,33},
-{24,13,41,31}, {17,11,41,35}, {15,16,34,35}, {13,14,34,35},
-{11,12,34,35}, {9,10,34,35}, {7,8,34,35}, {26,25,37,36},
-{35,36,37,38}, {37,36,39,38}, {37,38,39,40}, {25,31,36,39},
-{18,34,35,30}, {17,22,30,33}, {19,29,21,20}, {16,26,29,17},
-{24,29,28,25}, {22,31,28,23}, {20,31,30,21}, {18,31,30,19},
-{16,30,17,17}, {-21,-22,35,34}, {-21,-22,33,32}, {-21,-22,31,30},
-{-21,-22,29,28}, {-21,-22,27,26}, {-28,-22,25,31}, {24,28,29,30},
-{23,24,26,27}, {23,24,25,25}, {-69,-35,-32,27}, {-70,26,25,-66},
-{-68,-67,24,-33},
-};
- // ------------------------------- end copied code
-
-
-#define PRIM_PLANE 0
-#define PRIM_CUBE 1
-#define PRIM_CIRCLE 4
-#define PRIM_CYLINDER 5
-#define PRIM_CONE 7
-#define PRIM_GRID 10
-#define PRIM_UVSPHERE 11
-#define PRIM_ICOSPHERE 12
-#define PRIM_MONKEY 13
-
-static void make_prim(Object *obedit, int type, float mat[4][4], int tot, int seg,
- int subdiv, float dia, float depth, int ext, int fill)
-{
- /*
- * type - for the type of shape
- * dia - the radius for cone,sphere cylinder etc.
- * depth -
- * ext - extrude
- * fill - end capping, and option to fill in circle
- * cent[3] - center of the data.
- * */
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- EditVert *eve, *v1=NULL, *v2, *v3, *v4=NULL, *vtop, *vdown;
- float phi, phid, vec[3];
- float q[4], cmat[3][3], nor[3]= {0.0, 0.0, 0.0};
- short a, b;
-
- EM_clear_flag_all(em, SELECT);
-
- phid= 2.0f*(float)M_PI/tot;
- phi= .25f*(float)M_PI;
-
- switch(type) {
- case PRIM_GRID: /* grid */
- /* clear flags */
- eve= em->verts.first;
- while(eve) {
- eve->f= 0;
- eve= eve->next;
- }
-
- /* one segment first: the X axis */
- phi = (2*dia)/(float)(tot-1);
- phid = (2*dia)/(float)(seg-1);
- for(a=tot-1;a>=0;a--) {
- vec[0] = (phi*a) - dia;
- vec[1]= - dia;
- vec[2]= 0.0f;
- eve= addvertlist(em, vec, NULL);
- eve->f= 1+2+4;
- if(a < tot -1) addedgelist(em, eve->prev, eve, NULL);
- }
- /* extrude and translate */
- vec[0]= vec[2]= 0.0;
- vec[1]= phid;
-
- for(a=0;a<seg-1;a++) {
- extrudeflag_vert(obedit, em, 2, nor, 0); // nor unused
- translateflag(em, 2, vec);
- }
-
- /* and now do imat */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & SELECT) {
- mul_m4_v3(mat,eve->co);
- }
- eve= eve->next;
- }
- break;
-
- case PRIM_UVSPHERE: /* UVsphere */
-
- /* clear all flags */
- eve= em->verts.first;
- while(eve) {
- eve->f= 0;
- eve= eve->next;
- }
-
- /* one segment first */
- phi= 0;
- phid/=2;
- for(a=0; a<=tot; a++) {
- vec[0]= dia*sin(phi);
- vec[1]= 0.0;
- vec[2]= dia*cos(phi);
- eve= addvertlist(em, vec, NULL);
- eve->f= 1+2+4;
- if(a==0) v1= eve;
- else addedgelist(em, eve->prev, eve, NULL);
- phi+= phid;
- }
-
- /* extrude and rotate */
- phi= M_PI/seg;
- q[0]= cos(phi);
- q[3]= sin(phi);
- q[1]=q[2]= 0;
- quat_to_mat3( cmat,q);
-
- for(a=0; a<seg; a++) {
- extrudeflag_vert(obedit, em, 2, nor, 0); // nor unused
- rotateflag(em, 2, v1->co, cmat);
- }
-
- removedoublesflag(em, 4, 0, 0.0001);
-
- /* and now do imat */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & SELECT) {
- mul_m4_v3(mat,eve->co);
- }
- eve= eve->next;
- }
- break;
- case PRIM_ICOSPHERE: /* Icosphere */
- {
- EditVert *eva[12];
- EditEdge *eed;
-
- /* clear all flags */
- eve= em->verts.first;
- while(eve) {
- eve->f= 0;
- eve= eve->next;
- }
- dia/=200;
- for(a=0;a<12;a++) {
- vec[0]= dia*icovert[a][0];
- vec[1]= dia*icovert[a][1];
- vec[2]= dia*icovert[a][2];
- eva[a]= addvertlist(em, vec, NULL);
- eva[a]->f= 1+2;
- }
- for(a=0;a<20;a++) {
- EditFace *evtemp;
- v1= eva[ icoface[a][0] ];
- v2= eva[ icoface[a][1] ];
- v3= eva[ icoface[a][2] ];
- evtemp = addfacelist(em, v1, v2, v3, 0, NULL, NULL);
- evtemp->e1->f = 1+2;
- evtemp->e2->f = 1+2;
- evtemp->e3->f = 1+2;
- }
-
- dia*=200;
- for(a=1; a<subdiv; a++) esubdivideflag(obedit, em, 2, dia, 0, B_SPHERE,1, SUBDIV_CORNER_PATH, 0);
- /* and now do imat */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & 2) {
- mul_m4_v3(mat,eve->co);
- }
- eve= eve->next;
- }
-
- // Clear the flag 2 from the edges
- for(eed=em->edges.first;eed;eed=eed->next){
- if(eed->f & 2){
- eed->f &= !2;
- }
- }
- }
- break;
- case PRIM_MONKEY: /* Monkey */
- {
- //extern int monkeyo, monkeynv, monkeynf;
- //extern signed char monkeyf[][4];
- //extern signed char monkeyv[][3];
- EditVert **tv= MEM_mallocN(sizeof(*tv)*monkeynv*2, "tv");
- int i;
-
- for (i=0; i<monkeynv; i++) {
- float v[3];
- v[0]= (monkeyv[i][0]+127)/128.0, v[1]= monkeyv[i][1]/128.0, v[2]= monkeyv[i][2]/128.0;
- tv[i]= addvertlist(em, v, NULL);
- tv[i]->f |= SELECT;
- tv[monkeynv+i]= (fabs(v[0]= -v[0])<0.001)?tv[i]:addvertlist(em, v, NULL);
- tv[monkeynv+i]->f |= SELECT;
- }
- for (i=0; i<monkeynf; i++) {
- addfacelist(em, tv[monkeyf[i][0]+i-monkeyo], tv[monkeyf[i][1]+i-monkeyo], tv[monkeyf[i][2]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL);
- addfacelist(em, tv[monkeynv+monkeyf[i][2]+i-monkeyo], tv[monkeynv+monkeyf[i][1]+i-monkeyo], tv[monkeynv+monkeyf[i][0]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeynv+monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL);
- }
-
- MEM_freeN(tv);
-
- /* and now do imat */
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
- mul_m4_v3(mat,eve->co);
- }
- }
- recalc_editnormals(em);
- }
- break;
- default: /* all types except grid, sphere... */
- if(type==PRIM_CONE);
- else if(ext==0)
- depth= 0.0f;
-
- /* first vertex at 0° for circular objects */
- if( ELEM3(type, PRIM_CIRCLE,PRIM_CYLINDER,PRIM_CONE) )
- phi = 0.0f;
-
- vtop= vdown= v1= v2= 0;
- for(b=0; b<=ext; b++) {
- for(a=0; a<tot; a++) {
-
- vec[0]= dia*sin(phi);
- vec[1]= dia*cos(phi);
- vec[2]= b?depth:-depth;
-
- mul_m4_v3(mat, vec);
- eve= addvertlist(em, vec, NULL);
- eve->f= SELECT;
- if(a==0) {
- if(b==0) v1= eve;
- else v2= eve;
- }
- phi+=phid;
- }
- }
-
- /* center vertices */
- /* type PRIM_CONE can only have 1 one side filled
- * if the cone has no capping, dont add vtop */
- if(type == PRIM_CONE || (fill && !ELEM(type, PRIM_PLANE, PRIM_CUBE))) {
- vec[0]= vec[1]= 0.0f;
- vec[2]= type==PRIM_CONE ? depth : -depth;
- mul_m4_v3(mat, vec);
- vdown= addvertlist(em, vec, NULL);
- if((ext || type==PRIM_CONE) && fill) {
- vec[0]= vec[1]= 0.0f;
- vec[2]= type==PRIM_CONE ? -depth : depth;
- mul_m4_v3(mat,vec);
- vtop= addvertlist(em, vec, NULL);
- }
- } else {
- vdown= v1;
- vtop= v2;
- }
- if(vtop) vtop->f= SELECT;
- if(vdown) vdown->f= SELECT;
-
- /* top and bottom face */
- if(fill || type==PRIM_CONE) {
- if(tot==4 && ELEM(type, PRIM_PLANE, PRIM_CUBE)) {
- v3= v1->next->next;
- if(ext) v4= v2->next->next;
-
- addfacelist(em, v3, v1->next, v1, v3->next, NULL, NULL);
- if(ext) addfacelist(em, v2, v2->next, v4, v4->next, NULL, NULL);
-
- }
- else {
- v3= v1;
- v4= v2;
- for(a=1; a<tot; a++) {
- addfacelist(em, vdown, v3, v3->next, 0, NULL, NULL);
- v3= v3->next;
- if(ext && fill) {
- addfacelist(em, vtop, v4, v4->next, 0, NULL, NULL);
- v4= v4->next;
- }
- }
- if(!ELEM(type, PRIM_PLANE, PRIM_CUBE)) {
- addfacelist(em, vdown, v3, v1, 0, NULL, NULL);
- if(ext) addfacelist(em, vtop, v4, v2, 0, NULL, NULL);
- }
- }
- }
- else if(type==PRIM_CIRCLE) { /* we need edges for a circle */
- v3= v1;
- for(a=1;a<tot;a++) {
- addedgelist(em, v3, v3->next, NULL);
- v3= v3->next;
- }
- addedgelist(em, v3, v1, NULL);
- }
- /* side faces */
- if(ext) {
- v3= v1;
- v4= v2;
- for(a=1; a<tot; a++) {
- addfacelist(em, v3, v3->next, v4->next, v4, NULL, NULL);
- v3= v3->next;
- v4= v4->next;
- }
- addfacelist(em, v3, v1, v2, v4, NULL, NULL);
- }
- else if(fill && type==PRIM_CONE) {
- /* add the bottom flat area of the cone
- * if capping is disabled dont bother */
- v3= v1;
- for(a=1; a<tot; a++) {
- addfacelist(em, vtop, v3->next, v3, 0, NULL, NULL);
- v3= v3->next;
- }
- addfacelist(em, vtop, v1, v3, 0, NULL, NULL);
- }
- }
-
- EM_stats_update(em);
- /* simple selection flush OK, based on fact it's a single model */
- EM_select_flush(em); /* flushes vertex -> edge -> face selection */
-
- if(type!=PRIM_PLANE && type!=PRIM_MONKEY)
- EM_recalc_normal_direction(em, 0, 0); /* otherwise monkey has eyes in wrong direction */
-
- BKE_mesh_end_editmesh(obedit->data, em);
-}
-
-/* ********* add primitive operators ************* */
-
-static const char *get_mesh_defname(int type)
-{
- switch (type) {
- case PRIM_PLANE: return "Plane";
- case PRIM_CUBE: return "Cube";
- case PRIM_CIRCLE: return "Circle";
- case PRIM_CYLINDER: return "Cylinder";
- case PRIM_CONE: return "Cone";
- case PRIM_GRID: return "Grid";
- case PRIM_UVSPHERE: return "Sphere";
- case PRIM_ICOSPHERE: return "Icosphere";
- case PRIM_MONKEY: return "Monkey";
- default:
- return "Mesh";
- }
-}
-
-static void make_prim_ext(bContext *C, float *loc, float *rot, int enter_editmode, unsigned int layer,
- int type, int tot, int seg,
- int subdiv, float dia, float depth, int ext, int fill)
-{
- Object *obedit= CTX_data_edit_object(C);
- int newob = 0;
- float mat[4][4];
- float scale;
-
- if(obedit==NULL || obedit->type!=OB_MESH) {
- obedit= ED_object_add_type(C, OB_MESH, loc, rot, FALSE, layer);
-
- rename_id((ID *)obedit, get_mesh_defname(type));
- rename_id((ID *)obedit->data, get_mesh_defname(type));
-
- /* create editmode */
- ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER); /* rare cases the active layer is messed up */
- newob = 1;
- }
- else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
-
- scale= ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
-
- dia *= scale;
- depth *= scale * 0.5f;
-
- make_prim(obedit, type, mat, tot, seg, subdiv, dia, depth, ext, fill);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
-
- /* userdef */
- if (newob && !enter_editmode) {
- ED_object_exit_editmode(C, EM_FREEDATA); /* adding EM_DO_UNDO messes up operator redo */
- }
- WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, obedit);
-}
-
-static int add_primitive_plane_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- /* sqrt(2.0f) - plane (diameter of 1.41 makes it unit size) */
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_PLANE, 4, 0, 0, sqrt(2.0f), 0.0f, 0, 1);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_plane_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Plane";
- ot->description= "Construct a filled planar mesh with 4 vertices";
- ot->idname= "MESH_OT_primitive_plane_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_plane_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_cube_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- /* sqrt(2.0f) - plane (diameter of 1.41 makes it unit size) */
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_CUBE, 4, 0, 0, sqrt(2.0f), 2.0f, 1, 1);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_cube_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Cube";
- ot->description= "Construct a cube mesh";
- ot->idname= "MESH_OT_primitive_cube_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_cube_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_circle_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_CIRCLE, RNA_int_get(op->ptr, "vertices"), 0, 0,
- RNA_float_get(op->ptr,"radius"), 0.0f, 0,
- RNA_boolean_get(op->ptr, "fill"));
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_circle_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Circle";
- ot->description= "Construct a circle mesh";
- ot->idname= "MESH_OT_primitive_circle_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_circle_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 3, 500);
- RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
- RNA_def_boolean(ot->srna, "fill", 0, "Fill", "");
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_CYLINDER, RNA_int_get(op->ptr, "vertices"), 0, 0,
- RNA_float_get(op->ptr,"radius"),
- RNA_float_get(op->ptr, "depth"), 1,
- RNA_boolean_get(op->ptr, "cap_ends"));
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_cylinder_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Cylinder";
- ot->description= "Construct a cylinder mesh";
- ot->idname= "MESH_OT_primitive_cylinder_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_cylinder_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 2, 500);
- RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
- RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
- RNA_def_boolean(ot->srna, "cap_ends", 1, "Cap Ends", "");
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_cone_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_CONE, RNA_int_get(op->ptr, "vertices"), 0, 0,
- RNA_float_get(op->ptr,"radius"), RNA_float_get(op->ptr, "depth"),
- 0, RNA_boolean_get(op->ptr, "cap_end"));
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_cone_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Cone";
- ot->description= "Construct a conic mesh (ends filled)";
- ot->idname= "MESH_OT_primitive_cone_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_cone_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 2, 500);
- RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
- RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
- RNA_def_boolean(ot->srna, "cap_end", 1, "Cap End", "");
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_grid_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_GRID, RNA_int_get(op->ptr, "x_subdivisions"),
- RNA_int_get(op->ptr, "y_subdivisions"), 0,
- RNA_float_get(op->ptr,"size"), 0.0f, 0, 1);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_grid_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Grid";
- ot->description= "Construct a grid mesh";
- ot->idname= "MESH_OT_primitive_grid_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_grid_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_int(ot->srna, "x_subdivisions", 10, INT_MIN, INT_MAX, "X Subdivisions", "", 3, 1000);
- RNA_def_int(ot->srna, "y_subdivisions", 10, INT_MIN, INT_MAX, "Y Subdivisions", "", 3, 1000);
- RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, FLT_MAX);
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_MONKEY, 0, 0, 2, 0.0f, 0.0f, 0, 0);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_monkey_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Monkey";
- ot->description= "Construct a Suzanne mesh";
- ot->idname= "MESH_OT_primitive_monkey_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_monkey_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_UVSPHERE, RNA_int_get(op->ptr, "ring_count"),
- RNA_int_get(op->ptr, "segments"), 0,
- RNA_float_get(op->ptr,"size"), 0.0f, 0, 0);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add UV Sphere";
- ot->description= "Construct a UV sphere mesh";
- ot->idname= "MESH_OT_primitive_uv_sphere_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_uvsphere_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_int(ot->srna, "segments", 32, INT_MIN, INT_MAX, "Segments", "", 3, 500);
- RNA_def_int(ot->srna, "ring_count", 16, INT_MIN, INT_MAX, "Rings", "", 3, 500);
- RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, 100.00);
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_ICOSPHERE, 0, 0, RNA_int_get(op->ptr, "subdivisions"),
- RNA_float_get(op->ptr,"size"), 0.0f, 0, 0);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Ico Sphere";
- ot->description= "Construct an Icosphere mesh";
- ot->idname= "MESH_OT_primitive_ico_sphere_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_icosphere_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_int(ot->srna, "subdivisions", 2, 0, INT_MAX, "Subdivisions", "", 0, 8);
- RNA_def_float(ot->srna, "size", 1.0f, 0.0f, FLT_MAX, "Size", "", 0.001f, 100.00);
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-/****************** add duplicate operator ***************/
-
-static int mesh_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(ob->data);
-
- adduplicateflag(em, SELECT);
-
- BKE_mesh_end_editmesh(ob->data, em);
-
- DAG_id_tag_update(ob->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static int mesh_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
-{
- WM_cursor_wait(1);
- mesh_duplicate_exec(C, op);
- WM_cursor_wait(0);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_duplicate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Duplicate";
- ot->description= "Duplicate selected vertices, edges or faces";
- ot->idname= "MESH_OT_duplicate";
-
- /* api callbacks */
- ot->invoke= mesh_duplicate_invoke;
- ot->exec= mesh_duplicate_exec;
-
- ot->poll= ED_operator_editmesh;
-
- /* to give to transform */
- RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
-}
-
diff --git a/source/blender/editors/mesh/editmesh_lib.c b/source/blender/editors/mesh/editmesh_lib.c
deleted file mode 100644
index bc670c47940..00000000000
--- a/source/blender/editors/mesh/editmesh_lib.c
+++ /dev/null
@@ -1,2842 +0,0 @@
-/*
- * $Id$
- *
- * ***** 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) 2004 by Blender Foundation
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/*
-
-editmesh_lib: generic (no UI, no menus) operations/evaluators for editmesh data
-
-*/
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_editVert.h"
-#include "BLI_edgehash.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_customdata.h"
-#include "BKE_context.h"
-#include "BKE_global.h"
-#include "BKE_mesh.h"
-
-
-#include "ED_mesh.h"
-#include "ED_screen.h"
-#include "ED_view3d.h"
-#include "ED_transform.h"
-
-#include "mesh_intern.h"
-
-/* Helpers for EM_set_flag_all_selectmode */
-#define SET_EVE_FLAG(eve, flag) \
- if (eve->h==0) { \
- if (flag & SELECT && !(eve->f & SELECT)) { \
- ++selvert; \
- } \
- eve->f |= flag; \
- }
-
-#define SET_EED_FLAG(eed, flag) \
- if (eed->h==0) { \
- if (flag & SELECT && !(eed->f & SELECT)) { \
- ++seledge; \
- } \
- eed->f |= flag; \
- SET_EVE_FLAG(eed->v1, flag); \
- SET_EVE_FLAG(eed->v2, flag); \
- }
-
-
-/* ****************** stats *************** */
-
-int EM_nfaces_selected(EditMesh *em)
-{
- EditFace *efa;
- int count= 0;
-
- for (efa= em->faces.first; efa; efa= efa->next)
- if (efa->f & SELECT)
- count++;
-
- em->totfacesel= count;
-
- return count;
-}
-
-int EM_nedges_selected(EditMesh *em)
-{
- EditEdge *eed;
- int count= 0;
-
- for (eed= em->edges.first; eed; eed= eed->next)
- if(eed->f & SELECT)
- count++;
-
- em->totedgesel= count;
-
- return count;
-}
-
-int EM_nvertices_selected(EditMesh *em)
-{
- EditVert *eve;
- int count= 0;
-
- for (eve= em->verts.first; eve; eve= eve->next)
- if (eve->f & SELECT)
- count++;
-
- em->totvertsel= count;
-
- return count;
-}
-
-void EM_stats_update(EditMesh *em)
-{
-
- em->totvert= BLI_countlist(&em->verts);
- em->totedge= BLI_countlist(&em->edges);
- em->totface= BLI_countlist(&em->faces);
-
- EM_nvertices_selected(em);
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-/* ************************************** */
-
-/* this replaces the active flag used in uv/face mode */
-void EM_set_actFace(EditMesh *em, EditFace *efa)
-{
- em->act_face = efa;
-}
-
-EditFace *EM_get_actFace(EditMesh *em, int sloppy)
-{
- if (em->act_face) {
- return em->act_face;
- } else if (sloppy) {
- EditFace *efa= NULL;
- EditSelection *ese;
-
- ese = em->selected.last;
- for (; ese; ese=ese->prev){
- if(ese->type == EDITFACE) {
- efa = (EditFace *)ese->data;
-
- if (efa->h) efa= NULL;
- else break;
- }
- }
- if (efa==NULL) {
- for (efa= em->faces.first; efa; efa= efa->next) {
- if (efa->f & SELECT)
- break;
- }
- }
- return efa; /* can still be null */
- }
- return NULL;
-}
-
-int EM_get_actSelection(EditMesh *em, EditSelection *ese)
-{
- EditSelection *ese_last = em->selected.last;
- EditFace *efa = EM_get_actFace(em, 0);
-
- ese->next = ese->prev = NULL;
-
- if (ese_last) {
- if (ese_last->type == EDITFACE) { /* if there is an active face, use it over the last selected face */
- if (efa) {
- ese->data = (void *)efa;
- } else {
- ese->data = ese_last->data;
- }
- ese->type = EDITFACE;
- } else {
- ese->data = ese_last->data;
- ese->type = ese_last->type;
- }
- } else if (efa) { /* no */
- ese->data = (void *)efa;
- ese->type = EDITFACE;
- } else {
- ese->data = NULL;
- return 0;
- }
- return 1;
-}
-
-/* ********* Selection History ************ */
-static int EM_check_selection(EditMesh *em, void *data)
-{
- EditSelection *ese;
-
- for(ese = em->selected.first; ese; ese = ese->next){
- if(ese->data == data) return 1;
- }
-
- return 0;
-}
-
-void EM_remove_selection(EditMesh *em, void *data, int UNUSED(type))
-{
- EditSelection *ese;
- for(ese=em->selected.first; ese; ese = ese->next){
- if(ese->data == data){
- BLI_freelinkN(&(em->selected),ese);
- break;
- }
- }
-}
-
-void EM_store_selection(EditMesh *em, void *data, int type)
-{
- EditSelection *ese;
- if(!EM_check_selection(em, data)){
- ese = (EditSelection*) MEM_callocN( sizeof(EditSelection), "Edit Selection");
- ese->type = type;
- ese->data = data;
- BLI_addtail(&(em->selected),ese);
- }
-}
-
-void EM_validate_selections(EditMesh *em)
-{
- EditSelection *ese, *nextese;
-
- ese = em->selected.first;
-
- while(ese){
- nextese = ese->next;
- if(ese->type == EDITVERT && !(((EditVert*)ese->data)->f & SELECT)) BLI_freelinkN(&(em->selected), ese);
- else if(ese->type == EDITEDGE && !(((EditEdge*)ese->data)->f & SELECT)) BLI_freelinkN(&(em->selected), ese);
- else if(ese->type == EDITFACE && !(((EditFace*)ese->data)->f & SELECT)) BLI_freelinkN(&(em->selected), ese);
- ese = nextese;
- }
-}
-
-static void EM_strip_selections(EditMesh *em)
-{
- EditSelection *ese, *nextese;
- if(!(em->selectmode & SCE_SELECT_VERTEX)){
- ese = em->selected.first;
- while(ese){
- nextese = ese->next;
- if(ese->type == EDITVERT) BLI_freelinkN(&(em->selected),ese);
- ese = nextese;
- }
- }
- if(!(em->selectmode & SCE_SELECT_EDGE)){
- ese=em->selected.first;
- while(ese){
- nextese = ese->next;
- if(ese->type == EDITEDGE) BLI_freelinkN(&(em->selected), ese);
- ese = nextese;
- }
- }
- if(!(em->selectmode & SCE_SELECT_FACE)){
- ese=em->selected.first;
- while(ese){
- nextese = ese->next;
- if(ese->type == EDITFACE) BLI_freelinkN(&(em->selected), ese);
- ese = nextese;
- }
- }
-}
-
-/* generic way to get data from an EditSelection type
-These functions were written to be used by the Modifier widget when in Rotate about active mode,
-but can be used anywhere.
-EM_editselection_center
-EM_editselection_normal
-EM_editselection_plane
-*/
-void EM_editselection_center(float *center, EditSelection *ese)
-{
- if (ese->type==EDITVERT) {
- EditVert *eve= ese->data;
- copy_v3_v3(center, eve->co);
- } else if (ese->type==EDITEDGE) {
- EditEdge *eed= ese->data;
- add_v3_v3v3(center, eed->v1->co, eed->v2->co);
- mul_v3_fl(center, 0.5);
- } else if (ese->type==EDITFACE) {
- EditFace *efa= ese->data;
- copy_v3_v3(center, efa->cent);
- }
-}
-
-void EM_editselection_normal(float *normal, EditSelection *ese)
-{
- if (ese->type==EDITVERT) {
- EditVert *eve= ese->data;
- copy_v3_v3(normal, eve->no);
- } else if (ese->type==EDITEDGE) {
- EditEdge *eed= ese->data;
- float plane[3]; /* need a plane to correct the normal */
- float vec[3]; /* temp vec storage */
-
- add_v3_v3v3(normal, eed->v1->no, eed->v2->no);
- sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
-
- /* the 2 vertex normals will be close but not at rightangles to the edge
- for rotate about edge we want them to be at right angles, so we need to
- do some extra colculation to correct the vert normals,
- we need the plane for this */
- cross_v3_v3v3(vec, normal, plane);
- cross_v3_v3v3(normal, plane, vec);
- normalize_v3(normal);
-
- } else if (ese->type==EDITFACE) {
- EditFace *efa= ese->data;
- copy_v3_v3(normal, efa->n);
- }
-}
-
-/* Calculate a plane that is rightangles to the edge/vert/faces normal
-also make the plane run allong an axis that is related to the geometry,
-because this is used for the manipulators Y axis.*/
-void EM_editselection_plane(float *plane, EditSelection *ese)
-{
- if (ese->type==EDITVERT) {
- EditVert *eve= ese->data;
- float vec[3]={0,0,0};
-
- if (ese->prev) { /*use previously selected data to make a usefull vertex plane */
- EM_editselection_center(vec, ese->prev);
- sub_v3_v3v3(plane, vec, eve->co);
- } else {
- /* make a fake plane thats at rightangles to the normal
- we cant make a crossvec from a vec thats the same as the vec
- unlikely but possible, so make sure if the normal is (0,0,1)
- that vec isnt the same or in the same direction even.*/
- if (eve->no[0]<0.5) vec[0]=1;
- else if (eve->no[1]<0.5) vec[1]=1;
- else vec[2]=1;
- cross_v3_v3v3(plane, eve->no, vec);
- }
- } else if (ese->type==EDITEDGE) {
- EditEdge *eed= ese->data;
-
- /*the plane is simple, it runs allong the edge
- however selecting different edges can swap the direction of the y axis.
- this makes it less likely for the y axis of the manipulator
- (running along the edge).. to flip less often.
- at least its more predictable */
- if (eed->v2->co[1] > eed->v1->co[1]) /*check which to do first */
- sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
- else
- sub_v3_v3v3(plane, eed->v1->co, eed->v2->co);
-
- } else if (ese->type==EDITFACE) {
- EditFace *efa= ese->data;
- float vec[3];
- if (efa->v4) { /*if its a quad- set the plane along the 2 longest edges.*/
- float vecA[3], vecB[3];
- sub_v3_v3v3(vecA, efa->v4->co, efa->v3->co);
- sub_v3_v3v3(vecB, efa->v1->co, efa->v2->co);
- add_v3_v3v3(plane, vecA, vecB);
-
- sub_v3_v3v3(vecA, efa->v1->co, efa->v4->co);
- sub_v3_v3v3(vecB, efa->v2->co, efa->v3->co);
- add_v3_v3v3(vec, vecA, vecB);
- /*use the biggest edge length*/
- if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
- copy_v3_v3(plane, vec);
- } else {
- /*start with v1-2 */
- sub_v3_v3v3(plane, efa->v1->co, efa->v2->co);
-
- /*test the edge between v2-3, use if longer */
- sub_v3_v3v3(vec, efa->v2->co, efa->v3->co);
- if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
- copy_v3_v3(plane, vec);
-
- /*test the edge between v1-3, use if longer */
- sub_v3_v3v3(vec, efa->v3->co, efa->v1->co);
- if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
- copy_v3_v3(plane, vec);
- }
- }
- normalize_v3(plane);
-}
-
-
-
-void EM_select_face(EditFace *efa, int sel)
-{
- if(sel) {
- efa->f |= SELECT;
- efa->e1->f |= SELECT;
- efa->e2->f |= SELECT;
- efa->e3->f |= SELECT;
- if(efa->e4) efa->e4->f |= SELECT;
- efa->v1->f |= SELECT;
- efa->v2->f |= SELECT;
- efa->v3->f |= SELECT;
- if(efa->v4) efa->v4->f |= SELECT;
- }
- else {
- efa->f &= ~SELECT;
- efa->e1->f &= ~SELECT;
- efa->e2->f &= ~SELECT;
- efa->e3->f &= ~SELECT;
- if(efa->e4) efa->e4->f &= ~SELECT;
- efa->v1->f &= ~SELECT;
- efa->v2->f &= ~SELECT;
- efa->v3->f &= ~SELECT;
- if(efa->v4) efa->v4->f &= ~SELECT;
- }
-}
-
-void EM_select_edge(EditEdge *eed, int sel)
-{
- if(sel) {
- eed->f |= SELECT;
- eed->v1->f |= SELECT;
- eed->v2->f |= SELECT;
- }
- else {
- eed->f &= ~SELECT;
- eed->v1->f &= ~SELECT;
- eed->v2->f &= ~SELECT;
- }
-}
-
-void EM_select_face_fgon(EditMesh *em, EditFace *efa, int val)
-{
- short index=0;
-
- if(efa->fgonf==0) EM_select_face(efa, val);
- else {
- if(efa->e1->fgoni) index= efa->e1->fgoni;
- if(efa->e2->fgoni) index= efa->e2->fgoni;
- if(efa->e3->fgoni) index= efa->e3->fgoni;
- if(efa->v4 && efa->e4->fgoni) index= efa->e4->fgoni;
-
- if((index==0) && (G.f & G_DEBUG))printf("wrong fgon select\n");
-
- // select all ngon faces with index
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->fgonf) {
- if(efa->e1->fgoni==index || efa->e2->fgoni==index ||
- efa->e3->fgoni==index || (efa->e4 && efa->e4->fgoni==index) ) {
- EM_select_face(efa, val);
- }
- }
- }
- }
-}
-
-
-/* only vertices */
-int faceselectedOR(EditFace *efa, int flag)
-{
- if ((efa->v1->f | efa->v2->f | efa->v3->f | (efa->v4?efa->v4->f:0))&flag) {
- return 1;
- } else {
- return 0;
- }
-}
-
-// replace with (efa->f & SELECT)
-int faceselectedAND(EditFace *efa, int flag)
-{
- if ((efa->v1->f & efa->v2->f & efa->v3->f & (efa->v4?efa->v4->f:flag))&flag) {
- return 1;
- } else {
- return 0;
- }
-}
-
-void EM_clear_flag_all(EditMesh *em, int flag)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- for (eve= em->verts.first; eve; eve= eve->next) eve->f &= ~flag;
- for (eed= em->edges.first; eed; eed= eed->next) eed->f &= ~flag;
- for (efa= em->faces.first; efa; efa= efa->next) efa->f &= ~flag;
-
- if(flag & SELECT) {
- BLI_freelistN(&(em->selected));
- em->totvertsel= em->totedgesel= em->totfacesel= 0;
- }
-}
-
-void EM_set_flag_all(EditMesh *em, int flag)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- for (eve= em->verts.first; eve; eve= eve->next) if(eve->h==0) eve->f |= flag;
- for (eed= em->edges.first; eed; eed= eed->next) if(eed->h==0) eed->f |= flag;
- for (efa= em->faces.first; efa; efa= efa->next) if(efa->h==0) efa->f |= flag;
-
- if(flag & SELECT) {
- em->totvertsel= em->totvert;
- em->totedgesel= em->totedge;
- em->totfacesel= em->totface;
- }
-}
-
-void EM_set_flag_all_selectmode(EditMesh *em, int flag)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- int selvert= 0, seledge= 0, selface= 0;
-
- if (em->selectmode & SCE_SELECT_VERTEX) {
- /* If vertex select mode enabled all the data could be affected */
- for (eve= em->verts.first; eve; eve= eve->next) if(eve->h==0) eve->f |= flag;
- for (eed= em->edges.first; eed; eed= eed->next) if(eed->h==0) eed->f |= flag;
- for (efa= em->faces.first; efa; efa= efa->next) if(efa->h==0) efa->f |= flag;
-
- if (flag & SELECT) {
- selvert= em->totvert;
- seledge= em->totedge;
- selface= em->totface;
- }
- } else if (em->selectmode & SCE_SELECT_EDGE) {
- /* If edge select mode is enabled we should affect on all edges, faces and */
- /* vertices, connected to them */
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- SET_EED_FLAG(eed, flag)
- }
-
- for (efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- efa->f |= flag;
-
- if (flag & SELECT) {
- ++selface;
- }
- }
- }
- } else if (em->selectmode & SCE_SELECT_FACE) {
- /* No vertex and edge select mode, only face selection */
- /* In face select mode only edges and vertices belongs to faces should be affected */
-
- for (efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- efa->f |= flag;
- SET_EED_FLAG(efa->e1, flag);
- SET_EED_FLAG(efa->e2, flag);
- SET_EED_FLAG(efa->e3, flag);
-
- if (efa->e4) {
- SET_EED_FLAG(efa->e4, flag);
- }
-
- if (flag & SELECT) {
- ++selface;
- }
- }
- }
- }
-
- if(flag & SELECT) {
- em->totvertsel= selvert;
- em->totedgesel= seledge;
- em->totfacesel= selface;
- }
- }
-/* flush for changes in vertices only */
-void EM_deselect_flush(EditMesh *em)
-{
- EditEdge *eed;
- EditFace *efa;
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->v1->f & eed->v2->f & SELECT);
- else eed->f &= ~SELECT;
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->v4) {
- if(efa->v1->f & efa->v2->f & efa->v3->f & efa->v4->f & SELECT );
- else efa->f &= ~SELECT;
- }
- else {
- if(efa->v1->f & efa->v2->f & efa->v3->f & SELECT );
- else efa->f &= ~SELECT;
- }
- }
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-
-/* flush selection to edges & faces */
-
-/* this only based on coherent selected vertices, for example when adding new
- objects. call clear_flag_all() before you select vertices to be sure it ends OK!
-
-*/
-
-void EM_select_flush(EditMesh *em)
-{
- EditEdge *eed;
- EditFace *efa;
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->v1->f & eed->v2->f & SELECT) eed->f |= SELECT;
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->v4) {
- if(efa->v1->f & efa->v2->f & efa->v3->f & efa->v4->f & SELECT ) efa->f |= SELECT;
- }
- else {
- if(efa->v1->f & efa->v2->f & efa->v3->f & SELECT ) efa->f |= SELECT;
- }
- }
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-/* when vertices or edges can be selected, also make fgon consistent */
-static void check_fgons_selection(EditMesh *em)
-{
- EditFace *efa, *efan;
- EditEdge *eed;
- ListBase *lbar;
- int sel, desel, index, totfgon= 0;
-
- /* count amount of fgons */
- for(eed= em->edges.first; eed; eed= eed->next)
- if(eed->fgoni>totfgon) totfgon= eed->fgoni;
-
- if(totfgon==0) return;
-
- lbar= MEM_callocN((totfgon+1)*sizeof(ListBase), "listbase array");
-
- /* put all fgons in lbar */
- for(efa= em->faces.first; efa; efa= efan) {
- efan= efa->next;
- index= efa->e1->fgoni;
- if(index==0) index= efa->e2->fgoni;
- if(index==0) index= efa->e3->fgoni;
- if(index==0 && efa->e4) index= efa->e4->fgoni;
- if(index) {
- BLI_remlink(&em->faces, efa);
- BLI_addtail(&lbar[index], efa);
- }
- }
-
- /* now check the fgons */
- for(index=1; index<=totfgon; index++) {
- /* we count on vertices/faces/edges being set OK, so we only have to set ngon itself */
- sel= desel= 0;
- for(efa= lbar[index].first; efa; efa= efa->next) {
- if(efa->e1->fgoni==0) {
- if(efa->e1->f & SELECT) sel++;
- else desel++;
- }
- if(efa->e2->fgoni==0) {
- if(efa->e2->f & SELECT) sel++;
- else desel++;
- }
- if(efa->e3->fgoni==0) {
- if(efa->e3->f & SELECT) sel++;
- else desel++;
- }
- if(efa->e4 && efa->e4->fgoni==0) {
- if(efa->e4->f & SELECT) sel++;
- else desel++;
- }
-
- if(sel && desel) break;
- }
-
- if(sel && desel) sel= 0;
- else if(sel) sel= 1;
- else sel= 0;
-
- /* select/deselect and put back */
- for(efa= lbar[index].first; efa; efa= efa->next) {
- if(sel) efa->f |= SELECT;
- else efa->f &= ~SELECT;
- }
- BLI_movelisttolist(&em->faces, &lbar[index]);
- }
-
- MEM_freeN(lbar);
-}
-
-
-/* flush to edges & faces */
-
-/* based on select mode it selects edges/faces
- assumed is that verts/edges/faces were properly selected themselves
- with the calls above
-*/
-
-void EM_selectmode_flush(EditMesh *em)
-{
- EditEdge *eed;
- EditFace *efa;
-
- // flush to edges & faces
- if(em->selectmode & SCE_SELECT_VERTEX) {
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->v1->f & eed->v2->f & SELECT) eed->f |= SELECT;
- else eed->f &= ~SELECT;
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->v4) {
- if(efa->v1->f & efa->v2->f & efa->v3->f & efa->v4->f & SELECT) efa->f |= SELECT;
- else efa->f &= ~SELECT;
- }
- else {
- if(efa->v1->f & efa->v2->f & efa->v3->f & SELECT) efa->f |= SELECT;
- else efa->f &= ~SELECT;
- }
- }
- }
- // flush to faces
- else if(em->selectmode & SCE_SELECT_EDGE) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->e4) {
- if(efa->e1->f & efa->e2->f & efa->e3->f & efa->e4->f & SELECT) efa->f |= SELECT;
- else efa->f &= ~SELECT;
- }
- else {
- if(efa->e1->f & efa->e2->f & efa->e3->f & SELECT) efa->f |= SELECT;
- else efa->f &= ~SELECT;
- }
- }
- }
- // make sure selected faces have selected edges too, for extrude (hack?)
- else if(em->selectmode & SCE_SELECT_FACE) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) EM_select_face(efa, 1);
- }
- }
-
- if(!(em->selectmode & SCE_SELECT_FACE))
- check_fgons_selection(em);
-
- EM_nvertices_selected(em);
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-void EM_convertsel(EditMesh *em, short oldmode, short selectmode)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
- /*clear flags*/
- for(eve= em->verts.first; eve; eve= eve->next) eve->f1 = 0;
- for(eed= em->edges.first; eed; eed= eed->next) eed->f1 = 0;
- for(efa= em->faces.first; efa; efa= efa->next) efa->f1 = 0;
-
- /*have to find out what the selectionmode was previously*/
- if(oldmode == SCE_SELECT_VERTEX) {
- if(selectmode == SCE_SELECT_EDGE){
- /*select all edges associated with every selected vertex*/
- for(eed= em->edges.first; eed; eed= eed->next){
- if(eed->v1->f&SELECT) eed->f1 = 1;
- else if(eed->v2->f&SELECT) eed->f1 = 1;
- }
-
- for(eed= em->edges.first; eed; eed= eed->next){
- if(eed->f1 == 1) EM_select_edge(eed,1);
- }
- }
- else if(selectmode == SCE_SELECT_FACE){
- /*select all faces associated with every selected vertex*/
- for(efa= em->faces.first; efa; efa= efa->next){
- if(efa->v1->f&SELECT) efa->f1 = 1;
- else if(efa->v2->f&SELECT) efa->f1 = 1;
- else if(efa->v3->f&SELECT) efa->f1 = 1;
- else{
- if(efa->v4){
- if(efa->v4->f&SELECT) efa->f1 =1;
- }
- }
- }
- for(efa= em->faces.first; efa; efa= efa->next){
- if(efa->f1 == 1) EM_select_face(efa,1);
- }
- }
- }
-
- if(oldmode == SCE_SELECT_EDGE){
- if(selectmode == SCE_SELECT_FACE){
- for(efa= em->faces.first; efa; efa= efa->next){
- if(efa->e1->f&SELECT) efa->f1 = 1;
- else if(efa->e2->f&SELECT) efa->f1 = 1;
- else if(efa->e3->f&SELECT) efa->f1 = 1;
- else if(efa->e4){
- if(efa->e4->f&SELECT) efa->f1 = 1;
- }
- }
- for(efa= em->faces.first; efa; efa= efa->next){
- if(efa->f1 == 1) EM_select_face(efa,1);
- }
- }
- }
-
- check_fgons_selection(em);
-
- EM_nvertices_selected(em);
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-void EM_selectmode_to_scene(struct Scene *scene, struct Object *obedit)
-{
- scene->toolsettings->selectmode= get_mesh(obedit)->edit_mesh->selectmode;
-}
-
-/* when switching select mode, makes sure selection is consistent for editing */
-/* also for paranoia checks to make sure edge or face mode works */
-void EM_selectmode_set(EditMesh *em)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- EM_strip_selections(em); /*strip EditSelections from em->selected that are not relevant to new mode*/
-
- if(em->selectmode & SCE_SELECT_VERTEX) {
- /* vertices -> edges -> faces */
- for (eed= em->edges.first; eed; eed= eed->next) eed->f &= ~SELECT;
- for (efa= em->faces.first; efa; efa= efa->next) efa->f &= ~SELECT;
-
- EM_select_flush(em);
- }
- else if(em->selectmode & SCE_SELECT_EDGE) {
- /* deselect vertices, and select again based on edge select */
- for(eve= em->verts.first; eve; eve= eve->next) eve->f &= ~SELECT;
- for(eed= em->edges.first; eed; eed= eed->next)
- if(eed->f & SELECT) EM_select_edge(eed, 1);
- /* selects faces based on edge status */
- EM_selectmode_flush(em);
- }
- else if(em->selectmode & SCE_SELECT_FACE) {
- /* deselect eges, and select again based on face select */
- for(eed= em->edges.first; eed; eed= eed->next) EM_select_edge(eed, 0);
-
- for(efa= em->faces.first; efa; efa= efa->next)
- if(efa->f & SELECT) EM_select_face(efa, 1);
- }
-
- EM_nvertices_selected(em);
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-/* paranoia check, actually only for entering editmode. rule:
-- vertex hidden, always means edge is hidden too
-- edge hidden, always means face is hidden too
-- face hidden, dont change anything
-*/
-void EM_hide_reset(EditMesh *em)
-{
- EditEdge *eed;
- EditFace *efa;
-
- for(eed= em->edges.first; eed; eed= eed->next)
- if(eed->v1->h || eed->v2->h) eed->h |= 1;
-
- for(efa= em->faces.first; efa; efa= efa->next)
- if((efa->e1->h & 1) || (efa->e2->h & 1) || (efa->e3->h & 1) || (efa->e4 && (efa->e4->h & 1)))
- efa->h= 1;
-
-}
-
-void EM_data_interp_from_verts(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *eve, float fac)
-{
- void *src[2];
- float w[2];
-
- if (v1->data && v2->data) {
- src[0]= v1->data;
- src[1]= v2->data;
- w[0] = 1.0f-fac;
- w[1] = fac;
-
- CustomData_em_interp(&em->vdata, src, w, NULL, 2, eve->data);
- }
-}
-
-void EM_data_interp_from_faces(EditMesh *em, EditFace *efa1, EditFace *efa2, EditFace *efan, int i1, int i2, int i3, int i4)
-{
- float w[2][4][4];
- void *src[2];
- int count = (efa2)? 2: 1;
-
- if (efa1->data) {
- /* set weights for copying from corners directly to other corners */
- memset(w, 0, sizeof(w));
-
- w[i1/4][0][i1%4]= 1.0f;
- w[i2/4][1][i2%4]= 1.0f;
- w[i3/4][2][i3%4]= 1.0f;
- if (i4 != -1)
- w[i4/4][3][i4%4]= 1.0f;
-
- src[0]= efa1->data;
- src[1]= (efa2)? efa2->data: NULL;
-
- CustomData_em_interp(&em->fdata, src, NULL, (float*)w, count, efan->data);
- }
-}
-
-EditFace *EM_face_from_faces(EditMesh *em, EditFace *efa1, EditFace *efa2, int i1, int i2, int i3, int i4)
-{
- EditFace *efan;
- EditVert **v[2];
-
- v[0]= &efa1->v1;
- v[1]= (efa2)? &efa2->v1: NULL;
-
- efan= addfacelist(em, v[i1/4][i1%4], v[i2/4][i2%4], v[i3/4][i3%4],
- (i4 == -1)? 0: v[i4/4][i4%4], efa1, NULL);
-
- EM_data_interp_from_faces(em, efa1, efa2, efan, i1, i2, i3, i4);
-
- return efan;
-}
-
-static void update_data_blocks(EditMesh *em, CustomData *olddata, CustomData *data)
-{
- EditFace *efa;
- EditVert *eve;
- void *block;
-
- if (data == &em->vdata) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- block = NULL;
- CustomData_em_set_default(data, &block);
- CustomData_em_copy_data(olddata, data, eve->data, &block);
- CustomData_em_free_block(olddata, &eve->data);
- eve->data= block;
- }
- }
- else if (data == &em->fdata) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- block = NULL;
- CustomData_em_set_default(data, &block);
- CustomData_em_copy_data(olddata, data, efa->data, &block);
- CustomData_em_free_block(olddata, &efa->data);
- efa->data= block;
- }
- }
-}
-
-void EM_add_data_layer(EditMesh *em, CustomData *data, int type, const char *name)
-{
- CustomData olddata;
-
- olddata= *data;
- olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
- CustomData_add_layer_named(data, type, CD_CALLOC, NULL, 0, name);
-
- update_data_blocks(em, &olddata, data);
- if (olddata.layers) MEM_freeN(olddata.layers);
-}
-
-void EM_free_data_layer(EditMesh *em, CustomData *data, int type)
-{
- CustomData olddata;
-
- olddata= *data;
- olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
- CustomData_free_layer_active(data, type, 0);
-
- update_data_blocks(em, &olddata, data);
- if (olddata.layers) MEM_freeN(olddata.layers);
-}
-
-/* ******** EXTRUDE ********* */
-
-static void add_normal_aligned(float *nor, float *add)
-{
- if( INPR(nor, add) < -0.9999f)
- sub_v3_v3(nor, add);
- else
- add_v3_v3(nor, add);
-}
-
-static void set_edge_directions_f2(EditMesh *em, int val)
-{
- EditFace *efa;
- int do_all= 1;
-
- /* edge directions are used for extrude, to detect direction of edges that make new faces */
- /* we have set 'f2' flags in edges that need to get a direction set (e.g. get new face) */
- /* the val argument differs... so we need it as arg */
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- do_all= 0;
- if(efa->e1->f2<val) {
- if(efa->e1->v1 == efa->v1) efa->e1->dir= 0;
- else efa->e1->dir= 1;
- }
- if(efa->e2->f2<val) {
- if(efa->e2->v1 == efa->v2) efa->e2->dir= 0;
- else efa->e2->dir= 1;
- }
- if(efa->e3->f2<val) {
- if(efa->e3->v1 == efa->v3) efa->e3->dir= 0;
- else efa->e3->dir= 1;
- }
- if(efa->e4 && efa->e4->f2<val) {
- if(efa->e4->v1 == efa->v4) efa->e4->dir= 0;
- else efa->e4->dir= 1;
- }
- }
- }
- /* ok, no faces done... then we at least set it for exterior edges */
- if(do_all) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->e1->v1 == efa->v1) efa->e1->dir= 0;
- else efa->e1->dir= 1;
- if(efa->e2->v1 == efa->v2) efa->e2->dir= 0;
- else efa->e2->dir= 1;
- if(efa->e3->v1 == efa->v3) efa->e3->dir= 0;
- else efa->e3->dir= 1;
- if(efa->e4) {
- if(efa->e4->v1 == efa->v4) efa->e4->dir= 0;
- else efa->e4->dir= 1;
- }
- }
- }
-}
-
-/* individual face extrude */
-/* will use vertex normals for extrusion directions, so *nor is unaffected */
-short extrudeflag_face_indiv(EditMesh *em, short UNUSED(flag), float *UNUSED(nor))
-{
- EditVert *eve, *v1, *v2, *v3, *v4;
- EditEdge *eed;
- EditFace *efa, *nextfa;
-
- if(em==NULL) return 0;
-
- /* selected edges with 1 or more selected face become faces */
- /* selected faces each makes new faces */
- /* always remove old faces, keeps volumes manifold */
- /* select the new extrusion, deselect old */
-
- /* step 1; init, count faces in edges */
- recalc_editnormals(em);
-
- for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; // new select flag
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f2= 0; // amount of unselected faces
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT);
- else {
- efa->e1->f2++;
- efa->e2->f2++;
- efa->e3->f2++;
- if(efa->e4) efa->e4->f2++;
- }
- }
-
- /* step 2: make new faces from faces */
- for(efa= em->faces.last; efa; efa= efa->prev) {
- if(efa->f & SELECT) {
- v1= addvertlist(em, efa->v1->co, efa->v1);
- v2= addvertlist(em, efa->v2->co, efa->v2);
- v3= addvertlist(em, efa->v3->co, efa->v3);
-
- v1->f1= v2->f1= v3->f1= 1;
- VECCOPY(v1->no, efa->n);
- VECCOPY(v2->no, efa->n);
- VECCOPY(v3->no, efa->n);
- if(efa->v4) {
- v4= addvertlist(em, efa->v4->co, efa->v4);
- v4->f1= 1;
- VECCOPY(v4->no, efa->n);
- }
- else v4= NULL;
-
- /* side faces, clockwise */
- addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL);
- addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL);
- if(efa->v4) {
- addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL);
- addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL);
- }
- else {
- addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL);
- }
- /* top face */
- addfacelist(em, v1, v2, v3, v4, efa, NULL);
- }
- }
-
- /* step 3: remove old faces */
- efa= em->faces.first;
- while(efa) {
- nextfa= efa->next;
- if(efa->f & SELECT) {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- efa= nextfa;
- }
-
- /* step 4: redo selection */
- EM_clear_flag_all(em, SELECT);
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f1) eve->f |= SELECT;
- }
-
- EM_select_flush(em);
-
- return 'n';
-}
-
-
-/* extrudes individual edges */
-/* nor is filled with constraint vector */
-short extrudeflag_edges_indiv(EditMesh *em, short flag, float *nor)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL;
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->tmp.f = NULL;
- eed->f2= ((eed->f & flag)!=0);
- }
-
- set_edge_directions_f2(em, 2);
-
- /* sample for next loop */
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->e1->tmp.f = efa;
- efa->e2->tmp.f = efa;
- efa->e3->tmp.f = efa;
- if(efa->e4) efa->e4->tmp.f = efa;
- }
- /* make the faces */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & flag) {
- if(eed->v1->tmp.v == NULL)
- eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1);
- if(eed->v2->tmp.v == NULL)
- eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2);
-
- if(eed->dir==1)
- addfacelist(em, eed->v1, eed->v2,
- eed->v2->tmp.v, eed->v1->tmp.v,
- eed->tmp.f, NULL);
- else
- addfacelist(em, eed->v2, eed->v1,
- eed->v1->tmp.v, eed->v2->tmp.v,
- eed->tmp.f, NULL);
-
- /* for transform */
- if(eed->tmp.f) {
- efa = eed->tmp.f;
- if (efa->f & SELECT) add_normal_aligned(nor, efa->n);
- }
- }
- }
- normalize_v3(nor);
-
- /* set correct selection */
- EM_clear_flag_all(em, SELECT);
- for(eve= em->verts.last; eve; eve= eve->prev) {
- if(eve->tmp.v) {
- eve->tmp.v->f |= flag;
- }
- }
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->v1->f & eed->v2->f & flag) eed->f |= flag;
- }
-
- if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab
- return 'n'; // n is for normal constraint
-}
-
-/* extrudes individual vertices */
-short extrudeflag_verts_indiv(EditMesh *em, short flag, float *UNUSED(nor))
-{
- EditVert *eve;
-
- /* make the edges */
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & flag) {
- eve->tmp.v = addvertlist(em, eve->co, eve);
- addedgelist(em, eve, eve->tmp.v, NULL);
- }
- else eve->tmp.v = NULL;
- }
-
- /* set correct selection */
- EM_clear_flag_all(em, SELECT);
-
- for(eve= em->verts.last; eve; eve= eve->prev)
- if (eve->tmp.v)
- eve->tmp.v->f |= flag;
-
- return 'g'; // g is grab
-}
-
-
-/* this is actually a recode of extrudeflag(), using proper edge/face select */
-/* hurms, doesnt use 'flag' yet, but its not called by primitive making stuff anyway */
-static short extrudeflag_edge(Object *obedit, EditMesh *em, short UNUSED(flag), float *nor, int all)
-{
- /* all select edges/faces: extrude */
- /* old select is cleared, in new ones it is set */
- EditVert *eve, *nextve;
- EditEdge *eed, *nexted;
- EditFace *efa, *nextfa, *efan;
- short del_old= 0;
- ModifierData *md;
-
- if(em==NULL) return 0;
-
- md = obedit->modifiers.first;
-
- /* selected edges with 0 or 1 selected face become faces */
- /* selected faces generate new faces */
-
- /* if *one* selected face has edge with unselected face; remove old selected faces */
-
- /* if selected edge is not used anymore; remove */
- /* if selected vertex is not used anymore: remove */
-
- /* select the new extrusion, deselect old */
-
-
- /* step 1; init, count faces in edges */
- recalc_editnormals(em);
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- eve->tmp.v = NULL;
- eve->f1= 0;
- }
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0; // amount of unselected faces
- eed->f2= 0; // amount of selected faces
- if(eed->f & SELECT) {
- eed->v1->f1= 1; // we call this 'selected vertex' now
- eed->v2->f1= 1;
- }
- eed->tmp.f = NULL; // here we tuck face pointer, as sample
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- efa->e1->f2++;
- efa->e2->f2++;
- efa->e3->f2++;
- if(efa->e4) efa->e4->f2++;
-
- // sample for next loop
- efa->e1->tmp.f = efa;
- efa->e2->tmp.f = efa;
- efa->e3->tmp.f = efa;
- if(efa->e4) efa->e4->tmp.f = efa;
- }
- else {
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4) efa->e4->f1++;
- }
- }
-
- /* If a mirror modifier with clipping is on, we need to adjust some
- * of the cases above to handle edges on the line of symmetry.
- */
- for (; md; md=md->next) {
- if (md->type==eModifierType_Mirror) {
- MirrorModifierData *mmd = (MirrorModifierData*) md;
-
- if(mmd->flag & MOD_MIR_CLIPPING) {
- float mtx[4][4];
- if (mmd->mirror_ob) {
- float imtx[4][4];
- invert_m4_m4(imtx, mmd->mirror_ob->obmat);
- mul_m4_m4m4(mtx, obedit->obmat, imtx);
- }
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f2 == 1) {
- float co1[3], co2[3];
-
- copy_v3_v3(co1, eed->v1->co);
- copy_v3_v3(co2, eed->v2->co);
-
- if (mmd->mirror_ob) {
- mul_m4_v3(mtx, co1);
- mul_m4_v3(mtx, co2);
- }
-
- if (mmd->flag & MOD_MIR_AXIS_X)
- if ( (fabs(co1[0]) < mmd->tolerance) &&
- (fabs(co2[0]) < mmd->tolerance) )
- ++eed->f2;
-
- if (mmd->flag & MOD_MIR_AXIS_Y)
- if ( (fabs(co1[1]) < mmd->tolerance) &&
- (fabs(co2[1]) < mmd->tolerance) )
- ++eed->f2;
-
- if (mmd->flag & MOD_MIR_AXIS_Z)
- if ( (fabs(co1[2]) < mmd->tolerance) &&
- (fabs(co2[2]) < mmd->tolerance) )
- ++eed->f2;
- }
- }
- }
- }
- }
-
- set_edge_directions_f2(em, 2);
-
- /* step 1.5: if *one* selected face has edge with unselected face; remove old selected faces */
- if(all == 0) {
- for(efa= em->faces.last; efa; efa= efa->prev) {
- if(efa->f & SELECT) {
- if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1 || (efa->e4 && efa->e4->f1)) {
- del_old= 1;
- break;
- }
- }
- }
- }
-
- /* step 2: make new faces from edges */
- for(eed= em->edges.last; eed; eed= eed->prev) {
- if(eed->f & SELECT) {
- if(eed->f2<2) {
- if(eed->v1->tmp.v == NULL)
- eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1);
- if(eed->v2->tmp.v == NULL)
- eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2);
-
- /* if del_old, the preferred normal direction is exact
- * opposite as for keep old faces
- */
- if(eed->dir!=del_old)
- addfacelist(em, eed->v1, eed->v2,
- eed->v2->tmp.v, eed->v1->tmp.v,
- eed->tmp.f, NULL);
- else
- addfacelist(em, eed->v2, eed->v1,
- eed->v1->tmp.v, eed->v2->tmp.v,
- eed->tmp.f, NULL);
- }
- }
- }
-
- /* step 3: make new faces from faces */
- for(efa= em->faces.last; efa; efa= efa->prev) {
- if(efa->f & SELECT) {
- if (efa->v1->tmp.v == NULL)
- efa->v1->tmp.v = addvertlist(em, efa->v1->co, efa->v1);
- if (efa->v2->tmp.v ==NULL)
- efa->v2->tmp.v = addvertlist(em, efa->v2->co, efa->v2);
- if (efa->v3->tmp.v ==NULL)
- efa->v3->tmp.v = addvertlist(em, efa->v3->co, efa->v3);
- if (efa->v4 && (efa->v4->tmp.v == NULL))
- efa->v4->tmp.v = addvertlist(em, efa->v4->co, efa->v4);
-
- if(efa->v4)
- efan = addfacelist(em, efa->v1->tmp.v, efa->v2->tmp.v,
- efa->v3->tmp.v, efa->v4->tmp.v, efa, efa);
- else
- efan = addfacelist(em, efa->v1->tmp.v, efa->v2->tmp.v,
- efa->v3->tmp.v, NULL, efa, efa);
-
- /* keep old faces means flipping normal, reverse vertex order gives bad UV's & VCols etc - [#25260] */
- if(del_old==0) {
- flipface(em, efan);
- }
-
- if (em->act_face == efa) {
- em->act_face = efan;
- }
-
- /* for transform */
- add_normal_aligned(nor, efa->n);
- }
- }
-
- if(del_old) {
-
- /* step 4: remove old faces, if del_old */
- efa= em->faces.first;
- while(efa) {
- nextfa= efa->next;
- if(efa->f & SELECT) {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- efa= nextfa;
- }
-
-
- /* step 5: remove selected unused edges */
- /* start tagging again */
- for(eed= em->edges.first; eed; eed= eed->next) eed->f1=0;
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->e1->f1= 1;
- efa->e2->f1= 1;
- efa->e3->f1= 1;
- if(efa->e4) efa->e4->f1= 1;
- }
- /* remove */
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
- if(eed->f & SELECT) {
- if(eed->f1==0) {
- remedge(em, eed);
- free_editedge(em, eed);
- }
- }
- eed= nexted;
- }
-
- /* step 6: remove selected unused vertices */
- for(eed= em->edges.first; eed; eed= eed->next)
- eed->v1->f1= eed->v2->f1= 0;
-
- eve= em->verts.first;
- while(eve) {
- nextve= eve->next;
- if(eve->f1) {
- // hack... but we need it for step 7, redoing selection
- if(eve->tmp.v) eve->tmp.v->tmp.v= eve->tmp.v;
-
- BLI_remlink(&em->verts, eve);
- free_editvert(em, eve);
- }
- eve= nextve;
- }
- }
-
- normalize_v3(nor); // translation normal grab
-
- /* step 7: redo selection */
- EM_clear_flag_all(em, SELECT);
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->tmp.v) {
- eve->tmp.v->f |= SELECT;
- }
- }
-
- EM_select_flush(em);
-
- if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab
- return 'n'; // normal constraint
-}
-
-short extrudeflag_vert(Object *obedit, EditMesh *em, short flag, float *nor, int all)
-{
- /* all verts/edges/faces with (f & 'flag'): extrude */
- /* from old verts, 'flag' is cleared, in new ones it is set */
- EditVert *eve, *v1, *v2, *v3, *v4, *nextve;
- EditEdge *eed, *e1, *e2, *e3, *e4, *nexted;
- EditFace *efa, *efa2, *nextvl;
- short sel=0, del_old= 0, is_face_sel=0;
- ModifierData *md;
-
- if(em==NULL) return 0;
-
- md = obedit->modifiers.first;
-
- /* clear vert flag f1, we use this to detect a loose selected vertice */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & flag) eve->f1= 1;
- else eve->f1= 0;
- eve= eve->next;
- }
- /* clear edges counter flag, if selected we set it at 1 */
- eed= em->edges.first;
- while(eed) {
- if( (eed->v1->f & flag) && (eed->v2->f & flag) ) {
- eed->f2= 1;
- eed->v1->f1= 0;
- eed->v2->f1= 0;
- }
- else eed->f2= 0;
-
- eed->f1= 1; /* this indicates it is an 'old' edge (in this routine we make new ones) */
- eed->tmp.f = NULL; /* used as sample */
-
- eed= eed->next;
- }
-
- /* we set a flag in all selected faces, and increase the associated edge counters */
-
- efa= em->faces.first;
- while(efa) {
- efa->f1= 0;
-
- if(faceselectedAND(efa, flag)) {
- e1= efa->e1;
- e2= efa->e2;
- e3= efa->e3;
- e4= efa->e4;
-
- if(e1->f2 < 3) e1->f2++;
- if(e2->f2 < 3) e2->f2++;
- if(e3->f2 < 3) e3->f2++;
- if(e4 && e4->f2 < 3) e4->f2++;
-
- efa->f1= 1;
- is_face_sel= 1; // for del_old
- }
- else if(faceselectedOR(efa, flag)) {
- e1= efa->e1;
- e2= efa->e2;
- e3= efa->e3;
- e4= efa->e4;
-
- if( (e1->v1->f & flag) && (e1->v2->f & flag) ) e1->f1= 2;
- if( (e2->v1->f & flag) && (e2->v2->f & flag) ) e2->f1= 2;
- if( (e3->v1->f & flag) && (e3->v2->f & flag) ) e3->f1= 2;
- if( e4 && (e4->v1->f & flag) && (e4->v2->f & flag) ) e4->f1= 2;
- }
-
- // sample for next loop
- efa->e1->tmp.f = efa;
- efa->e2->tmp.f = efa;
- efa->e3->tmp.f = efa;
- if(efa->e4) efa->e4->tmp.f = efa;
-
- efa= efa->next;
- }
-
- set_edge_directions_f2(em, 3);
-
- /* the current state now is:
- eve->f1==1: loose selected vertex
-
- eed->f2==0 : edge is not selected, no extrude
- eed->f2==1 : edge selected, is not part of a face, extrude
- eed->f2==2 : edge selected, is part of 1 face, extrude
- eed->f2==3 : edge selected, is part of more faces, no extrude
-
- eed->f1==0: new edge
- eed->f1==1: edge selected, is part of selected face, when eed->f==3: remove
- eed->f1==2: edge selected, part of a partially selected face
-
- efa->f1==1 : duplicate this face
- */
-
- /* If a mirror modifier with clipping is on, we need to adjust some
- * of the cases above to handle edges on the line of symmetry.
- */
- for (; md; md=md->next) {
- if (md->type==eModifierType_Mirror) {
- MirrorModifierData *mmd = (MirrorModifierData*) md;
-
- if(mmd->flag & MOD_MIR_CLIPPING) {
- float mtx[4][4];
- if (mmd->mirror_ob) {
- float imtx[4][4];
- invert_m4_m4(imtx, mmd->mirror_ob->obmat);
- mul_m4_m4m4(mtx, obedit->obmat, imtx);
- }
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f2 == 2) {
- float co1[3], co2[3];
-
- copy_v3_v3(co1, eed->v1->co);
- copy_v3_v3(co2, eed->v2->co);
-
- if (mmd->mirror_ob) {
- mul_m4_v3(mtx, co1);
- mul_m4_v3(mtx, co2);
- }
-
- if (mmd->flag & MOD_MIR_AXIS_X)
- if ( (fabs(co1[0]) < mmd->tolerance) &&
- (fabs(co2[0]) < mmd->tolerance) )
- ++eed->f2;
-
- if (mmd->flag & MOD_MIR_AXIS_Y)
- if ( (fabs(co1[1]) < mmd->tolerance) &&
- (fabs(co2[1]) < mmd->tolerance) )
- ++eed->f2;
- if (mmd->flag & MOD_MIR_AXIS_Z)
- if ( (fabs(co1[2]) < mmd->tolerance) &&
- (fabs(co2[2]) < mmd->tolerance) )
- ++eed->f2;
- }
- }
- }
- }
- }
-
- /* copy all selected vertices, */
- /* write pointer to new vert in old struct at eve->tmp.v */
- eve= em->verts.last;
- while(eve) {
- eve->f &= ~128; /* clear, for later test for loose verts */
- if(eve->f & flag) {
- sel= 1;
- v1= addvertlist(em, 0, NULL);
-
- VECCOPY(v1->co, eve->co);
- VECCOPY(v1->no, eve->no);
- v1->f= eve->f;
- eve->f &= ~flag;
- eve->tmp.v = v1;
- }
- else eve->tmp.v = NULL;
- eve= eve->prev;
- }
-
- if(sel==0) return 0;
-
- /* all edges with eed->f2==1 or eed->f2==2 become faces */
-
- /* if del_old==1 then extrude is in partial geometry, to keep it manifold.
- verts with f1==0 and (eve->f & 128)==0) are removed
- edges with eed->f2>2 are removed
- faces with efa->f1 are removed
- if del_old==0 the extrude creates a volume.
- */
-
- /* find if we delete old faces */
- if(is_face_sel && all==0) {
- for(eed= em->edges.first; eed; eed= eed->next) {
- if( (eed->f2==1 || eed->f2==2) ) {
- if(eed->f1==2) {
- del_old= 1;
- break;
- }
- }
- }
- }
-
- eed= em->edges.last;
- while(eed) {
- nexted= eed->prev;
- if( eed->f2<3) {
- eed->v1->f |= 128; /* = no loose vert! */
- eed->v2->f |= 128;
- }
- if( (eed->f2==1 || eed->f2==2) ) {
-
- /* if del_old, the preferred normal direction is exact opposite as for keep old faces */
- if(eed->dir != del_old)
- efa2 = addfacelist(em, eed->v1, eed->v2,
- eed->v2->tmp.v, eed->v1->tmp.v,
- eed->tmp.f, NULL);
- else
- efa2 = addfacelist(em, eed->v2, eed->v1,
- eed->v1->tmp.v, eed->v2->tmp.v,
- eed->tmp.f, NULL);
-
- /* Needs smarter adaption of existing creases.
- * If addedgelist is used, make sure seams are set to 0 on these
- * new edges, since we do not want to add any seams on extrusion.
- */
- efa2->e1->crease= eed->crease;
- efa2->e2->crease= eed->crease;
- efa2->e3->crease= eed->crease;
- if(efa2->e4) efa2->e4->crease= eed->crease;
- }
-
- eed= nexted;
- }
-
- /* duplicate faces, if necessary remove old ones */
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- if(efa->f1 & 1) {
-
- v1 = efa->v1->tmp.v;
- v2 = efa->v2->tmp.v;
- v3 = efa->v3->tmp.v;
- if(efa->v4)
- v4 = efa->v4->tmp.v;
- else
- v4= NULL;
-
- /* hmm .. not sure about edges here */
- if(del_old==0) // if we keep old, we flip normal
- efa2= addfacelist(em, v3, v2, v1, v4, efa, efa);
- else
- efa2= addfacelist(em, v1, v2, v3, v4, efa, efa);
-
- /* for transform */
- add_normal_aligned(nor, efa->n);
-
- if(del_old) {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- }
- efa= nextvl;
- }
- /* delete edges after copying edges above! */
- if(del_old) {
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
- if(eed->f2==3 && eed->f1==1) {
- remedge(em, eed);
- free_editedge(em, eed);
- }
- eed= nexted;
- }
- }
-
- normalize_v3(nor); // for grab
-
- /* for all vertices with eve->tmp.v!=0
- if eve->f1==1: make edge
- if flag!=128 : if del_old==1: remove
- */
- eve= em->verts.last;
- while(eve) {
- nextve= eve->prev;
- if(eve->tmp.v) {
- if(eve->f1==1) addedgelist(em, eve, eve->tmp.v, NULL);
- else if( (eve->f & 128)==0) {
- if(del_old) {
- BLI_remlink(&em->verts,eve);
- free_editvert(em, eve);
- eve= NULL;
- }
- }
- }
- if(eve) {
- eve->f &= ~128;
- }
- eve= nextve;
- }
- // since its vertex select mode now, it also deselects higher order
- EM_selectmode_flush(em);
-
- if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab, for correct undo print
- return 'n';
-}
-
-/* generic extrude */
-short extrudeflag(Object *obedit, EditMesh *em, short flag, float *nor, int all)
-{
- if(em->selectmode & SCE_SELECT_VERTEX)
- return extrudeflag_vert(obedit, em, flag, nor, all);
- else
- return extrudeflag_edge(obedit, em, flag, nor, all);
-
-}
-
-void rotateflag(EditMesh *em, short flag, float *cent, float rotmat[][3])
-{
- /* all verts with (flag & 'flag') rotate */
- EditVert *eve;
-
- eve= em->verts.first;
- while(eve) {
- if(eve->f & flag) {
- eve->co[0]-=cent[0];
- eve->co[1]-=cent[1];
- eve->co[2]-=cent[2];
- mul_m3_v3(rotmat,eve->co);
- eve->co[0]+=cent[0];
- eve->co[1]+=cent[1];
- eve->co[2]+=cent[2];
- }
- eve= eve->next;
- }
-}
-
-void translateflag(EditMesh *em, short flag, float *vec)
-{
- /* all verts with (flag & 'flag') translate */
- EditVert *eve;
-
- eve= em->verts.first;
- while(eve) {
- if(eve->f & flag) {
- eve->co[0]+=vec[0];
- eve->co[1]+=vec[1];
- eve->co[2]+=vec[2];
- }
- eve= eve->next;
- }
-}
-
-/* helper call for below */
-static EditVert *adduplicate_vertex(EditMesh *em, EditVert *eve, int flag)
-{
- /* FIXME: copy deformation weight from eve ok here? */
- EditVert *v1= addvertlist(em, eve->co, eve);
-
- v1->f= eve->f;
- eve->f &= ~flag;
- eve->f|= 128;
-
- eve->tmp.v = v1;
-
- return v1;
-}
-
-/* old selection has flag 128 set, and flag 'flag' cleared
-new selection has flag 'flag' set */
-void adduplicateflag(EditMesh *em, int flag)
-{
- EditVert *eve, *v1, *v2, *v3, *v4;
- EditEdge *eed, *newed;
- EditFace *efa, *newfa, *act_efa = EM_get_actFace(em, 0);
-
- EM_clear_flag_all(em, 128);
- EM_selectmode_set(em); // paranoia check, selection now is consistent
-
- /* vertices first */
- for(eve= em->verts.last; eve; eve= eve->prev) {
-
- if(eve->f & flag)
- adduplicate_vertex(em, eve, flag);
- else
- eve->tmp.v = NULL;
- }
-
- /* copy edges, note that vertex selection can be independent of edge */
- for(eed= em->edges.last; eed; eed= eed->prev) {
- if( eed->f & flag ) {
- v1 = eed->v1->tmp.v;
- if(v1==NULL) v1= adduplicate_vertex(em, eed->v1, flag);
- v2 = eed->v2->tmp.v;
- if(v2==NULL) v2= adduplicate_vertex(em, eed->v2, flag);
-
- newed= addedgelist(em, v1, v2, eed);
-
- newed->f= eed->f;
- eed->f &= ~flag;
- eed->f |= 128;
- }
- }
-
- /* then duplicate faces, again create new vertices if needed */
- for(efa= em->faces.last; efa; efa= efa->prev) {
- if(efa->f & flag) {
- v1 = efa->v1->tmp.v;
- if(v1==NULL) v1= adduplicate_vertex(em, efa->v1, flag);
- v2 = efa->v2->tmp.v;
- if(v2==NULL) v2= adduplicate_vertex(em, efa->v2, flag);
- v3 = efa->v3->tmp.v;
- if(v3==NULL) v3= adduplicate_vertex(em, efa->v3, flag);
- if(efa->v4) {
- v4 = efa->v4->tmp.v;
- if(v4==NULL) v4= adduplicate_vertex(em, efa->v4, flag);
- }
- else v4= NULL;
-
- newfa= addfacelist(em, v1, v2, v3, v4, efa, efa);
-
- if (efa==act_efa) {
- EM_set_actFace(em, newfa);
- }
-
- newfa->f= efa->f;
- efa->f &= ~flag;
- efa->f |= 128;
- }
- }
-
- EM_fgon_flags(em); // redo flags and indices for fgons
-}
-
-void delfaceflag(EditMesh *em, int flag)
-{
- /* delete all faces with 'flag', including loose edges and loose vertices */
- /* this is maybe a bit weird, but this function is used for 'split' and 'separate' */
- /* in remaining vertices/edges 'flag' is cleared */
- EditVert *eve,*nextve;
- EditEdge *eed, *nexted;
- EditFace *efa,*nextvl;
-
- /* to detect loose edges, we put f2 flag on 1 */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & flag) eed->f2= 1;
- else eed->f2= 0;
- }
-
- /* delete faces */
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- if(efa->f & flag) {
-
- efa->e1->f2= 1;
- efa->e2->f2= 1;
- efa->e3->f2= 1;
- if(efa->e4) {
- efa->e4->f2= 1;
- }
-
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- efa= nextvl;
- }
-
- /* all remaining faces: make sure we keep the edges */
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->e1->f2= 0;
- efa->e2->f2= 0;
- efa->e3->f2= 0;
- if(efa->e4) {
- efa->e4->f2= 0;
- }
- }
-
- /* remove tagged edges, and clear remaining ones */
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
-
- if(eed->f2==1) {
- remedge(em, eed);
- free_editedge(em, eed);
- }
- else {
- eed->f &= ~flag;
- eed->v1->f &= ~flag;
- eed->v2->f &= ~flag;
- }
- eed= nexted;
- }
-
- /* vertices with 'flag' now are the loose ones, and will be removed */
- eve= em->verts.first;
- while(eve) {
- nextve= eve->next;
- if(eve->f & flag) {
- BLI_remlink(&em->verts, eve);
- free_editvert(em, eve);
- }
- eve= nextve;
- }
-
-}
-
-/* ********************* */
-#if 0
-static int check_vnormal_flip(float *n, float *vnorm)
-{
- float inp;
-
- inp= n[0]*vnorm[0]+n[1]*vnorm[1]+n[2]*vnorm[2];
-
- /* angles 90 degrees: dont flip */
- if(inp> -0.000001) return 0;
-
- return 1;
-}
-#endif
-
-
-
-/* does face centers too */
-void recalc_editnormals(EditMesh *em)
-{
- EditFace *efa;
- EditVert *eve;
-
- for(eve= em->verts.first; eve; eve=eve->next) {
- eve->no[0] = eve->no[1] = eve->no[2] = 0.0;
- }
-
- for(efa= em->faces.first; efa; efa=efa->next) {
- if(efa->v4) {
- normal_quad_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- cent_quad_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- add_v3_v3(efa->v4->no, efa->n);
- }
- else {
- normal_tri_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co);
- cent_tri_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co);
- }
- add_v3_v3(efa->v1->no, efa->n);
- add_v3_v3(efa->v2->no, efa->n);
- add_v3_v3(efa->v3->no, efa->n);
- }
-
- /* following Mesh convention; we use vertex coordinate itself for normal in this case */
- for(eve= em->verts.first; eve; eve=eve->next) {
- if (normalize_v3(eve->no)==0.0) {
- VECCOPY(eve->no, eve->co);
- normalize_v3(eve->no);
- }
- }
-}
-
-int compareface(EditFace *vl1, EditFace *vl2)
-{
- EditVert *v1, *v2, *v3, *v4;
-
- if(vl1->v4 && vl2->v4) {
- v1= vl2->v1;
- v2= vl2->v2;
- v3= vl2->v3;
- v4= vl2->v4;
-
- if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1 || vl1->v4==v1) {
- if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2 || vl1->v4==v2) {
- if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3 || vl1->v4==v3) {
- if(vl1->v1==v4 || vl1->v2==v4 || vl1->v3==v4 || vl1->v4==v4) {
- return 1;
- }
- }
- }
- }
- }
- else if(vl1->v4==0 && vl2->v4==0) {
- v1= vl2->v1;
- v2= vl2->v2;
- v3= vl2->v3;
-
- if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1) {
- if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2) {
- if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3) {
- return 1;
- }
- }
- }
- }
-
- return 0;
-}
-
-/* checks for existence, not tria overlapping inside quad */
-EditFace *exist_face(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4)
-{
- EditFace *efa, efatest;
-
- efatest.v1= v1;
- efatest.v2= v2;
- efatest.v3= v3;
- efatest.v4= v4;
-
- efa= em->faces.first;
- while(efa) {
- if(compareface(&efatest, efa)) return efa;
- efa= efa->next;
- }
- return NULL;
-}
-
-/* evaluate if entire quad is a proper convex quad */
-int convex(float *v1, float *v2, float *v3, float *v4)
-{
- float nor[3], nor1[3], nor2[3], vec[4][2];
-
- /* define projection, do both trias apart, quad is undefined! */
- normal_tri_v3( nor1,v1, v2, v3);
- normal_tri_v3( nor2,v1, v3, v4);
- nor[0]= ABS(nor1[0]) + ABS(nor2[0]);
- nor[1]= ABS(nor1[1]) + ABS(nor2[1]);
- nor[2]= ABS(nor1[2]) + ABS(nor2[2]);
-
- if(nor[2] >= nor[0] && nor[2] >= nor[1]) {
- vec[0][0]= v1[0]; vec[0][1]= v1[1];
- vec[1][0]= v2[0]; vec[1][1]= v2[1];
- vec[2][0]= v3[0]; vec[2][1]= v3[1];
- vec[3][0]= v4[0]; vec[3][1]= v4[1];
- }
- else if(nor[1] >= nor[0] && nor[1]>= nor[2]) {
- vec[0][0]= v1[0]; vec[0][1]= v1[2];
- vec[1][0]= v2[0]; vec[1][1]= v2[2];
- vec[2][0]= v3[0]; vec[2][1]= v3[2];
- vec[3][0]= v4[0]; vec[3][1]= v4[2];
- }
- else {
- vec[0][0]= v1[1]; vec[0][1]= v1[2];
- vec[1][0]= v2[1]; vec[1][1]= v2[2];
- vec[2][0]= v3[1]; vec[2][1]= v3[2];
- vec[3][0]= v4[1]; vec[3][1]= v4[2];
- }
-
- /* linetests, the 2 diagonals have to instersect to be convex */
- if( isect_line_line_v2(vec[0], vec[2], vec[1], vec[3]) > 0 ) return 1;
- return 0;
-}
-
-
-/* ********************* Fake Polgon support (FGon) ***************** */
-
-
-/* results in:
- - faces having ->fgonf flag set (also for draw)
- - edges having ->fgoni index set (for select)
-*/
-
-float EM_face_area(EditFace *efa)
-{
- if(efa->v4) return area_quad_v3(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- else return area_tri_v3(efa->v1->co, efa->v2->co, efa->v3->co);
-}
-
-float EM_face_perimeter(EditFace *efa)
-{
- if(efa->v4) return
- len_v3v3(efa->v1->co, efa->v2->co)+
- len_v3v3(efa->v2->co, efa->v3->co)+
- len_v3v3(efa->v3->co, efa->v4->co)+
- len_v3v3(efa->v4->co, efa->v1->co);
-
- else return
- len_v3v3(efa->v1->co, efa->v2->co)+
- len_v3v3(efa->v2->co, efa->v3->co)+
- len_v3v3(efa->v3->co, efa->v1->co);
-}
-
-void EM_fgon_flags(EditMesh *em)
-{
- EditFace *efa, *efan, *efamax;
- EditEdge *eed;
- ListBase listb={NULL, NULL};
- float size, maxsize;
- short done, curindex= 1;
-
- // for each face with fgon edge AND not fgon flag set
- for(eed= em->edges.first; eed; eed= eed->next) eed->fgoni= 0; // index
- for(efa= em->faces.first; efa; efa= efa->next) efa->fgonf= 0; // flag
-
- // for speed & simplicity, put fgon face candidates in new listbase
- efa= em->faces.first;
- while(efa) {
- efan= efa->next;
- if( (efa->e1->h & EM_FGON) || (efa->e2->h & EM_FGON) ||
- (efa->e3->h & EM_FGON) || (efa->e4 && (efa->e4->h & EM_FGON)) ) {
- BLI_remlink(&em->faces, efa);
- BLI_addtail(&listb, efa);
- }
- efa= efan;
- }
-
- // find an undone face with fgon edge
- for(efa= listb.first; efa; efa= efa->next) {
- if(efa->fgonf==0) {
-
- // init this face
- efa->fgonf= EM_FGON;
- if(efa->e1->h & EM_FGON) efa->e1->fgoni= curindex;
- if(efa->e2->h & EM_FGON) efa->e2->fgoni= curindex;
- if(efa->e3->h & EM_FGON) efa->e3->fgoni= curindex;
- if(efa->e4 && (efa->e4->h & EM_FGON)) efa->e4->fgoni= curindex;
-
- // we search for largest face, to give facedot drawing rights
- maxsize= EM_face_area(efa);
- efamax= efa;
-
- // now flush curendex over edges and set faceflags
- done= 1;
- while(done==1) {
- done= 0;
-
- for(efan= listb.first; efan; efan= efan->next) {
- if(efan->fgonf==0) {
- // if one if its edges has index set, do other too
- if( (efan->e1->fgoni==curindex) || (efan->e2->fgoni==curindex) ||
- (efan->e3->fgoni==curindex) || (efan->e4 && (efan->e4->fgoni==curindex)) ) {
-
- efan->fgonf= EM_FGON;
- if(efan->e1->h & EM_FGON) efan->e1->fgoni= curindex;
- if(efan->e2->h & EM_FGON) efan->e2->fgoni= curindex;
- if(efan->e3->h & EM_FGON) efan->e3->fgoni= curindex;
- if(efan->e4 && (efan->e4->h & EM_FGON)) efan->e4->fgoni= curindex;
-
- size= EM_face_area(efan);
- if(size>maxsize) {
- efamax= efan;
- maxsize= size;
- }
- done= 1;
- }
- }
- }
- }
-
- efamax->fgonf |= EM_FGON_DRAW;
- curindex++;
-
- }
- }
-
- // put fgon face candidates back in listbase
- efa= listb.first;
- while(efa) {
- efan= efa->next;
- BLI_remlink(&listb, efa);
- BLI_addtail(&em->faces, efa);
- efa= efan;
- }
-
- // remove fgon flags when edge not in fgon (anymore)
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->fgoni==0) eed->h &= ~EM_FGON;
- }
-
-}
-
-/* editmesh vertmap, copied from intern.mesh.c
- * if do_face_idx_array is 0 it means we need to run it as well as freeing
- * */
-
-UvVertMap *EM_make_uv_vert_map(EditMesh *em, int selected, int do_face_idx_array, float *limit)
-{
- EditVert *ev;
- EditFace *efa;
- int totverts;
-
- /* vars from original func */
- UvVertMap *vmap;
- UvMapVert *buf;
- MTFace *tf;
- unsigned int a;
- int i, totuv, nverts;
-
- if (do_face_idx_array)
- EM_init_index_arrays(em, 0, 0, 1);
-
- /* we need the vert */
- for (ev= em->verts.first, totverts=0; ev; ev= ev->next, totverts++) {
- ev->tmp.l = totverts;
- }
-
- totuv = 0;
-
- /* generate UvMapVert array */
- for (efa= em->faces.first; efa; efa= efa->next)
- if(!selected || ((!efa->h) && (efa->f & SELECT)))
- totuv += (efa->v4)? 4: 3;
-
- if(totuv==0) {
- if (do_face_idx_array)
- EM_free_index_arrays();
- return NULL;
- }
- vmap= (UvVertMap*)MEM_callocN(sizeof(*vmap), "UvVertMap");
- if (!vmap) {
- if (do_face_idx_array)
- EM_free_index_arrays();
- return NULL;
- }
-
- vmap->vert= (UvMapVert**)MEM_callocN(sizeof(*vmap->vert)*totverts, "UvMapVert*");
- buf= vmap->buf= (UvMapVert*)MEM_callocN(sizeof(*vmap->buf)*totuv, "UvMapVert");
-
- if (!vmap->vert || !vmap->buf) {
- free_uv_vert_map(vmap);
- if (do_face_idx_array)
- EM_free_index_arrays();
- return NULL;
- }
-
- for (a=0, efa= em->faces.first; efa; a++, efa= efa->next) {
- if(!selected || ((!efa->h) && (efa->f & SELECT))) {
- nverts= (efa->v4)? 4: 3;
-
- for(i=0; i<nverts; i++) {
- buf->tfindex= i;
- buf->f= a;
- buf->separate = 0;
-
- buf->next= vmap->vert[(*(&efa->v1 + i))->tmp.l];
- vmap->vert[(*(&efa->v1 + i))->tmp.l]= buf;
-
- buf++;
- }
- }
- }
-
- /* sort individual uvs for each vert */
- for(a=0, ev=em->verts.first; ev; a++, ev= ev->next) {
- UvMapVert *newvlist= NULL, *vlist=vmap->vert[a];
- UvMapVert *iterv, *v, *lastv, *next;
- float *uv, *uv2, uvdiff[2];
-
- while(vlist) {
- v= vlist;
- vlist= vlist->next;
- v->next= newvlist;
- newvlist= v;
-
- efa = EM_get_face_for_index(v->f);
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- uv = tf->uv[v->tfindex];
-
- lastv= NULL;
- iterv= vlist;
-
- while(iterv) {
- next= iterv->next;
- efa = EM_get_face_for_index(iterv->f);
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- uv2 = tf->uv[iterv->tfindex];
-
- sub_v2_v2v2(uvdiff, uv2, uv);
-
- if(fabs(uv[0]-uv2[0]) < limit[0] && fabs(uv[1]-uv2[1]) < limit[1]) {
- if(lastv) lastv->next= next;
- else vlist= next;
- iterv->next= newvlist;
- newvlist= iterv;
- }
- else
- lastv=iterv;
-
- iterv= next;
- }
-
- newvlist->separate = 1;
- }
-
- vmap->vert[a]= newvlist;
- }
-
- if (do_face_idx_array)
- EM_free_index_arrays();
-
- return vmap;
-}
-
-UvMapVert *EM_get_uv_map_vert(UvVertMap *vmap, unsigned int v)
-{
- return vmap->vert[v];
-}
-
-void EM_free_uv_vert_map(UvVertMap *vmap)
-{
- if (vmap) {
- if (vmap->vert) MEM_freeN(vmap->vert);
- if (vmap->buf) MEM_freeN(vmap->buf);
- MEM_freeN(vmap);
- }
-}
-
-/* poll call for mesh operators requiring a view3d context */
-int EM_view3d_poll(bContext *C)
-{
- if(ED_operator_editmesh(C) && ED_operator_view3d_active(C))
- return 1;
- return 0;
-}
-
-/* higher quality normals */
-
-/* NormalCalc */
-/* NormalCalc modifier: calculates higher quality normals
-*/
-
-/* each edge uses this to */
-typedef struct EdgeFaceRef {
- int f1; /* init as -1 */
- int f2;
-} EdgeFaceRef;
-
-void EM_make_hq_normals(EditMesh *em)
-{
- EditFace *efa;
- EditVert *eve;
- int i;
-
- EdgeHash *edge_hash = BLI_edgehash_new();
- EdgeHashIterator *edge_iter;
- int edge_ref_count = 0;
- int ed_v1, ed_v2; /* use when getting the key */
- EdgeFaceRef *edge_ref_array = MEM_callocN(em->totedge * sizeof(EdgeFaceRef), "Edge Connectivity");
- EdgeFaceRef *edge_ref;
- float edge_normal[3];
-
- EM_init_index_arrays(em, 1, 1, 1);
-
- for(eve= em->verts.first, i=0; eve; eve= eve->next, i++) {
- zero_v3(eve->no);
- eve->tmp.l= i;
- }
-
- /* This function adds an edge hash if its not there, and adds the face index */
-#define NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(EDV1, EDV2); \
- edge_ref = (EdgeFaceRef *)BLI_edgehash_lookup(edge_hash, EDV1, EDV2); \
- if (!edge_ref) { \
- edge_ref = &edge_ref_array[edge_ref_count]; edge_ref_count++; \
- edge_ref->f1=i; \
- edge_ref->f2=-1; \
- BLI_edgehash_insert(edge_hash, EDV1, EDV2, edge_ref); \
- } else { \
- edge_ref->f2=i; \
- }
-
-
- efa= em->faces.first;
- for(i = 0; i < em->totface; i++, efa= efa->next) {
- if(efa->v4) {
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v1->tmp.l, efa->v2->tmp.l);
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v2->tmp.l, efa->v3->tmp.l);
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v3->tmp.l, efa->v4->tmp.l);
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v4->tmp.l, efa->v1->tmp.l);
- } else {
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v1->tmp.l, efa->v2->tmp.l);
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v2->tmp.l, efa->v3->tmp.l);
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v3->tmp.l, efa->v1->tmp.l);
- }
- }
-
-#undef NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE
-
-
- for(edge_iter = BLI_edgehashIterator_new(edge_hash); !BLI_edgehashIterator_isDone(edge_iter); BLI_edgehashIterator_step(edge_iter)) {
- /* Get the edge vert indices, and edge value (the face indices that use it)*/
- BLI_edgehashIterator_getKey(edge_iter, (int*)&ed_v1, (int*)&ed_v2);
- edge_ref = BLI_edgehashIterator_getValue(edge_iter);
-
- if (edge_ref->f2 != -1) {
- EditFace *ef1= EM_get_face_for_index(edge_ref->f1), *ef2= EM_get_face_for_index(edge_ref->f2);
- float angle= angle_normalized_v3v3(ef1->n, ef2->n);
- if(angle > 0.0f) {
- /* We have 2 faces using this edge, calculate the edges normal
- * using the angle between the 2 faces as a weighting */
- add_v3_v3v3(edge_normal, ef1->n, ef2->n);
- normalize_v3(edge_normal);
- mul_v3_fl(edge_normal, angle);
- }
- else {
- /* cant do anything useful here!
- Set the face index for a vert incase it gets a zero normal */
- EM_get_vert_for_index(ed_v1)->tmp.l=
- EM_get_vert_for_index(ed_v2)->tmp.l= -(edge_ref->f1 + 1);
- continue;
- }
- } else {
- /* only one face attached to that edge */
- /* an edge without another attached- the weight on this is
- * undefined, M_PI/2 is 90d in radians and that seems good enough */
- VECCOPY(edge_normal, EM_get_face_for_index(edge_ref->f1)->n)
- mul_v3_fl(edge_normal, M_PI/2);
- }
- add_v3_v3(EM_get_vert_for_index(ed_v1)->no, edge_normal );
- add_v3_v3(EM_get_vert_for_index(ed_v2)->no, edge_normal );
-
-
- }
- BLI_edgehashIterator_free(edge_iter);
- BLI_edgehash_free(edge_hash, NULL);
- MEM_freeN(edge_ref_array);
-
- /* normalize vertex normals and assign */
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(normalize_v3(eve->no) == 0.0f && eve->tmp.l < 0) {
- /* exceptional case, totally flat */
- efa= EM_get_face_for_index(-(eve->tmp.l) - 1);
- VECCOPY(eve->no, efa->n);
- }
- }
-
- EM_free_index_arrays();
-}
-
-void EM_solidify(EditMesh *em, float dist)
-{
- EditFace *efa;
- EditVert *eve;
- float *vert_angles= MEM_callocN(sizeof(float) * em->totvert * 2, "EM_solidify"); /* 2 in 1 */
- float *vert_accum= vert_angles + em->totvert;
- float face_angles[4];
- int i, j;
-
- for(eve= em->verts.first, i=0; eve; eve= eve->next, i++) {
- eve->tmp.l= i;
- }
-
- efa= em->faces.first;
- for(i = 0; i < em->totface; i++, efa= efa->next) {
-
- if(!(efa->f & SELECT))
- continue;
-
- if(efa->v4) {
- angle_quad_v3(face_angles, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- j= 3;
- }
- else {
- angle_tri_v3(face_angles, efa->v1->co, efa->v2->co, efa->v3->co);
- j= 2;
- }
-
- for(; j>=0; j--) {
- eve= *(&efa->v1 + j);
- vert_accum[eve->tmp.l] += face_angles[j];
- vert_angles[eve->tmp.l]+= shell_angle_to_dist(angle_normalized_v3v3(eve->no, efa->n)) * face_angles[j];
- }
- }
-
- for(eve= em->verts.first, i=0; eve; eve= eve->next, i++) {
- if(vert_accum[i]) { /* zero if unselected */
- madd_v3_v3fl(eve->co, eve->no, dist * vert_angles[i] / vert_accum[i]);
- }
- }
-
- MEM_freeN(vert_angles);
-}
-
-/* not that optimal!, should be nicer with bmesh */
-static void tag_face_edges(EditFace *efa)
-{
- if(efa->v4)
- efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;
- else
- efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
-}
-static int tag_face_edges_test(EditFace *efa)
-{
- if(efa->v4)
- return (efa->e1->tmp.l || efa->e2->tmp.l || efa->e3->tmp.l || efa->e4->tmp.l) ? 1:0;
- else
- return (efa->e1->tmp.l || efa->e2->tmp.l || efa->e3->tmp.l) ? 1:0;
-}
-
-static void em_deselect_nth_face(EditMesh *em, int nth, EditFace *efa_act)
-{
- EditFace *efa;
- EditEdge *eed;
- int ok= 1;
-
- if(efa_act==NULL) {
- return;
- }
-
- /* to detect loose edges, we put f2 flag on 1 */
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->tmp.l= 0;
- }
-
- for (efa= em->faces.first; efa; efa= efa->next) {
- efa->tmp.l = 0;
- }
-
- efa_act->tmp.l = 1;
-
- while(ok) {
- ok = 0;
-
- for (efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- if(efa->tmp.l==1) { /* initialize */
- tag_face_edges(efa);
- }
-
- if(efa->tmp.l) {
- efa->tmp.l++;
- }
- }
- }
-
- for (efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- if(efa->tmp.l==0 && tag_face_edges_test(efa)) {
- efa->tmp.l= 1;
- ok = 1; /* keep looping */
- }
- }
- }
- }
-
- for (efa= em->faces.first; efa; efa= efa->next) {
- if(efa->tmp.l > 0 && efa->tmp.l % nth) {
- EM_select_face(efa, 0);
- }
- }
- for (efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- EM_select_face(efa, 1);
- }
- }
-
- EM_nvertices_selected(em);
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-/* not that optimal!, should be nicer with bmesh */
-static void tag_edge_verts(EditEdge *eed)
-{
- eed->v1->tmp.l= eed->v2->tmp.l= 1;
-}
-static int tag_edge_verts_test(EditEdge *eed)
-{
- return (eed->v1->tmp.l || eed->v2->tmp.l) ? 1:0;
-}
-
-static void em_deselect_nth_edge(EditMesh *em, int nth, EditEdge *eed_act)
-{
- EditEdge *eed;
- EditVert *eve;
- int ok= 1;
-
- if(eed_act==NULL) {
- return;
- }
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- eve->tmp.l= 0;
- }
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- eed->tmp.l = 0;
- }
-
- eed_act->tmp.l = 1;
-
- while(ok) {
- ok = 0;
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- if(eed->tmp.l==1) { /* initialize */
- tag_edge_verts(eed);
- }
-
- if(eed->tmp.l) {
- eed->tmp.l++;
- }
- }
- }
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- if(eed->tmp.l==0 && tag_edge_verts_test(eed)) {
- eed->tmp.l= 1;
- ok = 1; /* keep looping */
- }
- }
- }
- }
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->tmp.l > 0 && eed->tmp.l % nth) {
- EM_select_edge(eed, 0);
- }
- }
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- EM_select_edge(eed, 1);
- }
- }
-
- {
- /* grr, should be a function */
- EditFace *efa;
- for (efa= em->faces.first; efa; efa= efa->next) {
- if(efa->v4) {
- if(efa->e1->f & efa->e2->f & efa->e3->f & efa->e4->f & SELECT );
- else efa->f &= ~SELECT;
- }
- else {
- if(efa->e1->f & efa->e2->f & efa->e3->f & SELECT );
- else efa->f &= ~SELECT;
- }
- }
- }
-
- EM_nvertices_selected(em);
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-static void em_deselect_nth_vert(EditMesh *em, int nth, EditVert *eve_act)
-{
- EditVert *eve;
- EditEdge *eed;
- int ok= 1;
-
- if(eve_act==NULL) {
- return;
- }
-
- for (eve= em->verts.first; eve; eve= eve->next) {
- eve->tmp.l = 0;
- }
-
- eve_act->tmp.l = 1;
-
- while(ok) {
- ok = 0;
-
- for (eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
- if(eve->tmp.l)
- eve->tmp.l++;
- }
- }
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- if(eed->v1->tmp.l==2 && eed->v2->tmp.l==0) { /* initialize */
- eed->v2->tmp.l= 1;
- ok = 1; /* keep looping */
- }
- else if(eed->v2->tmp.l==2 && eed->v1->tmp.l==0) { /* initialize */
- eed->v1->tmp.l= 1;
- ok = 1; /* keep looping */
- }
- }
- }
- }
-
- for (eve= em->verts.first; eve; eve= eve->next) {
- if(eve->tmp.l > 0 && eve->tmp.l % nth) {
- eve->f &= ~SELECT;
- }
- }
-
- EM_deselect_flush(em);
-
- EM_nvertices_selected(em);
- // EM_nedges_selected(em); // flush does these
- // EM_nfaces_selected(em); // flush does these
-}
-
-static void deselect_nth_active(EditMesh *em, EditVert **eve_p, EditEdge **eed_p, EditFace **efa_p)
-{
- EditSelection *ese;
-
- *eve_p= NULL;
- *eed_p= NULL;
- *efa_p= NULL;
-
- ese= (EditSelection*)em->selected.last;
-
- if(ese) {
- switch(ese->type) {
- case EDITVERT:
- *eve_p= (EditVert *)ese->data;
- return;
- case EDITEDGE:
- *eed_p= (EditEdge *)ese->data;
- return;
- case EDITFACE:
- *efa_p= (EditFace *)ese->data;
- return;
- }
- }
-
- if(em->selectmode & SCE_SELECT_VERTEX) {
- EditVert *eve;
- for (eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
- *eve_p= eve;
- return;
- }
- }
- }
-
- if(em->selectmode & SCE_SELECT_EDGE) {
- EditEdge *eed;
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- *eed_p= eed;
- return;
- }
- }
- }
-
- if(em->selectmode & SCE_SELECT_FACE) {
- EditFace *efa= EM_get_actFace(em, 1);
- if(efa) {
- *efa_p= efa;
- return;
- }
- }
-}
-
-int EM_deselect_nth(EditMesh *em, int nth)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- deselect_nth_active(em, &eve, &eed, &efa);
-
- if(eve)
- em_deselect_nth_vert(em, nth, eve);
- else if (eed)
- em_deselect_nth_edge(em, nth, eed);
- else if (efa)
- em_deselect_nth_face(em, nth, efa);
- else
- return 0;
-
- return 1;
-}
-
-void EM_project_snap_verts(bContext *C, ARegion *ar, Object *obedit, EditMesh *em)
-{
- EditVert *eve;
- for(eve= em->verts.first;eve; eve=eve->next) {
- if(eve->f & SELECT) {
- float mval[2], vec[3], no_dummy[3];
- int dist_dummy;
- mul_v3_m4v3(vec, obedit->obmat, eve->co);
- project_float_noclip(ar, vec, mval);
- if(snapObjectsContext(C, mval, &dist_dummy, vec, no_dummy, SNAP_NOT_OBEDIT)) {
- mul_v3_m4v3(eve->co, obedit->imat, vec);
- }
- }
- }
-}
diff --git a/source/blender/editors/mesh/editmesh_loop.c b/source/blender/editors/mesh/editmesh_loop.c
deleted file mode 100644
index 71b66d3e163..00000000000
--- a/source/blender/editors/mesh/editmesh_loop.c
+++ /dev/null
@@ -1,731 +0,0 @@
-/*
- * $Id$
- *
- * ***** 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) 2004 by Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/*
-
-editmesh_loop: tools with own drawing subloops, select, knife, subdiv
-
-*/
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-#include "BLI_editVert.h"
-#include "BLI_ghash.h"
-
-#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_mesh.h"
-#include "BKE_array_mallocn.h"
-
-#include "PIL_time.h"
-
-#include "BIF_gl.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_mesh.h"
-#include "ED_view3d.h"
-
-#include "mesh_intern.h"
-
-/* **** XXX ******** */
-static void error(const char *UNUSED(arg)) {}
-/* **** XXX ******** */
-
-#if 0 /* UNUSED 2.5 */
-static void edgering_sel(EditMesh *em, EditEdge *startedge, int select, int previewlines)
-{
- EditEdge *eed;
- EditFace *efa;
- EditVert *v[2][2];
- float co[2][3];
- int looking= 1,i;
-
- /* in eed->f1 we put the valence (amount of faces in edge) */
- /* in eed->f2 we put tagged flag as correct loop */
- /* in efa->f1 we put tagged flag as correct to select */
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0;
- eed->f2= 0;
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->f1= 0;
- if(efa->h==0) {
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4) efa->e4->f1++;
- }
- }
-
- // tag startedge OK
- startedge->f2= 1;
-
- while(looking) {
- looking= 0;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->e4 && efa->f1==0 && efa->h == 0) { // not done quad
- if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { // valence ok
-
- // if edge tagged, select opposing edge and mark face ok
- if(efa->e1->f2) {
- efa->e3->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- else if(efa->e2->f2) {
- efa->e4->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e3->f2) {
- efa->e1->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e4->f2) {
- efa->e2->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- }
- }
- }
- }
-
- if(previewlines > 0 && select == 0){
-// XXX persp(PERSP_VIEW);
-// XXX glPushMatrix();
-// XXX mymultmatrix(obedit->obmat);
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->v4 == NULL) { continue; }
- if(efa->h == 0){
- if(efa->e1->f2 == 1){
- if(efa->e1->h == 1 || efa->e3->h == 1 )
- continue;
-
- v[0][0] = efa->v1;
- v[0][1] = efa->v2;
- v[1][0] = efa->v4;
- v[1][1] = efa->v3;
- } else if(efa->e2->f2 == 1){
- if(efa->e2->h == 1 || efa->e4->h == 1)
- continue;
- v[0][0] = efa->v2;
- v[0][1] = efa->v3;
- v[1][0] = efa->v1;
- v[1][1] = efa->v4;
- } else { continue; }
-
- for(i=1;i<=previewlines;i++){
- co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0];
- co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1];
- co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2];
-
- co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0];
- co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1];
- co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2];
- glColor3ub(255, 0, 255);
- glBegin(GL_LINES);
- glVertex3f(co[0][0],co[0][1],co[0][2]);
- glVertex3f(co[1][0],co[1][1],co[1][2]);
- glEnd();
- }
- }
- }
- glPopMatrix();
- } else {
-
- /* (de)select the edges */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f2) EM_select_edge(eed, select);
- }
- }
-}
-
-static void CutEdgeloop(Object *obedit, wmOperator *op, EditMesh *em, int numcuts)
-{
- ViewContext vc; // XXX
- EditEdge *nearest=NULL, *eed;
- float fac;
- int keys = 0, holdnum=0, selectmode, dist;
- short mvalo[2] = {0, 0}, mval[2] = {0, 0};
- short event=0, val, choosing=1, cancel=0, cuthalf = 0, smooth=0;
- short hasHidden = 0;
- char msg[128];
-
- selectmode = em->selectmode;
-
- if(em->selectmode & SCE_SELECT_FACE){
- em->selectmode = SCE_SELECT_EDGE;
- EM_selectmode_set(em);
- }
-
-
- BIF_undo_push("Loopcut Begin");
- while(choosing && !cancel){
-// XXX getmouseco_areawin(mval);
- if (mval[0] != mvalo[0] || mval[1] != mvalo[1]) {
- mvalo[0] = mval[0];
- mvalo[1] = mval[1];
- dist= 50;
- nearest = findnearestedge(&vc, &dist); // returns actual distance in dist
-// scrarea_do_windraw(curarea); // after findnearestedge, backbuf!
-
- BLI_snprintf(msg, sizeof(msg),"Number of Cuts: %d (S)mooth: %s", numcuts, smooth ? "on":"off");
-
-// headerprint(msg);
- /* Need to figure preview */
- if(nearest){
- edgering_sel(em, nearest, 0, numcuts);
- }
-// XXX screen_swapbuffers();
-
- /* backbuffer refresh for non-apples (no aux) */
-#ifndef __APPLE__
-// XXX if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
-// backdrawview3d(0);
-// }
-#endif
- }
- else PIL_sleep_ms(10); // idle
-
-
- while(qtest())
- {
- val=0;
-// XXX event= extern_qread(&val);
- if(val && (event == MOUSEX || event == MOUSEY)){ ; }
- else if(val && ((event==LEFTMOUSE || event==RETKEY) || (event == MIDDLEMOUSE || event==PADENTER)))
- {
- if(event == MIDDLEMOUSE){
- cuthalf = 1;
- }
- if (nearest==NULL)
- cancel = 1;
- choosing=0;
- mvalo[0] = -1;
- }
- else if(val && (event==ESCKEY || event==RIGHTMOUSE ))
- {
- choosing=0;
- cancel = 1;
- mvalo[0] = -1;
- }
- else if(val && (event==PADPLUSKEY || event==WHEELUPMOUSE))
- {
- numcuts++;
- mvalo[0] = -1;
- }
- else if(val && (event==PADMINUS || event==WHEELDOWNMOUSE))
- {
- if(numcuts > 1){
- numcuts--;
- mvalo[0] = -1;
- }
- }
- else if(val && event==SKEY)
- {
- if(smooth){smooth=0;}
- else { smooth=1; }
- mvalo[0] = -1;
- }
-
- else if(val){
- holdnum = -1;
- switch(event){
- case PAD9:
- case NINEKEY:
- holdnum = 9; break;
- case PAD8:
- case EIGHTKEY:
- holdnum = 8;break;
- case PAD7:
- case SEVENKEY:
- holdnum = 7;break;
- case PAD6:
- case SIXKEY:
- holdnum = 6;break;
- case PAD5:
- case FIVEKEY:
- holdnum = 5;break;
- case PAD4:
- case FOURKEY:
- holdnum = 4;break;
- case PAD3:
- case THREEKEY:
- holdnum = 3; break;
- case PAD2:
- case TWOKEY:
- holdnum = 2;break;
- case PAD1:
- case ONEKEY:
- holdnum = 1; break;
- case PAD0:
- case ZEROKEY:
- holdnum = 0;break;
- case BACKSPACEKEY:
- holdnum = -2;break;
- }
- if(holdnum >= 0 && numcuts*10 < 130){
- if(keys == 0){ // first level numeric entry
- if(holdnum > 0){
- numcuts = holdnum;
- keys++;
- }
- } else if(keys > 0){//highrt level numeric entry
- numcuts *= 10;
- numcuts += holdnum;
- keys++;
- }
- } else if (holdnum == -2){// backspace
- if (keys > 1){
- numcuts /= 10;
- keys--;
- } else {
- numcuts=1;
- keys = 0;
- }
- }
- mvalo[0] = -1;
- break;
- } // End Numeric Entry
- } //End while(qtest())
- } // End Choosing
-
- if(cancel){
- return;
- }
- /* clean selection */
- for(eed=em->edges.first; eed; eed = eed->next){
- EM_select_edge(eed,0);
- }
- /* select edge ring */
- edgering_sel(em, nearest, 1, 0);
-
- /* now cut the loops */
- if(smooth){
- fac= 1.0f;
-// XXX if(fbutton(&fac, 0.0f, 5.0f, 10, 10, "Smooth:")==0) return;
- fac= 0.292f*fac;
- esubdivideflag(obedit, em, SELECT,fac,0,B_SMOOTH,numcuts, SUBDIV_CORNER_PATH, SUBDIV_SELECT_LOOPCUT);
- } else {
- esubdivideflag(obedit, em, SELECT,0,0,0,numcuts,SUBDIV_CORNER_PATH, SUBDIV_SELECT_LOOPCUT);
- }
- /* if this was a single cut, enter edgeslide mode */
- if(numcuts == 1 && hasHidden == 0){
- if(cuthalf)
- EdgeSlide(em, op, 1,0.0);
- else {
- if(EdgeSlide(em, op, 0,0.0) == -1){
- BIF_undo();
- }
- }
- }
-
- if(em->selectmode != selectmode){
- em->selectmode = selectmode;
- EM_selectmode_set(em);
- }
-
-// DAG_id_tag_update(obedit->data, 0);
- return;
-}
-#endif
-
-/* *************** LOOP SELECT ************* */
-#if 0
-static short edgeFaces(EditMesh *em, EditEdge *e)
-{
- EditFace *search=NULL;
- short count = 0;
-
- search = em->faces.first;
- while(search){
- if((search->e1 == e || search->e2 == e) || (search->e3 == e || search->e4 == e))
- count++;
- search = search->next;
- }
- return count;
-}
-#endif
-
-
-
-/* ***************** TRAIL ************************
-
-Read a trail of mouse coords and return them as an array of CutCurve structs
-len returns number of mouse coords read before commiting with RETKEY
-It is up to the caller to free the block when done with it,
-
-XXX Is only used here, so local inside this file (ton)
- */
-
-#define TRAIL_POLYLINE 1 /* For future use, They don't do anything yet */
-#define TRAIL_FREEHAND 2
-#define TRAIL_MIXED 3 /* (1|2) */
-#define TRAIL_AUTO 4
-#define TRAIL_MIDPOINTS 8
-
-typedef struct CutCurve {
- float x;
- float y;
-} CutCurve;
-
-
-/* ******************************************************************** */
-/* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail
- drawn by user.
-
- Currently mapped to KKey when in MeshEdit mode.
- Usage:
- Hit Shift K, Select Centers or Exact
- Hold LMB down to draw path, hit RETKEY.
- ESC cancels as expected.
-
- Contributed by Robert Wenzlaff (Det. Thorn).
-
- 2.5 revamp:
- - non modal (no menu before cutting)
- - exit on mouse release
- - polygon/segment drawing can become handled by WM cb later
-
-*/
-
-#define KNIFE_EXACT 1
-#define KNIFE_MIDPOINT 2
-#define KNIFE_MULTICUT 3
-
-static EnumPropertyItem knife_items[]= {
- {KNIFE_EXACT, "EXACT", 0, "Exact", ""},
- {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""},
- {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-/* seg_intersect() Determines if and where a mouse trail intersects an EditEdge */
-
-static float seg_intersect(EditEdge *e, CutCurve *c, int len, char mode, struct GHash *gh)
-{
-#define MAXSLOPE 100000
- float x11, y11, x12=0, y12=0, x2max, x2min, y2max;
- float y2min, dist, lastdist=0, xdiff2, xdiff1;
- float m1, b1, m2, b2, x21, x22, y21, y22, xi;
- float yi, x1min, x1max, y1max, y1min, perc=0;
- float *scr;
- float threshold;
- int i;
-
- threshold = 0.000001; /*tolerance for vertex intersection*/
- // XXX threshold = scene->toolsettings->select_thresh / 100;
-
- /* Get screen coords of verts */
- scr = BLI_ghash_lookup(gh, e->v1);
- x21=scr[0];
- y21=scr[1];
-
- scr = BLI_ghash_lookup(gh, e->v2);
- x22=scr[0];
- y22=scr[1];
-
- xdiff2=(x22-x21);
- if (xdiff2) {
- m2=(y22-y21)/xdiff2;
- b2= ((x22*y21)-(x21*y22))/xdiff2;
- }
- else {
- m2=MAXSLOPE; /* Verticle slope */
- b2=x22;
- }
-
- /*check for *exact* vertex intersection first*/
- if(mode!=KNIFE_MULTICUT){
- for (i=0; i<len; i++){
- if (i>0){
- x11=x12;
- y11=y12;
- }
- else {
- x11=c[i].x;
- y11=c[i].y;
- }
- x12=c[i].x;
- y12=c[i].y;
-
- /*test e->v1*/
- if((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)){
- e->v1->f1 = 1;
- perc = 0;
- return(perc);
- }
- /*test e->v2*/
- else if((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)){
- e->v2->f1 = 1;
- perc = 0;
- return(perc);
- }
- }
- }
-
- /*now check for edge interesect (may produce vertex intersection as well)*/
- for (i=0; i<len; i++){
- if (i>0){
- x11=x12;
- y11=y12;
- }
- else {
- x11=c[i].x;
- y11=c[i].y;
- }
- x12=c[i].x;
- y12=c[i].y;
-
- /* Perp. Distance from point to line */
- if (m2!=MAXSLOPE) dist=(y12-m2*x12-b2);/* /sqrt(m2*m2+1); Only looking for */
- /* change in sign. Skip extra math */
- else dist=x22-x12;
-
- if (i==0) lastdist=dist;
-
- /* if dist changes sign, and intersect point in edge's Bound Box*/
- if ((lastdist*dist)<=0){
- xdiff1=(x12-x11); /* Equation of line between last 2 points */
- if (xdiff1){
- m1=(y12-y11)/xdiff1;
- b1= ((x12*y11)-(x11*y12))/xdiff1;
- }
- else{
- m1=MAXSLOPE;
- b1=x12;
- }
- x2max=MAX2(x21,x22)+0.001; /* prevent missed edges */
- x2min=MIN2(x21,x22)-0.001; /* due to round off error */
- y2max=MAX2(y21,y22)+0.001;
- y2min=MIN2(y21,y22)-0.001;
-
- /* Found an intersect, calc intersect point */
- if (m1==m2){ /* co-incident lines */
- /* cut at 50% of overlap area*/
- x1max=MAX2(x11, x12);
- x1min=MIN2(x11, x12);
- xi= (MIN2(x2max,x1max)+MAX2(x2min,x1min))/2.0;
-
- y1max=MAX2(y11, y12);
- y1min=MIN2(y11, y12);
- yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0;
- }
- else if (m2==MAXSLOPE){
- xi=x22;
- yi=m1*x22+b1;
- }
- else if (m1==MAXSLOPE){
- xi=x12;
- yi=m2*x12+b2;
- }
- else {
- xi=(b1-b2)/(m2-m1);
- yi=(b1*m2-m1*b2)/(m2-m1);
- }
-
- /* Intersect inside bounding box of edge?*/
- if ((xi>=x2min)&&(xi<=x2max)&&(yi<=y2max)&&(yi>=y2min)){
- /*test for vertex intersect that may be 'close enough'*/
- if(mode!=KNIFE_MULTICUT){
- if(xi <= (x21 + threshold) && xi >= (x21 - threshold)){
- if(yi <= (y21 + threshold) && yi >= (y21 - threshold)){
- e->v1->f1 = 1;
- perc = 0;
- break;
- }
- }
- if(xi <= (x22 + threshold) && xi >= (x22 - threshold)){
- if(yi <= (y22 + threshold) && yi >= (y22 - threshold)){
- e->v2->f1 = 1;
- perc = 0;
- break;
- }
- }
- }
- if ((m2<=1.0)&&(m2>=-1.0)) perc = (xi-x21)/(x22-x21);
- else perc=(yi-y21)/(y22-y21); /*lower slope more accurate*/
- //isect=32768.0*(perc+0.0000153); /* Percentage in 1/32768ths */
-
- break;
- }
- }
- lastdist=dist;
- }
- return(perc);
-}
-
-
-#define MAX_CUTS 256
-
-static int knife_cut_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- ARegion *ar= CTX_wm_region(C);
- EditEdge *eed;
- EditVert *eve;
- CutCurve curve[MAX_CUTS];
- struct GHash *gh;
- float isect=0.0;
- float *scr, co[4];
- int len=0;
- short numcuts= RNA_int_get(op->ptr, "num_cuts");
- short mode= RNA_int_get(op->ptr, "type");
-// int corner_cut_pattern= RNA_enum_get(op->ptr,"corner_cut_pattern");
-
- /* edit-object needed for matrix, and ar->regiondata for projections to work */
- if (ELEM3(NULL, obedit, ar, ar->regiondata))
- return OPERATOR_CANCELLED;
-
- if (EM_nvertices_selected(em) < 2) {
- error("No edges are selected to operate on");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- /* get the cut curve */
- RNA_BEGIN(op->ptr, itemptr, "path") {
-
- RNA_float_get_array(&itemptr, "loc", (float *)&curve[len]);
- len++;
- if(len>= MAX_CUTS) break;
- }
- RNA_END;
-
- if(len<2) {
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- /*store percentage of edge cut for KNIFE_EXACT here.*/
- for(eed=em->edges.first; eed; eed= eed->next)
- eed->tmp.fp = 0.0;
-
- /*the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer*/
- gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife_cut_exec gh");
- for(eve=em->verts.first; eve; eve=eve->next){
- scr = MEM_mallocN(sizeof(float)*2, "Vertex Screen Coordinates");
- VECCOPY(co, eve->co);
- co[3]= 1.0;
- mul_m4_v4(obedit->obmat, co);
- project_float(ar, co, scr);
- BLI_ghash_insert(gh, eve, scr);
- eve->f1 = 0; /*store vertex intersection flag here*/
-
- }
-
- eed= em->edges.first;
- while(eed) {
- if( eed->v1->f & eed->v2->f & SELECT ){ // NOTE: uses vertex select, subdiv doesnt do edges yet
- isect= seg_intersect(eed, curve, len, mode, gh);
- if (isect!=0.0f) eed->f2= 1;
- else eed->f2=0;
- eed->tmp.fp= isect;
- }
- else {
- eed->f2=0;
- eed->f1=0;
- }
- eed= eed->next;
- }
-
- if (mode==KNIFE_MIDPOINT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, 1, SUBDIV_CORNER_INNERVERT, SUBDIV_SELECT_INNER);
- else if (mode==KNIFE_MULTICUT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, numcuts, SUBDIV_CORNER_INNERVERT, SUBDIV_SELECT_INNER);
- else esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE|B_PERCENTSUBD, 1, SUBDIV_CORNER_INNERVERT, SUBDIV_SELECT_INNER);
-
- eed=em->edges.first;
- while(eed){
- eed->f2=0;
- eed->f1=0;
- eed=eed->next;
- }
-
- BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-
-void MESH_OT_knife_cut(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- ot->name= "Knife Cut";
- ot->description= "Cut selected edges and faces into parts";
- ot->idname= "MESH_OT_knife_cut";
-
- ot->invoke= WM_gesture_lines_invoke;
- ot->modal= WM_gesture_lines_modal;
- ot->exec= knife_cut_exec;
-
- ot->poll= EM_view3d_poll;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", "");
- prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
- RNA_def_int(ot->srna, "num_cuts", 1, 1, MAX_CUTS, "Number of Cuts", "Only for Multi-Cut", 1, MAX_CUTS);
- // doesn't work atm.. RNA_def_enum(ot->srna, "corner_cut_pattern", corner_type_items, SUBDIV_CORNER_INNERVERT, "Corner Cut Pattern", "Topology pattern to use to fill a face after cutting across its corner");
-
- /* internal */
- RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
-}
-
-/* ******************************************************* */
-
diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c
deleted file mode 100644
index e9c88d095b4..00000000000
--- a/source/blender/editors/mesh/editmesh_mods.c
+++ /dev/null
@@ -1,4459 +0,0 @@
-/*
- * $Id$
- *
- * ***** 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) 2004 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/*
-
-editmesh_mods.c, UI level access, no geometry changes
-
-*/
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_material_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_editVert.h"
-#include "BLI_rand.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_context.h"
-#include "BKE_displist.h"
-#include "BKE_depsgraph.h"
-#include "BKE_mesh.h"
-#include "BKE_material.h"
-#include "BKE_paint.h"
-#include "BKE_report.h"
-#include "BKE_texture.h"
-
-#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h"
-
-#include "RE_render_ext.h" /* externtex */
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "ED_mesh.h"
-#include "ED_screen.h"
-#include "ED_view3d.h"
-
-#include "BIF_gl.h"
-
-#include "mesh_intern.h"
-
-#include "BLO_sys_types.h" // for intptr_t support
-
-/* XXX */
-static void waitcursor(int UNUSED(val)) {}
-static int pupmenu(const char *UNUSED(arg)) {return 0;}
-
-/* ****************************** MIRROR **************** */
-
-void EM_cache_x_mirror_vert(struct Object *ob, struct EditMesh *em)
-{
- EditVert *eve, *eve_mirror;
- int index= 0;
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- eve->tmp.v= NULL;
- }
-
- for(eve= em->verts.first; eve; eve= eve->next, index++) {
- if(eve->tmp.v==NULL) {
- eve_mirror = editmesh_get_x_mirror_vert(ob, em, eve, eve->co, index);
- if(eve_mirror) {
- eve->tmp.v= eve_mirror;
- eve_mirror->tmp.v = eve;
- }
- }
- }
-}
-
-static void EM_select_mirrored(Object *obedit, EditMesh *em, int extend)
-{
-
- EditVert *eve;
-
- EM_cache_x_mirror_vert(obedit, em);
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT && eve->tmp.v && (eve->tmp.v != eve->tmp.v->tmp.v)) {
- eve->tmp.v->f |= SELECT;
-
- if(extend==FALSE)
- eve->f &= ~SELECT;
-
- /* remove the interference */
- eve->tmp.v->tmp.v= NULL;
- eve->tmp.v= NULL;
- }
- }
-}
-
-void EM_automerge(Scene *scene, Object *obedit, int update)
-{
- Mesh *me= obedit ? obedit->data : NULL; /* can be NULL */
- int len;
-
- if ((scene->toolsettings->automerge) &&
- (obedit && obedit->type==OB_MESH && (obedit->mode & OB_MODE_EDIT)) &&
- (me->mr==NULL)
- ) {
- EditMesh *em= me->edit_mesh;
-
- len = removedoublesflag(em, 1, 1, scene->toolsettings->doublimit);
- if (len) {
- em->totvert -= len; /* saves doing a countall */
- if (update) {
- DAG_id_tag_update(&me->id, 0);
- }
- }
- }
-}
-
-/* ****************************** SELECTION ROUTINES **************** */
-
-unsigned int em_solidoffs=0, em_wireoffs=0, em_vertoffs=0; /* set in drawobject.c ... for colorindices */
-
-/* facilities for border select and circle select */
-static char *selbuf= NULL;
-
-/* opengl doesn't support concave... */
-static void draw_triangulated(short mcords[][2], short tot)
-{
- ListBase lb={NULL, NULL};
- DispList *dl;
- float *fp;
- int a;
-
- /* make displist */
- dl= MEM_callocN(sizeof(DispList), "poly disp");
- dl->type= DL_POLY;
- dl->parts= 1;
- dl->nr= tot;
- dl->verts= fp= MEM_callocN(tot*3*sizeof(float), "poly verts");
- BLI_addtail(&lb, dl);
-
- for(a=0; a<tot; a++, fp+=3) {
- fp[0]= (float)mcords[a][0];
- fp[1]= (float)mcords[a][1];
- }
-
- /* do the fill */
- filldisplist(&lb, &lb, 0);
-
- /* do the draw */
- dl= lb.first; /* filldisplist adds in head of list */
- if(dl->type==DL_INDEX3) {
- int *index;
-
- a= dl->parts;
- fp= dl->verts;
- index= dl->index;
- glBegin(GL_TRIANGLES);
- while(a--) {
- glVertex3fv(fp+3*index[0]);
- glVertex3fv(fp+3*index[1]);
- glVertex3fv(fp+3*index[2]);
- index+= 3;
- }
- glEnd();
- }
-
- freedisplist(&lb);
-}
-
-
-/* reads rect, and builds selection array for quick lookup */
-/* returns if all is OK */
-int EM_init_backbuf_border(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
-{
- struct ImBuf *buf;
- unsigned int *dr;
- int a;
-
- if(vc->obedit==NULL || vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
-
- buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
- if(buf==NULL) return 0;
- if(em_vertoffs==0) return 0;
-
- dr = buf->rect;
-
- /* build selection lookup */
- selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
-
- a= (xmax-xmin+1)*(ymax-ymin+1);
- while(a--) {
- if(*dr>0 && *dr<=em_vertoffs)
- selbuf[*dr]= 1;
- dr++;
- }
- IMB_freeImBuf(buf);
- return 1;
-}
-
-int EM_check_backbuf(unsigned int index)
-{
- if(selbuf==NULL) return 1;
- if(index>0 && index<=em_vertoffs)
- return selbuf[index];
- return 0;
-}
-
-void EM_free_backbuf(void)
-{
- if(selbuf) MEM_freeN(selbuf);
- selbuf= NULL;
-}
-
-/* mcords is a polygon mask
- - grab backbuffer,
- - draw with black in backbuffer,
- - grab again and compare
- returns 'OK'
-*/
-int EM_mask_init_backbuf_border(ViewContext *vc, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
-{
- unsigned int *dr, *drm;
- struct ImBuf *buf, *bufmask;
- int a;
- GLboolean is_cull;
-
- /* method in use for face selecting too */
- if(vc->obedit==NULL) {
- if(paint_facesel_test(vc->obact));
- else return 0;
- }
- else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
-
- buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
- if(buf==NULL) return 0;
- if(em_vertoffs==0) return 0;
-
- dr = buf->rect;
-
- /* draw the mask */
- glDisable(GL_DEPTH_TEST);
-
- glColor3ub(0, 0, 0);
-
- /* some opengl drivers have problems with draw direction */
- glGetBooleanv(GL_CULL_FACE, &is_cull);
- if(is_cull) glDisable(GL_CULL_FACE);
-
- /* yah, opengl doesn't do concave... tsk! */
- ED_region_pixelspace(vc->ar);
- draw_triangulated(mcords, tot);
-
- glBegin(GL_LINE_LOOP); /* for zero sized masks, lines */
- for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]);
- glEnd();
-
- glFinish(); /* to be sure readpixels sees mask */
-
- /* grab mask */
- bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
- drm = bufmask->rect;
- if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
-
- /* build selection lookup */
- selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
-
- a= (xmax-xmin+1)*(ymax-ymin+1);
- while(a--) {
- if(*dr>0 && *dr<=em_vertoffs && *drm==0) selbuf[*dr]= 1;
- dr++; drm++;
- }
- IMB_freeImBuf(buf);
- IMB_freeImBuf(bufmask);
-
- if(is_cull) glEnable(GL_CULL_FACE);
-
- return 1;
-
-}
-
-/* circle shaped sample area */
-int EM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
-{
- struct ImBuf *buf;
- unsigned int *dr;
- short xmin, ymin, xmax, ymax, xc, yc;
- int radsq;
-
- /* method in use for face selecting too */
- if(vc->obedit==NULL) {
- if(paint_facesel_test(vc->obact));
- else return 0;
- }
- else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
-
- xmin= xs-rads; xmax= xs+rads;
- ymin= ys-rads; ymax= ys+rads;
- buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
- if(em_vertoffs==0) return 0;
- if(buf==NULL) return 0;
-
- dr = buf->rect;
-
- /* build selection lookup */
- selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
- radsq= rads*rads;
- for(yc= -rads; yc<=rads; yc++) {
- for(xc= -rads; xc<=rads; xc++, dr++) {
- if(xc*xc + yc*yc < radsq) {
- if(*dr>0 && *dr<=em_vertoffs) selbuf[*dr]= 1;
- }
- }
- }
-
- IMB_freeImBuf(buf);
- return 1;
-
-}
-
-static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int y, int index)
-{
- struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } *data = userData;
-
- if (data->pass==0) {
- if (index<=data->lastIndex)
- return;
- } else {
- if (index>data->lastIndex)
- return;
- }
-
- if (data->dist>3) {
- int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
- if ((eve->f&1) == data->select) {
- if (data->strict == 1)
- return;
- else
- temp += 5;
- }
-
- if (temp<data->dist) {
- data->dist = temp;
- data->closest = eve;
- data->closestIndex = index;
- }
- }
-}
-
-
-
-
-static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index)
-{
- EditMesh *em= (EditMesh *)handle;
- EditVert *eve = BLI_findlink(&em->verts, index-1);
-
- if(eve && (eve->f & SELECT)) return 0;
- return 1;
-}
-/**
- * findnearestvert
- *
- * dist (in/out): minimal distance to the nearest and at the end, actual distance
- * sel: selection bias
- * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
- * if 0, unselected vertice are given the bias
- * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
- */
-EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short strict)
-{
- if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){
- int distance;
- unsigned int index;
- EditVert *eve;
-
- if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest);
- else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL);
-
- eve = BLI_findlink(&vc->em->verts, index-1);
-
- if(eve && distance < *dist) {
- *dist = distance;
- return eve;
- } else {
- return NULL;
- }
-
- }
- else {
- struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } data;
- static int lastSelectedIndex=0;
- static EditVert *lastSelected=NULL;
-
- if (lastSelected && BLI_findlink(&vc->em->verts, lastSelectedIndex)!=lastSelected) {
- lastSelectedIndex = 0;
- lastSelected = NULL;
- }
-
- data.lastIndex = lastSelectedIndex;
- data.mval[0] = vc->mval[0];
- data.mval[1] = vc->mval[1];
- data.select = sel;
- data.dist = *dist;
- data.strict = strict;
- data.closest = NULL;
- data.closestIndex = 0;
-
- data.pass = 0;
-
- ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
-
- mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
-
- if (data.dist>3) {
- data.pass = 1;
- mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
- }
-
- *dist = data.dist;
- lastSelected = data.closest;
- lastSelectedIndex = data.closestIndex;
-
- return data.closest;
- }
-}
-
-/* returns labda for closest distance v1 to line-piece v2-v3 */
-static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3)
-{
- float rc[2], len;
-
- rc[0]= v3[0]-v2[0];
- rc[1]= v3[1]-v2[1];
- len= rc[0]*rc[0]+ rc[1]*rc[1];
- if(len==0.0f)
- return 0.0f;
-
- return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
-}
-
-/* note; uses v3d, so needs active 3d window */
-static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int UNUSED(index))
-{
- struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } *data = userData;
- float v1[2], v2[2];
- int distance;
-
- ED_view3d_local_clipping(data->vc.rv3d, data->vc.obedit->obmat); /* for local clipping lookups */
-
- v1[0] = x0;
- v1[1] = y0;
- v2[0] = x1;
- v2[1] = y1;
-
- distance= dist_to_line_segment_v2(data->mval, v1, v2);
-
-
- if(eed->f & SELECT) distance+=5;
- if(distance < data->dist) {
- if(data->vc.rv3d->rflag & RV3D_CLIPPING) {
- float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
- float vec[3];
-
- vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
- vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
- vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
-
- if(view3d_test_clipping(data->vc.rv3d, vec, 1)==0) {
- data->dist = distance;
- data->closest = eed;
- }
- }
- else {
- data->dist = distance;
- data->closest = eed;
- }
- }
-}
-EditEdge *findnearestedge(ViewContext *vc, int *dist)
-{
-
- if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
- int distance;
- unsigned int index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_solidoffs, em_wireoffs, &distance,0, NULL, NULL);
- EditEdge *eed = BLI_findlink(&vc->em->edges, index-1);
-
- if (eed && distance<*dist) {
- *dist = distance;
- return eed;
- } else {
- return NULL;
- }
- }
- else {
- struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } data;
-
- data.vc= *vc;
- data.mval[0] = vc->mval[0];
- data.mval[1] = vc->mval[1];
- data.dist = *dist;
- data.closest = NULL;
-
- ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2);
-
- *dist = data.dist;
- return data.closest;
- }
-}
-
-static void findnearestface__getDistance(void *userData, EditFace *efa, int x, int y, int UNUSED(index))
-{
- struct { short mval[2]; int dist; EditFace *toFace; } *data = userData;
-
- if (efa==data->toFace) {
- int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
-
- if (temp<data->dist)
- data->dist = temp;
- }
-}
-static void findnearestface__doClosest(void *userData, EditFace *efa, int x, int y, int index)
-{
- struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } *data = userData;
-
- if (data->pass==0) {
- if (index<=data->lastIndex)
- return;
- } else {
- if (index>data->lastIndex)
- return;
- }
-
- if (data->dist>3) {
- int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
-
- if (temp<data->dist) {
- data->dist = temp;
- data->closest = efa;
- data->closestIndex = index;
- }
- }
-}
-static EditFace *findnearestface(ViewContext *vc, int *dist)
-{
-
- if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
- unsigned int index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
- EditFace *efa = BLI_findlink(&vc->em->faces, index-1);
-
- if (efa) {
- struct { short mval[2]; int dist; EditFace *toFace; } data;
-
- data.mval[0] = vc->mval[0];
- data.mval[1] = vc->mval[1];
- data.dist = 0x7FFF; /* largest short */
- data.toFace = efa;
-
- ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- mesh_foreachScreenFace(vc, findnearestface__getDistance, &data);
-
- if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) { /* only faces, no dist check */
- *dist= data.dist;
- return efa;
- }
- }
-
- return NULL;
- }
- else {
- struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } data;
- static int lastSelectedIndex=0;
- static EditFace *lastSelected=NULL;
-
- if (lastSelected && BLI_findlink(&vc->em->faces, lastSelectedIndex)!=lastSelected) {
- lastSelectedIndex = 0;
- lastSelected = NULL;
- }
-
- data.lastIndex = lastSelectedIndex;
- data.mval[0] = vc->mval[0];
- data.mval[1] = vc->mval[1];
- data.dist = *dist;
- data.closest = NULL;
- data.closestIndex = 0;
-
- data.pass = 0;
-
- ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
-
- if (data.dist>3) {
- data.pass = 1;
- mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
- }
-
- *dist = data.dist;
- lastSelected = data.closest;
- lastSelectedIndex = data.closestIndex;
-
- return data.closest;
- }
-}
-
-/* best distance based on screen coords.
- use em->selectmode to define how to use
- selected vertices and edges get disadvantage
- return 1 if found one
-*/
-static int unified_findnearest(ViewContext *vc, EditVert **eve, EditEdge **eed, EditFace **efa)
-{
- EditMesh *em= vc->em;
- int dist= 75;
-
- *eve= NULL;
- *eed= NULL;
- *efa= NULL;
-
- /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
- view3d_validate_backbuf(vc);
-
- if(em->selectmode & SCE_SELECT_VERTEX)
- *eve= findnearestvert(vc, &dist, SELECT, 0);
- if(em->selectmode & SCE_SELECT_FACE)
- *efa= findnearestface(vc, &dist);
-
- dist-= 20; /* since edges select lines, we give dots advantage of 20 pix */
- if(em->selectmode & SCE_SELECT_EDGE)
- *eed= findnearestedge(vc, &dist);
-
- /* return only one of 3 pointers, for frontbuffer redraws */
- if(*eed) {
- *efa= NULL; *eve= NULL;
- }
- else if(*efa) {
- *eve= NULL;
- }
-
- return (*eve || *eed || *efa);
-}
-
-
-/* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
-
-/* selects new faces/edges/verts based on the existing selection */
-
-/* VERT GROUP */
-
-#define SIMVERT_NORMAL 0
-#define SIMVERT_FACE 1
-#define SIMVERT_VGROUP 2
-#define SIMVERT_TOT 3
-
-/* EDGE GROUP */
-
-#define SIMEDGE_LENGTH 101
-#define SIMEDGE_DIR 102
-#define SIMEDGE_FACE 103
-#define SIMEDGE_FACE_ANGLE 104
-#define SIMEDGE_CREASE 105
-#define SIMEDGE_SEAM 106
-#define SIMEDGE_SHARP 107
-#define SIMEDGE_TOT 108
-
-/* FACE GROUP */
-
-#define SIMFACE_MATERIAL 201
-#define SIMFACE_IMAGE 202
-#define SIMFACE_AREA 203
-#define SIMFACE_PERIMETER 204
-#define SIMFACE_NORMAL 205
-#define SIMFACE_COPLANAR 206
-#define SIMFACE_TOT 207
-
-static EnumPropertyItem prop_similar_types[] = {
- {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
- {SIMVERT_FACE, "FACE", 0, "Amount of Vertices in Face", ""},
- {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
- {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
- {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
- {SIMEDGE_FACE, "FACE", 0, "Amount of Vertices in Face", ""},
- {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
- {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
- {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
- {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
- {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
- {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
- {SIMFACE_AREA, "AREA", 0, "Area", ""},
- {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
- {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
- {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-
-/* this as a way to compare the ares, perim of 2 faces thay will scale to different sizes
-*0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */
-#define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5) <= b))
-
-static int similar_face_select__internal(EditMesh *em, int mode, float thresh)
-{
- EditFace *efa, *base_efa=NULL;
- unsigned int selcount=0; /*count how many new faces we select*/
-
- /*deselcount, count how many deselected faces are left, so we can bail out early
- also means that if there are no deselected faces, we can avoid a lot of looping */
- unsigned int deselcount=0;
- short ok=0;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (!efa->h) {
- if (efa->f & SELECT) {
- efa->f1=1;
- ok=1;
- } else {
- efa->f1=0;
- deselcount++; /* a deselected face we may select later */
- }
- }
- }
-
- if (!ok || !deselcount) /* no data selected OR no more data to select */
- return 0;
-
- if (mode==SIMFACE_AREA) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->tmp.fp= EM_face_area(efa);
- }
- } else if (mode==SIMFACE_PERIMETER) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->tmp.fp= EM_face_perimeter(efa);
- }
- }
-
- for(base_efa= em->faces.first; base_efa; base_efa= base_efa->next) {
- if (base_efa->f1) { /* This was one of the faces originaly selected */
- if (mode==SIMFACE_MATERIAL) { /* same material */
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (
- !(efa->f & SELECT) &&
- !efa->h &&
- base_efa->mat_nr == efa->mat_nr
- ) {
- EM_select_face(efa, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- } else if (mode==SIMFACE_IMAGE) { /* same image */
- MTFace *tf, *base_tf;
-
- base_tf = (MTFace*)CustomData_em_get(&em->fdata, base_efa->data,
- CD_MTFACE);
-
- if(!base_tf)
- return selcount;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (!(efa->f & SELECT) && !efa->h) {
- tf = (MTFace*)CustomData_em_get(&em->fdata, efa->data,
- CD_MTFACE);
-
- if(base_tf->tpage == tf->tpage) {
- EM_select_face(efa, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- }
- } else if (mode==SIMFACE_AREA || mode==SIMFACE_PERIMETER) { /* same area OR same perimeter, both use the same temp var */
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (
- (!(efa->f & SELECT) && !efa->h) &&
- SCALE_CMP(base_efa->tmp.fp, efa->tmp.fp)
- ) {
- EM_select_face(efa, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- } else if (mode==SIMFACE_NORMAL) {
- float angle;
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (!(efa->f & SELECT) && !efa->h) {
- angle= RAD2DEG(angle_v2v2(base_efa->n, efa->n));
- if (angle/180.0<=thresh) {
- EM_select_face(efa, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- }
- } else if (mode==SIMFACE_COPLANAR) { /* same planer */
- float angle, base_dot, dot;
- base_dot= dot_v3v3(base_efa->cent, base_efa->n);
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (!(efa->f & SELECT) && !efa->h) {
- angle= RAD2DEG(angle_v2v2(base_efa->n, efa->n));
- if (angle/180.0<=thresh) {
- dot=dot_v3v3(efa->cent, base_efa->n);
- if (fabs(base_dot-dot) <= thresh) {
- EM_select_face(efa, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- }
- }
- }
- }
- } /* end base_efa loop */
- return selcount;
-}
-
-static int similar_face_select_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- Mesh *me= obedit->data;
- EditMesh *em= BKE_mesh_get_editmesh(me);
-
- int selcount = similar_face_select__internal(em, RNA_int_get(op->ptr, "type"), RNA_float_get(op->ptr, "threshold"));
-
- if (selcount) {
- /* here was an edge-mode only select flush case, has to be generalized */
- EM_selectmode_flush(em);
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(me, em);
- return OPERATOR_FINISHED;
- }
-
- BKE_mesh_end_editmesh(me, em);
- return OPERATOR_CANCELLED;
-}
-
-/* ***************************************************** */
-
-static int similar_edge_select__internal(EditMesh *em, int mode, float thresh)
-{
- EditEdge *eed, *base_eed=NULL;
- unsigned int selcount=0; /* count how many new edges we select*/
-
- /*count how many visible selected edges there are,
- so we can return when there are none left */
- unsigned int deselcount=0;
-
- short ok=0;
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (!eed->h) {
- if (eed->f & SELECT) {
- eed->f1=1;
- ok=1;
- } else {
- eed->f1=0;
- deselcount++;
- }
- /* set all eed->tmp.l to 0 we use it later.
- for counting face users*/
- eed->tmp.l=0;
- eed->f2=0; /* only for mode SIMEDGE_FACE_ANGLE, edge animations */
- }
- }
-
- if (!ok || !deselcount) /* no data selected OR no more data to select*/
- return 0;
-
- if (mode==SIMEDGE_LENGTH) { /*store length*/
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (!eed->h) /* dont calc data for hidden edges*/
- eed->tmp.fp= len_v3v3(eed->v1->co, eed->v2->co);
- }
- } else if (mode==SIMEDGE_FACE) { /*store face users*/
- EditFace *efa;
- /* cound how many faces each edge uses use tmp->l */
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->e1->tmp.l++;
- efa->e2->tmp.l++;
- efa->e3->tmp.l++;
- if (efa->e4) efa->e4->tmp.l++;
- }
- } else if (mode==SIMEDGE_FACE_ANGLE) { /*store edge angles */
- EditFace *efa;
- int j;
- /* cound how many faces each edge uses use tmp.l */
- for(efa= em->faces.first; efa; efa= efa->next) {
- /* here we use the edges temp data to assign a face
- if a face has already been assigned (eed->f2==1)
- we calculate the angle between the current face and
- the edges previously found face.
- store the angle in eed->tmp.fp (loosing the face eed->tmp.f)
- but tagging eed->f2==2, so we know not to look at it again.
- This only works for edges that connect to 2 faces. but its good enough
- */
-
- /* se we can loop through face edges*/
- j=0;
- eed= efa->e1;
- while (j<4) {
- if (j==1) eed= efa->e2;
- else if (j==2) eed= efa->e3;
- else if (j==3) {
- eed= efa->e4;
- if (!eed)
- break;
- } /* done looping */
-
- if (!eed->h) { /* dont calc data for hidden edges*/
- if (eed->f2==2)
- break;
- else if (eed->f2==0) /* first access, assign the face */
- eed->tmp.f= efa;
- else if (eed->f2==1) /* second, we assign the angle*/
- eed->tmp.fp= RAD2DEG(angle_v2v2(eed->tmp.f->n, efa->n))/180;
- eed->f2++; /* f2==0 no face assigned. f2==1 one face found. f2==2 angle calculated.*/
- }
- j++;
- }
- }
- }
-
- for(base_eed= em->edges.first; base_eed; base_eed= base_eed->next) {
- if (base_eed->f1) {
- if (mode==SIMEDGE_LENGTH) { /* same length */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (
- !(eed->f & SELECT) &&
- !eed->h &&
- SCALE_CMP(base_eed->tmp.fp, eed->tmp.fp)
- ) {
- EM_select_edge(eed, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- } else if (mode==SIMEDGE_DIR) { /* same direction */
- float base_dir[3], dir[3], angle;
- sub_v3_v3v3(base_dir, base_eed->v1->co, base_eed->v2->co);
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (!(eed->f & SELECT) && !eed->h) {
- sub_v3_v3v3(dir, eed->v1->co, eed->v2->co);
- angle= RAD2DEG(angle_v2v2(base_dir, dir));
-
- if (angle>90) /* use the smallest angle between the edges */
- angle= fabs(angle-180.0f);
-
- if (angle/90.0<=thresh) {
- EM_select_edge(eed, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- }
- } else if (mode==SIMEDGE_FACE) { /* face users */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (
- !(eed->f & SELECT) &&
- !eed->h &&
- base_eed->tmp.l==eed->tmp.l
- ) {
- EM_select_edge(eed, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- } else if (mode==SIMEDGE_FACE_ANGLE && base_eed->f2==2) { /* edge angles, f2==2 means the edge has an angle. */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (
- !(eed->f & SELECT) &&
- !eed->h &&
- eed->f2==2 &&
- (fabs(base_eed->tmp.fp-eed->tmp.fp)<=thresh)
- ) {
- EM_select_edge(eed, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- } else if (mode==SIMEDGE_CREASE) { /* edge crease */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (
- !(eed->f & SELECT) &&
- !eed->h &&
- (fabs(base_eed->crease-eed->crease) <= thresh)
- ) {
- EM_select_edge(eed, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- } else if (mode==SIMEDGE_SEAM) { /* edge seam */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (
- !(eed->f & SELECT) &&
- !eed->h &&
- (eed->seam == base_eed->seam)
- ) {
- EM_select_edge(eed, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- } else if (mode==SIMEDGE_SHARP) { /* edge sharp */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (
- !(eed->f & SELECT) &&
- !eed->h &&
- (eed->sharp == base_eed->sharp)
- ) {
- EM_select_edge(eed, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- }
- }
- }
- return selcount;
-}
-/* wrap the above function but do selection flushing edge to face */
-static int similar_edge_select_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- Mesh *me= obedit->data;
- EditMesh *em= BKE_mesh_get_editmesh(me);
-
- int selcount = similar_edge_select__internal(em, RNA_int_get(op->ptr, "type"), RNA_float_get(op->ptr, "threshold"));
-
- if (selcount) {
- /* here was an edge-mode only select flush case, has to be generalized */
- EM_selectmode_flush(em);
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(me, em);
- return OPERATOR_FINISHED;
- }
-
- BKE_mesh_end_editmesh(me, em);
- return OPERATOR_CANCELLED;
-}
-
-/* ********************************* */
-
-static int similar_vert_select_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- Mesh *me= obedit->data;
- EditMesh *em= BKE_mesh_get_editmesh(me);
- EditVert *eve, *base_eve=NULL;
- unsigned int selcount=0; /* count how many new edges we select*/
-
- /*count how many visible selected edges there are,
- so we can return when there are none left */
- unsigned int deselcount=0;
- int mode= RNA_enum_get(op->ptr, "type");
- float thresh = RNA_float_get(op->ptr, "threshold");
-
- short ok=0;
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if (!eve->h) {
- if (eve->f & SELECT) {
- eve->f1=1;
- ok=1;
- } else {
- eve->f1=0;
- deselcount++;
- }
- /* set all eve->tmp.l to 0 we use them later.*/
- eve->tmp.l=0;
- }
-
- }
-
- if (!ok || !deselcount) { /* no data selected OR no more data to select*/
- BKE_mesh_end_editmesh(me, em);
- return 0;
- }
-
- if(mode == SIMVERT_FACE) {
- /* store face users */
- EditFace *efa;
-
- /* count how many faces each edge uses use tmp->l */
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->v1->tmp.l++;
- efa->v2->tmp.l++;
- efa->v3->tmp.l++;
- if (efa->v4) efa->v4->tmp.l++;
- }
- }
-
-
- for(base_eve= em->verts.first; base_eve; base_eve= base_eve->next) {
- if (base_eve->f1) {
-
- if(mode == SIMVERT_NORMAL) {
- float angle;
- for(eve= em->verts.first; eve; eve= eve->next) {
- if (!(eve->f & SELECT) && !eve->h) {
- angle= RAD2DEG(angle_v2v2(base_eve->no, eve->no));
- if (angle/180.0<=thresh) {
- eve->f |= SELECT;
- selcount++;
- deselcount--;
- if (!deselcount) {/*have we selected all posible faces?, if so return*/
- BKE_mesh_end_editmesh(me, em);
- return selcount;
- }
- }
- }
- }
- }
- else if(mode == SIMVERT_FACE) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if (
- !(eve->f & SELECT) &&
- !eve->h &&
- base_eve->tmp.l==eve->tmp.l
- ) {
- eve->f |= SELECT;
- selcount++;
- deselcount--;
- if (!deselcount) {/*have we selected all posible faces?, if so return*/
- BKE_mesh_end_editmesh(me, em);
- return selcount;
- }
- }
- }
- }
- else if(mode == SIMVERT_VGROUP) {
- MDeformVert *dvert, *base_dvert;
- short i, j; /* weight index */
-
- base_dvert= CustomData_em_get(&em->vdata, base_eve->data,
- CD_MDEFORMVERT);
-
- if (!base_dvert || base_dvert->totweight == 0) {
- BKE_mesh_end_editmesh(me, em);
- return selcount;
- }
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- dvert= CustomData_em_get(&em->vdata, eve->data,
- CD_MDEFORMVERT);
-
- if (dvert && !(eve->f & SELECT) && !eve->h && dvert->totweight) {
- /* do the extra check for selection in the following if, so were not
- checking verts that may be already selected */
- for (i=0; base_dvert->totweight >i && !(eve->f & SELECT); i++) {
- for (j=0; dvert->totweight >j; j++) {
- if (base_dvert->dw[i].def_nr==dvert->dw[j].def_nr) {
- eve->f |= SELECT;
- selcount++;
- deselcount--;
- if (!deselcount) { /*have we selected all posible faces?, if so return*/
- BKE_mesh_end_editmesh(me, em);
- return selcount;
- }
- break;
- }
- }
- }
- }
- }
- }
- }
- } /* end basevert loop */
-
- if(selcount) {
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(me, em);
- return OPERATOR_FINISHED;
- }
-
- BKE_mesh_end_editmesh(me, em);
- return OPERATOR_CANCELLED;
-}
-
-static int select_similar_exec(bContext *C, wmOperator *op)
-{
- int type= RNA_enum_get(op->ptr, "type");
-
- if(type < 100)
- return similar_vert_select_exec(C, op);
- else if(type < 200)
- return similar_edge_select_exec(C, op);
- else
- return similar_face_select_exec(C, op);
-}
-
-static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
-{
- Object *obedit= CTX_data_edit_object(C);
- EnumPropertyItem *item= NULL;
- int a, totitem= 0;
-
- if (C == NULL) {
- return prop_similar_types;
- }
-
- if(obedit && obedit->type == OB_MESH) {
- EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
-
- if(em->selectmode & SCE_SELECT_VERTEX) {
- for(a=SIMVERT_NORMAL; a<=SIMVERT_TOT; a++)
- RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
- }
- else if(em->selectmode & SCE_SELECT_EDGE) {
- for(a=SIMEDGE_LENGTH; a<=SIMEDGE_TOT; a++)
- RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
- }
- else if(em->selectmode & SCE_SELECT_FACE) {
- for(a=SIMFACE_MATERIAL; a<=SIMFACE_TOT; a++)
- RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
- }
- }
-
- RNA_enum_item_end(&item, &totitem);
- *free= 1;
-
- return item;
-}
-
-void MESH_OT_select_similar(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name= "Select Similar";
- ot->description= "Select similar vertices, edges or faces by property types";
- ot->idname= "MESH_OT_select_similar";
-
- /* api callbacks */
- ot->invoke= WM_menu_invoke;
- ot->exec= select_similar_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- prop= RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
- RNA_def_enum_funcs(prop, select_similar_type_itemf);
- ot->prop= prop;
- RNA_def_float(ot->srna, "threshold", 0.01f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 100.f);
-}
-
-/* ******************************************* */
-
-
-int mesh_layers_menu_charlen(CustomData *data, int type)
-{
- int i, len = 0;
- /* see if there is a duplicate */
- for(i=0; i<data->totlayer; i++) {
- if((&data->layers[i])->type == type) {
- /* we could count the chars here but we'll just assumeme each
- * is 32 chars with some room for the menu text - 40 should be fine */
- len+=40;
- }
- }
- return len;
-}
-
-/* this function adds menu text into an existing string.
- * this string's size should be allocated with mesh_layers_menu_charlen */
-void mesh_layers_menu_concat(CustomData *data, int type, char *str)
-{
- int i, count = 0;
- char *str_pt = str;
- CustomDataLayer *layer;
-
- /* see if there is a duplicate */
- for(i=0; i<data->totlayer; i++) {
- layer = &data->layers[i];
- if(layer->type == type) {
- str_pt += sprintf(str_pt, "%s%%x%d|", layer->name, count);
- count++;
- }
- }
-}
-
-int mesh_layers_menu(CustomData *data, int type) {
- int ret;
- char *str_pt, *str;
-
- str_pt = str = MEM_mallocN(mesh_layers_menu_charlen(data, type) + 18, "layer menu");
- str[0] = '\0';
-
- str_pt += sprintf(str_pt, "Layers%%t|");
-
- mesh_layers_menu_concat(data, type, str_pt);
-
- ret = pupmenu(str);
- MEM_freeN(str);
- return ret;
-}
-
-static void EM_mesh_copy_edge(EditMesh *em, short type)
-{
- EditSelection *ese;
- short change=0;
-
- EditEdge *eed, *eed_act;
- float vec[3], vec_mid[3], eed_len, eed_len_act;
-
- if (!em) return;
-
- ese = em->selected.last;
- if (!ese) return;
-
- eed_act = (EditEdge*)ese->data;
-
- switch (type) {
- case 1: /* copy crease */
- for(eed=em->edges.first; eed; eed=eed->next) {
- if (eed->f & SELECT && eed != eed_act && eed->crease != eed_act->crease) {
- eed->crease = eed_act->crease;
- change = 1;
- }
- }
- break;
- case 2: /* copy bevel weight */
- for(eed=em->edges.first; eed; eed=eed->next) {
- if (eed->f & SELECT && eed != eed_act && eed->bweight != eed_act->bweight) {
- eed->bweight = eed_act->bweight;
- change = 1;
- }
- }
- break;
-
- case 3: /* copy length */
- eed_len_act = len_v3v3(eed_act->v1->co, eed_act->v2->co);
- for(eed=em->edges.first; eed; eed=eed->next) {
- if (eed->f & SELECT && eed != eed_act) {
-
- eed_len = len_v3v3(eed->v1->co, eed->v2->co);
-
- if (eed_len == eed_len_act) continue;
- /* if this edge is zero length we cont do anything with it*/
- if (eed_len == 0.0f) continue;
- if (eed_len_act == 0.0f) {
- add_v3_v3v3(vec_mid, eed->v1->co, eed->v2->co);
- mul_v3_fl(vec_mid, 0.5);
- VECCOPY(eed->v1->co, vec_mid);
- VECCOPY(eed->v2->co, vec_mid);
- } else {
- /* copy the edge length */
- add_v3_v3v3(vec_mid, eed->v1->co, eed->v2->co);
- mul_v3_fl(vec_mid, 0.5);
-
- /* SCALE 1 */
- sub_v3_v3v3(vec, eed->v1->co, vec_mid);
- mul_v3_fl(vec, eed_len_act/eed_len);
- add_v3_v3v3(eed->v1->co, vec, vec_mid);
-
- /* SCALE 2 */
- sub_v3_v3v3(vec, eed->v2->co, vec_mid);
- mul_v3_fl(vec, eed_len_act/eed_len);
- add_v3_v3v3(eed->v2->co, vec, vec_mid);
- }
- change = 1;
- }
- }
-
- if (change)
- recalc_editnormals(em);
-
- break;
- }
-
- if (change) {
-// DAG_id_tag_update(obedit->data, 0);
-
- }
-}
-
-static void EM_mesh_copy_face(EditMesh *em, wmOperator *op, short type)
-{
- short change=0;
-
- EditFace *efa, *efa_act;
- MTFace *tf, *tf_act = NULL;
- MCol *mcol, *mcol_act = NULL;
- if (!em) return;
- efa_act = EM_get_actFace(em, 0);
-
- if (!efa_act) return;
-
- tf_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MTFACE);
- mcol_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MCOL);
-
- switch (type) {
- case 1: /* copy material */
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT && efa->mat_nr != efa_act->mat_nr) {
- efa->mat_nr = efa_act->mat_nr;
- change = 1;
- }
- }
- break;
- case 2: /* copy image */
- if (!tf_act) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
- return;
- }
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT && efa != efa_act) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if (tf_act->tpage) {
- tf->tpage = tf_act->tpage;
- tf->mode |= TF_TEX;
- } else {
- tf->tpage = NULL;
- tf->mode &= ~TF_TEX;
- }
- tf->tile= tf_act->tile;
- change = 1;
- }
- }
- break;
-
- case 3: /* copy UV's */
- if (!tf_act) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
- return;
- }
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT && efa != efa_act) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- memcpy(tf->uv, tf_act->uv, sizeof(tf->uv));
- change = 1;
- }
- }
- break;
- case 4: /* mode's */
- if (!tf_act) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
- return;
- }
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT && efa != efa_act) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- tf->mode= tf_act->mode;
- change = 1;
- }
- }
- break;
- case 5: /* copy transp's */
- if (!tf_act) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
- return;
- }
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT && efa != efa_act) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- tf->transp= tf_act->transp;
- change = 1;
- }
- }
- break;
-
- case 6: /* copy vcols's */
- if (!mcol_act) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers.");
- return;
- } else {
- /* guess the 4th color if needs be */
- float val =- 1;
-
- if (!efa_act->v4) {
- /* guess the othe vale, we may need to use it
- *
- * Modifying the 4th value of the mcol is ok here since its not seen
- * on a triangle
- * */
- val = ((float)(mcol_act->r + (mcol_act+1)->r + (mcol_act+2)->r)) / 3; CLAMP(val, 0, 255);
- (mcol_act+3)->r = (char)val;
-
- val = ((float)(mcol_act->g + (mcol_act+1)->g + (mcol_act+2)->g)) / 3; CLAMP(val, 0, 255);
- (mcol_act+3)->g = (char)val;
-
- val = ((float)(mcol_act->b + (mcol_act+1)->b + (mcol_act+2)->b)) / 3; CLAMP(val, 0, 255);
- (mcol_act+3)->b = (char)val;
- }
-
-
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT && efa != efa_act) {
- /* TODO - make copy from tri to quad guess the 4th vert */
- mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
- memcpy(mcol, mcol_act, sizeof(MCol)*4);
- change = 1;
- }
- }
- }
- break;
- }
-
- if (change) {
-// DAG_id_tag_update(obedit->data, 0);
-
- }
-}
-
-
-void EM_mesh_copy_face_layer(EditMesh *em, wmOperator *op, short type)
-{
- short change=0;
-
- EditFace *efa;
- MTFace *tf, *tf_from;
- MCol *mcol, *mcol_from;
-
- if (!em) return;
-
- switch(type) {
- case 7:
- case 8:
- case 9:
- if (CustomData_number_of_layers(&em->fdata, CD_MTFACE)<2) {
- BKE_report(op->reports, RPT_WARNING, "mesh does not have multiple uv/image layers");
- return;
- } else {
- int layer_orig_idx, layer_idx;
-
- layer_idx = mesh_layers_menu(&em->fdata, CD_MTFACE);
- if (layer_idx<0) return;
-
- /* warning, have not updated mesh pointers however this is not needed since we swicth back */
- layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MTFACE);
- if (layer_idx==layer_orig_idx)
- return;
-
- /* get the tfaces */
- CustomData_set_layer_active(&em->fdata, CD_MTFACE, (int)layer_idx);
- /* store the tfaces in our temp */
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- }
- }
- CustomData_set_layer_active(&em->fdata, CD_MTFACE, layer_orig_idx);
- }
- break;
-
- case 10: /* select vcol layers - make sure this stays in sync with above code */
- if (CustomData_number_of_layers(&em->fdata, CD_MCOL)<2) {
- BKE_report(op->reports, RPT_WARNING, "mesh does not have multiple color layers");
- return;
- } else {
- int layer_orig_idx, layer_idx;
-
- layer_idx = mesh_layers_menu(&em->fdata, CD_MCOL);
- if (layer_idx<0) return;
-
- /* warning, have not updated mesh pointers however this is not needed since we swicth back */
- layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MCOL);
- if (layer_idx==layer_orig_idx)
- return;
-
- /* get the tfaces */
- CustomData_set_layer_active(&em->fdata, CD_MCOL, (int)layer_idx);
- /* store the tfaces in our temp */
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
- }
- }
- CustomData_set_layer_active(&em->fdata, CD_MCOL, layer_orig_idx);
-
- }
- break;
- }
-
- /* layer copy only - sanity checks done above */
- switch (type) {
- case 7: /* copy UV's only */
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- memcpy(tf->uv, tf_from->uv, sizeof(tf->uv));
- change = 1;
- }
- }
- break;
- case 8: /* copy image settings only */
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if (tf_from->tpage) {
- tf->tpage = tf_from->tpage;
- tf->mode |= TF_TEX;
- } else {
- tf->tpage = NULL;
- tf->mode &= ~TF_TEX;
- }
- tf->tile= tf_from->tile;
- change = 1;
- }
- }
- break;
- case 9: /* copy all tface info */
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- memcpy(tf->uv, ((MTFace *)efa->tmp.p)->uv, sizeof(tf->uv));
- tf->tpage = tf_from->tpage;
- tf->mode = tf_from->mode;
- tf->transp = tf_from->transp;
- change = 1;
- }
- }
- break;
- case 10:
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- mcol_from = (MCol *)efa->tmp.p;
- mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
- memcpy(mcol, mcol_from, sizeof(MCol)*4);
- change = 1;
- }
- }
- break;
- }
-
- if (change) {
-// DAG_id_tag_update(obedit->data, 0);
-
- }
-}
-
-
-/* ctrl+c in mesh editmode */
-static void mesh_copy_menu(EditMesh *em, wmOperator *op)
-{
- EditSelection *ese;
- int ret;
- if (!em) return;
-
- ese = em->selected.last;
-
- /* Faces can have a NULL ese, so dont return on a NULL ese here */
-
- if(ese && ese->type == EDITVERT) {
- /* EditVert *ev, *ev_act = (EditVert*)ese->data;
- ret= pupmenu(""); */
- } else if(ese && ese->type == EDITEDGE) {
- ret= pupmenu("Copy Active Edge to Selected%t|Crease%x1|Bevel Weight%x2|Length%x3");
- if (ret<1) return;
-
- EM_mesh_copy_edge(em, ret);
-
- } else if(ese==NULL || ese->type == EDITFACE) {
- ret= pupmenu(
- "Copy Face Selected%t|"
- "Active Material%x1|Active Image%x2|Active UV Coords%x3|"
- "Active Mode%x4|Active Transp%x5|Active Vertex Colors%x6|%l|"
-
- "TexFace UVs from layer%x7|"
- "TexFace Images from layer%x8|"
- "TexFace All from layer%x9|"
- "Vertex Colors from layer%x10");
- if (ret<1) return;
-
- if (ret<=6) {
- EM_mesh_copy_face(em, op, ret);
- } else {
- EM_mesh_copy_face_layer(em, op, ret);
- }
- }
-}
-
-/* **************** LOOP SELECTS *************** */
-
-/* selects quads in loop direction of indicated edge */
-/* only flush over edges with valence <= 2 */
-void faceloop_select(EditMesh *em, EditEdge *startedge, int select)
-{
- EditEdge *eed;
- EditFace *efa;
- int looking= 1;
-
- /* in eed->f1 we put the valence (amount of faces in edge) */
- /* in eed->f2 we put tagged flag as correct loop */
- /* in efa->f1 we put tagged flag as correct to select */
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0;
- eed->f2= 0;
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->f1= 0;
- if(efa->h==0) {
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4) efa->e4->f1++;
- }
- }
-
- /* tag startedge OK*/
- startedge->f2= 1;
-
- while(looking) {
- looking= 0;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0 && efa->e4 && efa->f1==0) { /* not done quad */
- if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
-
- /* if edge tagged, select opposing edge and mark face ok */
- if(efa->e1->f2) {
- efa->e3->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- else if(efa->e2->f2) {
- efa->e4->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e3->f2) {
- efa->e1->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e4->f2) {
- efa->e2->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- }
- }
- }
- }
-
- /* (de)select the faces */
- if(select!=2) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f1) EM_select_face(efa, select);
- }
- }
-}
-
-
-/* helper for edgeloop_select, checks for eed->f2 tag in faces */
-static int edge_not_in_tagged_face(EditMesh *em, EditEdge *eed)
-{
- EditFace *efa;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- if(efa->e1==eed || efa->e2==eed || efa->e3==eed || efa->e4==eed) { /* edge is in face */
- if(efa->e1->f2 || efa->e2->f2 || efa->e3->f2 || (efa->e4 && efa->e4->f2)) { /* face is tagged */
- return 0;
- }
- }
- }
- }
- return 1;
-}
-
-/* selects or deselects edges that:
-- if edges has 2 faces:
- - has vertices with valence of 4
- - not shares face with previous edge
-- if edge has 1 face:
- - has vertices with valence 4
- - not shares face with previous edge
- - but also only 1 face
-- if edge no face:
- - has vertices with valence 2
-*/
-static void edgeloop_select(EditMesh *em, EditEdge *starteed, int select)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
- int looking= 1;
-
- /* in f1 we put the valence (amount of edges in a vertex, or faces in edge) */
- /* in eed->f2 and efa->f1 we put tagged flag as correct loop */
- for(eve= em->verts.first; eve; eve= eve->next) {
- eve->f1= 0;
- eve->f2= 0;
- }
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0;
- eed->f2= 0;
- if((eed->h & 1)==0) { /* fgon edges add to valence too */
- eed->v1->f1++; eed->v2->f1++;
- }
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->f1= 0;
- if(efa->h==0) {
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4) efa->e4->f1++;
- }
- }
-
- /* looped edges & vertices get tagged f2 */
- starteed->f2= 1;
- if(starteed->v1->f1<5) starteed->v1->f2= 1;
- if(starteed->v2->f1<5) starteed->v2->f2= 1;
- /* sorry, first edge isnt even ok */
- if(starteed->v1->f2==0 && starteed->v2->f2==0) looking= 0;
-
- while(looking) {
- looking= 0;
-
- /* find correct valence edges which are not tagged yet, but connect to tagged one */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0 && eed->f2==0) { /* edge not hidden, not tagged */
- if( (eed->v1->f1<5 && eed->v1->f2) || (eed->v2->f1<5 && eed->v2->f2)) { /* valence of vertex OK, and is tagged */
- /* new edge is not allowed to be in face with tagged edge */
- if(edge_not_in_tagged_face(em, eed)) {
- if(eed->f1==starteed->f1) { /* same amount of faces */
- looking= 1;
- eed->f2= 1;
- if(eed->v2->f1<5) eed->v2->f2= 1;
- if(eed->v1->f1<5) eed->v1->f2= 1;
- }
- }
- }
- }
- }
- }
- /* and we do the select */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f2) EM_select_edge(eed, select);
- }
-}
-
-/*
- Almostly exactly the same code as faceloop select
-*/
-static void edgering_select(EditMesh *em, EditEdge *startedge, int select)
-{
- EditEdge *eed;
- EditFace *efa;
- int looking= 1;
-
- /* in eed->f1 we put the valence (amount of faces in edge) */
- /* in eed->f2 we put tagged flag as correct loop */
- /* in efa->f1 we put tagged flag as correct to select */
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0;
- eed->f2= 0;
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->f1= 0;
- if(efa->h==0) {
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4) efa->e4->f1++;
- }
- }
-
- /* tag startedge OK */
- startedge->f2= 1;
-
- while(looking) {
- looking= 0;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->e4 && efa->f1==0 && !efa->h) { /* not done quad */
- if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
-
- /* if edge tagged, select opposing edge and mark face ok */
- if(efa->e1->f2) {
- efa->e3->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- else if(efa->e2->f2) {
- efa->e4->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e3->f2) {
- efa->e1->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e4->f2) {
- efa->e2->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- }
- }
- }
- }
-
- /* (de)select the edges */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f2) EM_select_edge(eed, select);
- }
-}
-
-static int loop_multiselect(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- EditEdge *eed;
- EditEdge **edarray;
- int edindex, edfirstcount;
- int looptype= RNA_boolean_get(op->ptr, "ring");
-
- /* sets em->totedgesel */
- EM_nedges_selected(em);
-
- edarray = MEM_mallocN(sizeof(EditEdge*)*em->totedgesel,"edge array");
- edindex = 0;
- edfirstcount = em->totedgesel;
-
- for(eed=em->edges.first; eed; eed=eed->next){
- if(eed->f&SELECT){
- edarray[edindex] = eed;
- edindex += 1;
- }
- }
-
- if(looptype){
- for(edindex = 0; edindex < edfirstcount; edindex +=1){
- eed = edarray[edindex];
- edgering_select(em, eed,SELECT);
- }
- EM_selectmode_flush(em);
- }
- else{
- for(edindex = 0; edindex < edfirstcount; edindex +=1){
- eed = edarray[edindex];
- edgeloop_select(em, eed,SELECT);
- }
- EM_selectmode_flush(em);
- }
- MEM_freeN(edarray);
-// if (EM_texFaceCheck())
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_loop_multi_select(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Multi Select Loops";
- ot->description= "Select a loop of connected edges by connection type";
- ot->idname= "MESH_OT_loop_multi_select";
-
- /* api callbacks */
- ot->exec= loop_multiselect;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
-}
-
-
-/* ***************** MAIN MOUSE SELECTION ************** */
-
-
-/* ***************** loop select (non modal) ************** */
-
-static void mouse_mesh_loop(bContext *C, short mval[2], short extend, short ring)
-{
- ViewContext vc;
- EditMesh *em;
- EditEdge *eed;
- int select= 1;
- int dist= 50;
-
- em_setup_viewcontext(C, &vc);
- vc.mval[0]= mval[0];
- vc.mval[1]= mval[1];
- em= vc.em;
-
- /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
- view3d_validate_backbuf(&vc);
-
- eed= findnearestedge(&vc, &dist);
- if(eed) {
- if(extend==0) EM_clear_flag_all(em, SELECT);
-
- if((eed->f & SELECT)==0) select=1;
- else if(extend) select=0;
-
- if(em->selectmode & SCE_SELECT_FACE) {
- faceloop_select(em, eed, select);
- }
- else if(em->selectmode & SCE_SELECT_EDGE) {
- if(ring)
- edgering_select(em, eed, select);
- else
- edgeloop_select(em, eed, select);
- }
- else if(em->selectmode & SCE_SELECT_VERTEX) {
- if(ring)
- edgering_select(em, eed, select);
- else
- edgeloop_select(em, eed, select);
- }
-
- EM_selectmode_flush(em);
-// if (EM_texFaceCheck())
-
- /* sets as active, useful for other tools */
- if(select) {
- if(em->selectmode & SCE_SELECT_VERTEX)
- EM_store_selection(em, eed->v1, EDITVERT);
- if(em->selectmode & SCE_SELECT_EDGE)
- EM_store_selection(em, eed, EDITEDGE);
- }
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
- }
-}
-
-static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
-
- view3d_operator_needs_opengl(C);
-
- mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
- RNA_boolean_get(op->ptr, "ring"));
-
- /* cannot do tweaks for as long this keymap is after transform map */
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_loop_select(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Loop Select";
- ot->description= "Select a loop of connected edges";
- ot->idname= "MESH_OT_loop_select";
-
- /* api callbacks */
- ot->invoke= mesh_select_loop_invoke;
- ot->poll= ED_operator_editmesh_region_view3d;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
- RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "");
-}
-
-/* ******************* mesh shortest path select, uses prev-selected edge ****************** */
-
-/* since you want to create paths with multiple selects, it doesn't have extend option */
-static void mouse_mesh_shortest_path(bContext *C, short mval[2])
-{
- ViewContext vc;
- EditMesh *em;
- EditEdge *eed, *eed_act= NULL;
- int dist= 50;
-
- em_setup_viewcontext(C, &vc);
- vc.mval[0]= mval[0];
- vc.mval[1]= mval[1];
- em= vc.em;
-
- /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
- view3d_validate_backbuf(&vc);
-
- eed= findnearestedge(&vc, &dist);
- if(eed) {
- Mesh *me= vc.obedit->data;
- int path = 0;
-
- if (em->selected.last) {
- EditSelection *ese = em->selected.last;
-
- if(ese && ese->type == EDITEDGE) {
- eed_act = (EditEdge*)ese->data;
- if (eed_act != eed) {
- if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) { /* <- this is where the magic happens */
- EM_remove_selection(em, eed_act, EDITEDGE);
- path = 1;
- }
- }
- }
- }
- if (path==0) {
- int act = (edgetag_context_check(vc.scene, eed)==0);
- edgetag_context_set(vc.scene, eed, act); /* switch the edge option */
- }
-
- /* even if this is selected it may not be in the selection list */
- if(edgetag_context_check(vc.scene, eed)==0) {
- EM_remove_selection(em, eed, EDITEDGE);
- }
- else {
- /* other modes need to keep the last edge tagged */
- if(eed_act) {
- if(vc.scene->toolsettings->edge_mode!=EDGE_MODE_SELECT) {
- /* for non-select modes, always de-select the previous active edge */
- EM_select_edge(eed_act, 0);
- }
- }
-
- /* set the new edge active */
- EM_select_edge(eed, 1);
- EM_store_selection(em, eed, EDITEDGE);
- }
-
- EM_selectmode_flush(em);
-
- /* force drawmode for mesh */
- switch (vc.scene->toolsettings->edge_mode) {
-
- case EDGE_MODE_TAG_SEAM:
- me->drawflag |= ME_DRAWSEAMS;
- break;
- case EDGE_MODE_TAG_SHARP:
- me->drawflag |= ME_DRAWSHARP;
- break;
- case EDGE_MODE_TAG_CREASE:
- me->drawflag |= ME_DRAWCREASES;
- break;
- case EDGE_MODE_TAG_BEVEL:
- me->drawflag |= ME_DRAWBWEIGHTS;
- break;
- }
-
- DAG_id_tag_update(vc.obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
- }
-}
-
-
-static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
-{
-
- view3d_operator_needs_opengl(C);
-
- mouse_mesh_shortest_path(C, event->mval);
-
- return OPERATOR_FINISHED;
-}
-
-static int mesh_shortest_path_select_poll(bContext *C)
-{
- if(ED_operator_editmesh_region_view3d(C)) {
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
- return (em->selectmode & SCE_SELECT_EDGE);
- }
- return 0;
-}
-
-void MESH_OT_select_shortest_path(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Shortest Path Select";
- ot->description= "Select shortest path between two selections";
- ot->idname= "MESH_OT_select_shortest_path";
-
- /* api callbacks */
- ot->invoke= mesh_shortest_path_select_invoke;
- ot->poll= mesh_shortest_path_select_poll;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
-}
-
-
-/* ************************************************** */
-
-
-/* here actual select happens */
-/* gets called via generic mouse select operator */
-int mouse_mesh(bContext *C, short mval[2], short extend)
-{
- ViewContext vc;
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- /* setup view context for argument to callbacks */
- em_setup_viewcontext(C, &vc);
- vc.mval[0]= mval[0];
- vc.mval[1]= mval[1];
-
- if(unified_findnearest(&vc, &eve, &eed, &efa)) {
-
- if(extend==0) EM_clear_flag_all(vc.em, SELECT);
-
- if(efa) {
- /* set the last selected face */
- EM_set_actFace(vc.em, efa);
-
- if( (efa->f & SELECT)==0 ) {
- EM_store_selection(vc.em, efa, EDITFACE);
- EM_select_face_fgon(vc.em, efa, 1);
- }
- else if(extend) {
- EM_remove_selection(vc.em, efa, EDITFACE);
- EM_select_face_fgon(vc.em, efa, 0);
- }
- }
- else if(eed) {
- if((eed->f & SELECT)==0) {
- EM_store_selection(vc.em, eed, EDITEDGE);
- EM_select_edge(eed, 1);
- }
- else if(extend) {
- EM_remove_selection(vc.em, eed, EDITEDGE);
- EM_select_edge(eed, 0);
- }
- }
- else if(eve) {
- if((eve->f & SELECT)==0) {
- eve->f |= SELECT;
- EM_store_selection(vc.em, eve, EDITVERT);
- }
- else if(extend){
- EM_remove_selection(vc.em, eve, EDITVERT);
- eve->f &= ~SELECT;
- }
- }
-
- EM_selectmode_flush(vc.em);
-
-// if (EM_texFaceCheck()) {
-
- if (efa && efa->mat_nr != vc.obedit->actcol-1) {
- vc.obedit->actcol= efa->mat_nr+1;
- vc.em->mat_nr= efa->mat_nr;
-// BIF_preview_changed(ID_MA);
- }
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
-
- return 1;
- }
-
- return 0;
-}
-
-/* *********** select linked ************* */
-
-/* for use with selectconnected_delimit_mesh only! */
-#define is_edge_delimit_ok(eed) ((eed->tmp.l == 1) && (eed->seam==0))
-#define is_face_tag(efa) is_edge_delimit_ok(efa->e1) || is_edge_delimit_ok(efa->e2) || is_edge_delimit_ok(efa->e3) || (efa->v4 && is_edge_delimit_ok(efa->e4))
-
-#define face_tag(efa)\
-if(efa->v4) efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;\
-else efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
-
-/* all - 1) use all faces for extending the selection 2) only use the mouse face
-* sel - 1) select 0) deselect
-* */
-
-/* legacy warning, this function combines too much :) */
-static int select_linked_limited_invoke(ViewContext *vc, short all, short sel)
-{
- EditMesh *em= vc->em;
- EditFace *efa;
- EditEdge *eed;
- EditVert *eve;
- short done=1, change=0;
-
- if(em->faces.first==0) return OPERATOR_CANCELLED;
-
- /* flag all edges+faces as off*/
- for(eed= em->edges.first; eed; eed= eed->next)
- eed->tmp.l=0;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->tmp.l = 0;
- }
-
- if (all) {
- // XXX verts?
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT)
- eed->tmp.l= 1;
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
-
- if (efa->f & SELECT) {
- face_tag(efa);
- } else {
- efa->tmp.l = 0;
- }
- }
- }
- else {
- if( unified_findnearest(vc, &eve, &eed, &efa) ) {
-
- if(efa) {
- efa->tmp.l = 1;
- face_tag(efa);
- }
- else if(eed)
- eed->tmp.l= 1;
- else {
- for(eed= em->edges.first; eed; eed= eed->next)
- if(eed->v1==eve || eed->v2==eve)
- break;
- eed->tmp.l= 1;
- }
- }
- else
- return OPERATOR_FINISHED;
- }
-
- while(done==1) {
- done= 0;
- /* simple algo - select all faces that have a selected edge
- * this intern selects the edge, repeat until nothing is left to do */
- for(efa= em->faces.first; efa; efa= efa->next) {
- if ((efa->tmp.l == 0) && (!efa->h)) {
- if (is_face_tag(efa)) {
- face_tag(efa);
- done= 1;
- }
- }
- }
- }
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (efa->tmp.l) {
- if (sel) {
- if (!(efa->f & SELECT)) {
- EM_select_face(efa, 1);
- change = 1;
- }
- } else {
- if (efa->f & SELECT) {
- EM_select_face(efa, 0);
- change = 1;
- }
- }
- }
- }
-
- if (!change)
- return OPERATOR_CANCELLED;
-
- if (!sel) /* make sure de-selecting faces didnt de-select the verts/edges connected to selected faces, this is common with boundries */
- for(efa= em->faces.first; efa; efa= efa->next)
- if (efa->f & SELECT)
- EM_select_face(efa, 1);
-
- // if (EM_texFaceCheck())
-
- return OPERATOR_FINISHED;
-}
-
-#undef is_edge_delimit_ok
-#undef is_face_tag
-#undef face_tag
-
-static void linked_limit_default(bContext *C, wmOperator *op) {
- if(!RNA_property_is_set(op->ptr, "limit")) {
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
- if(em->selectmode == SCE_SELECT_FACE)
- RNA_boolean_set(op->ptr, "limit", TRUE);
- }
-}
-
-static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
- Object *obedit= CTX_data_edit_object(C);
- ViewContext vc;
- EditVert *eve, *v1, *v2;
- EditEdge *eed;
- EditFace *efa;
- short done=1, toggle=0;
- int sel= !RNA_boolean_get(op->ptr, "deselect");
- int limit;
-
- linked_limit_default(C, op);
-
- limit = RNA_boolean_get(op->ptr, "limit");
-
- /* unified_finednearest needs ogl */
- view3d_operator_needs_opengl(C);
-
- /* setup view context for argument to callbacks */
- em_setup_viewcontext(C, &vc);
-
- if(vc.em->edges.first==0) return OPERATOR_CANCELLED;
-
- vc.mval[0]= event->mval[0];
- vc.mval[1]= event->mval[1];
-
- /* return warning! */
- if(limit) {
- int retval= select_linked_limited_invoke(&vc, 0, sel);
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- return retval;
- }
-
- if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- return OPERATOR_CANCELLED;
- }
-
- /* clear test flags */
- for(v1= vc.em->verts.first; v1; v1= v1->next) v1->f1= 0;
-
- /* start vertex/face/edge */
- if(eve) eve->f1= 1;
- else if(eed) eed->v1->f1= eed->v2->f1= 1;
- else efa->v1->f1= efa->v2->f1= efa->v3->f1= 1;
-
- /* set flag f1 if affected */
- while(done==1) {
- done= 0;
- toggle++;
-
- if(toggle & 1) eed= vc.em->edges.first;
- else eed= vc.em->edges.last;
-
- while(eed) {
- v1= eed->v1;
- v2= eed->v2;
-
- if(eed->h==0) {
- if(v1->f1 && v2->f1==0) {
- v2->f1= 1;
- done= 1;
- }
- else if(v1->f1==0 && v2->f1) {
- v1->f1= 1;
- done= 1;
- }
- }
-
- if(toggle & 1) eed= eed->next;
- else eed= eed->prev;
- }
- }
-
- /* now use vertex f1 flag to select/deselect */
- for(eed= vc.em->edges.first; eed; eed= eed->next) {
- if(eed->v1->f1 && eed->v2->f1)
- EM_select_edge(eed, sel);
- }
- for(efa= vc.em->faces.first; efa; efa= efa->next) {
- if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1))
- EM_select_face(efa, sel);
- }
- /* no flush needed, connected geometry is done */
-
-// if (EM_texFaceCheck())
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_linked_pick(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Linked";
- ot->description= "(un)select all vertices linked to the active mesh";
- ot->idname= "MESH_OT_select_linked_pick";
-
- /* api callbacks */
- ot->invoke= select_linked_pick_invoke;
- ot->poll= ED_operator_editmesh_region_view3d;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
- RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "Limit selection by seam boundries (faces only)");
-}
-
-
-/* ************************* */
-
-void selectconnected_mesh_all(EditMesh *em)
-{
- EditVert *v1,*v2;
- EditEdge *eed;
- short done=1, toggle=0;
-
- if(em->edges.first==0) return;
-
- while(done==1) {
- done= 0;
-
- toggle++;
- if(toggle & 1) eed= em->edges.first;
- else eed= em->edges.last;
-
- while(eed) {
- v1= eed->v1;
- v2= eed->v2;
- if(eed->h==0) {
- if(v1->f & SELECT) {
- if( (v2->f & SELECT)==0 ) {
- v2->f |= SELECT;
- done= 1;
- }
- }
- else if(v2->f & SELECT) {
- if( (v1->f & SELECT)==0 ) {
- v1->f |= SELECT;
- done= 1;
- }
- }
- }
- if(toggle & 1) eed= eed->next;
- else eed= eed->prev;
- }
- }
-
- /* now use vertex select flag to select rest */
- EM_select_flush(em);
-
- // if (EM_texFaceCheck())
-}
-
-static int select_linked_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
-
- if( RNA_boolean_get(op->ptr, "limit") ) {
- ViewContext vc;
- em_setup_viewcontext(C, &vc);
- select_linked_limited_invoke(&vc, 1, 1);
- }
- else
- selectconnected_mesh_all(em);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
-{
- linked_limit_default(C, op);
- return select_linked_exec(C, op);
-}
-
-void MESH_OT_select_linked(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Linked All";
- ot->description= "Select all vertices linked to the active mesh";
- ot->idname= "MESH_OT_select_linked";
-
- /* api callbacks */
- ot->exec= select_linked_exec;
- ot->invoke= select_linked_invoke;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "Limit selection by seam boundries (faces only)");
-}
-
-
-/* ************************* */
-
-/* swap is 0 or 1, if 1 it hides not selected */
-void EM_hide_mesh(EditMesh *em, int swap)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
- int a;
-
- if(em==NULL) return;
-
- /* hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
- /* - vertex hidden, always means edge is hidden too
- - edge hidden, always means face is hidden too
- - face hidden, only set face hide
- - then only flush back down what's absolute hidden
- */
- if(em->selectmode & SCE_SELECT_VERTEX) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if((eve->f & SELECT)!=swap) {
- eve->f &= ~SELECT;
- eve->h= 1;
- }
- }
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->v1->h || eed->v2->h) {
- eed->h |= 1;
- eed->f &= ~SELECT;
- }
- }
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
- efa->h= 1;
- efa->f &= ~SELECT;
- }
- }
- }
- else if(em->selectmode & SCE_SELECT_EDGE) {
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if((eed->f & SELECT)!=swap) {
- eed->h |= 1;
- EM_select_edge(eed, 0);
- }
- }
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
- efa->h= 1;
- efa->f &= ~SELECT;
- }
- }
- }
- else {
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if((efa->f & SELECT)!=swap) {
- efa->h= 1;
- EM_select_face(efa, 0);
- }
- }
- }
-
- /* flush down, only whats 100% hidden */
- for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
- for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
-
- if(em->selectmode & SCE_SELECT_FACE) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h) a= 1; else a= 2;
- efa->e1->f1 |= a;
- efa->e2->f1 |= a;
- efa->e3->f1 |= a;
- if(efa->e4) efa->e4->f1 |= a;
- /* When edges are not delt with in their own loop, we need to explicitly re-selct select edges that are joined to unselected faces */
- if (swap && (em->selectmode == SCE_SELECT_FACE) && (efa->f & SELECT)) {
- EM_select_face(efa, 1);
- }
- }
- }
-
- if(em->selectmode >= SCE_SELECT_EDGE) {
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f1==1) eed->h |= 1;
- if(eed->h & 1) a= 1; else a= 2;
- eed->v1->f1 |= a;
- eed->v2->f1 |= a;
- }
- }
-
- if(em->selectmode >= SCE_SELECT_VERTEX) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f1==1) eve->h= 1;
- }
- }
-
- em->totedgesel= em->totfacesel= em->totvertsel= 0;
-// if(EM_texFaceCheck())
-
- // DAG_id_tag_update(obedit->data, 0);
-}
-
-static int hide_mesh_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- EM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_hide(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Hide Selection";
- ot->description= "Hide (un)selected vertices, edges or faces";
- ot->idname= "MESH_OT_hide";
-
- /* api callbacks */
- ot->exec= hide_mesh_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
-}
-
-void EM_reveal_mesh(EditMesh *em)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- if(em==NULL) return;
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->h) {
- eve->h= 0;
- eve->f |= SELECT;
- }
- }
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h & 1) {
- eed->h &= ~1;
- if(em->selectmode & SCE_SELECT_VERTEX);
- else EM_select_edge(eed, 1);
- }
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h) {
- efa->h= 0;
- if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX));
- else EM_select_face(efa, 1);
- }
- }
-
- EM_fgon_flags(em); /* redo flags and indices for fgons */
- EM_selectmode_flush(em);
-
-// if (EM_texFaceCheck())
-// DAG_id_tag_update(obedit->data, 0);
-}
-
-static int reveal_mesh_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- EM_reveal_mesh(em);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_reveal(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Reveal Hidden";
- ot->description= "Reveal all hidden vertices, edges and faces";
- ot->idname= "MESH_OT_reveal";
-
- /* api callbacks */
- ot->exec= reveal_mesh_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static int select_by_number_vertices_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- EditFace *efa;
- int numverts= RNA_enum_get(op->ptr, "type");
-
- /* Selects trias/qiads or isolated verts, and edges that do not have 2 neighboring
- * faces
- */
-
- /* for loose vertices/edges, we first select all, loop below will deselect */
- if(numverts==5) {
- EM_set_flag_all(em, SELECT);
- }
- else if(em->selectmode!=SCE_SELECT_FACE) {
- BKE_report(op->reports, RPT_WARNING, "Only works in face selection mode");
- return OPERATOR_CANCELLED;
- }
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (efa->e4) {
- EM_select_face(efa, (numverts==4) );
- }
- else {
- EM_select_face(efa, (numverts==3) );
- }
- }
-
- EM_selectmode_flush(em);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_by_number_vertices(wmOperatorType *ot)
-{
- static const EnumPropertyItem type_items[]= {
- {3, "TRIANGLES", 0, "Triangles", NULL},
- {4, "QUADS", 0, "Quads", NULL},
- {5, "OTHER", 0, "Other", NULL},
- {0, NULL, 0, NULL, NULL}};
-
- /* identifiers */
- ot->name= "Select by Number of Vertices";
- ot->description= "Select vertices or faces by vertex count";
- ot->idname= "MESH_OT_select_by_number_vertices";
-
- /* api callbacks */
- ot->exec= select_by_number_vertices_exec;
- ot->invoke= WM_menu_invoke;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- ot->prop= RNA_def_enum(ot->srna, "type", type_items, 3, "Type", "Type of elements to select.");
-}
-
-
-static int select_mirror_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- int extend= RNA_boolean_get(op->ptr, "extend");
-
- EM_select_mirrored(obedit, em, extend);
- EM_selectmode_flush(em);
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_mirror(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Mirror";
- ot->description= "Select mesh items at mirrored locations";
- ot->idname= "MESH_OT_select_mirror";
-
- /* api callbacks */
- ot->exec= select_mirror_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
-}
-
-static int select_sharp_edges_exec(bContext *C, wmOperator *op)
-{
- /* Find edges that have exactly two neighboring faces,
- * check the angle between those faces, and if angle is
- * small enough, select the edge
- */
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- EditEdge *eed;
- EditFace *efa;
- EditFace **efa1;
- EditFace **efa2;
- intptr_t edgecount = 0, i = 0;
- float sharpness, fsharpness;
-
- /* 'standard' behaviour - check if selected, then apply relevant selection */
-
- if(em->selectmode==SCE_SELECT_FACE) {
- BKE_report(op->reports, RPT_WARNING, "Doesn't work in face selection mode");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- sharpness= RNA_float_get(op->ptr, "sharpness");
- fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
-
- /* count edges, use tmp.l */
- eed= em->edges.first;
- while(eed) {
- edgecount++;
- eed->tmp.l = i;
- eed= eed->next;
- ++i;
- }
-
- /* for each edge, we want a pointer to two adjacent faces */
- efa1 = MEM_callocN(edgecount*sizeof(EditFace *),
- "pairs of edit face pointers");
- efa2 = MEM_callocN(edgecount*sizeof(EditFace *),
- "pairs of edit face pointers");
-
-#define face_table_edge(eed) { \
- i = eed->tmp.l; \
- if (i != -1) { \
- if (efa1[i]) { \
- if (efa2[i]) { \
- /* invalidate, edge has more than two neighbors */ \
- eed->tmp.l = -1; \
- } \
- else { \
- efa2[i] = efa; \
- } \
- } \
- else { \
- efa1[i] = efa; \
- } \
- } \
- }
-
- /* find the adjacent faces of each edge, we want only two */
- efa= em->faces.first;
- while(efa) {
- face_table_edge(efa->e1);
- face_table_edge(efa->e2);
- face_table_edge(efa->e3);
- if (efa->e4) {
- face_table_edge(efa->e4);
- }
- efa= efa->next;
- }
-
-#undef face_table_edge
-
- eed = em->edges.first;
- while(eed) {
- i = eed->tmp.l;
- if (i != -1) {
- /* edge has two or less neighboring faces */
- if ( (efa1[i]) && (efa2[i]) ) {
- /* edge has exactly two neighboring faces, check angle */
- float angle;
- angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
- efa1[i]->n[1]*efa2[i]->n[1] +
- efa1[i]->n[2]*efa2[i]->n[2]);
- if (fabs(angle) >= fsharpness)
- EM_select_edge(eed, 1);
- }
- }
-
- eed= eed->next;
- }
-
- MEM_freeN(efa1);
- MEM_freeN(efa2);
-
-// if (EM_texFaceCheck())
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); //TODO is this needed ?
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_edges_select_sharp(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Sharp Edges";
- ot->description= "Marked selected edges as sharp";
- ot->idname= "MESH_OT_edges_select_sharp";
-
- /* api callbacks */
- ot->exec= select_sharp_edges_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_float(ot->srna, "sharpness", 0.01f, 0.0f, FLT_MAX, "sharpness", "", 0.0f, 180.0f);
-}
-
-
-static void select_linked_flat_faces(EditMesh *em, wmOperator *op, float sharpness)
-{
- /* Find faces that are linked to selected faces that are
- * relatively flat (angle between faces is higher than
- * specified angle)
- */
- EditEdge *eed;
- EditFace *efa;
- EditFace **efa1;
- EditFace **efa2;
- intptr_t edgecount = 0, i, faceselcount=0, faceselcountold=0;
- float fsharpness;
-
- if(em->selectmode!=SCE_SELECT_FACE) {
- BKE_report(op->reports, RPT_WARNING, "Only works in face selection mode");
- return;
- }
-
- fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
-
- i=0;
- /* count edges, use tmp.l */
- eed= em->edges.first;
- while(eed) {
- edgecount++;
- eed->tmp.l = i;
- eed= eed->next;
- ++i;
- }
-
- /* for each edge, we want a pointer to two adjacent faces */
- efa1 = MEM_callocN(edgecount*sizeof(EditFace *),
- "pairs of edit face pointers");
- efa2 = MEM_callocN(edgecount*sizeof(EditFace *),
- "pairs of edit face pointers");
-
-#define face_table_edge(eed) { \
- i = eed->tmp.l; \
- if (i != -1) { \
- if (efa1[i]) { \
- if (efa2[i]) { \
- /* invalidate, edge has more than two neighbors */ \
- eed->tmp.l = -1; \
- } \
- else { \
- efa2[i] = efa; \
- } \
- } \
- else { \
- efa1[i] = efa; \
- } \
- } \
- }
-
- /* find the adjacent faces of each edge, we want only two */
- efa= em->faces.first;
- while(efa) {
- face_table_edge(efa->e1);
- face_table_edge(efa->e2);
- face_table_edge(efa->e3);
- if (efa->e4) {
- face_table_edge(efa->e4);
- }
-
- /* while were at it, count the selected faces */
- if (efa->f & SELECT) ++faceselcount;
-
- efa= efa->next;
- }
-
-#undef face_table_edge
-
- eed= em->edges.first;
- while(eed) {
- i = eed->tmp.l;
- if (i != -1) {
- /* edge has two or less neighboring faces */
- if ( (efa1[i]) && (efa2[i]) ) {
- /* edge has exactly two neighboring faces, check angle */
- float angle;
- angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
- efa1[i]->n[1]*efa2[i]->n[1] +
- efa1[i]->n[2]*efa2[i]->n[2]);
- /* invalidate: edge too sharp */
- if (fabs(angle) >= fsharpness)
- eed->tmp.l = -1;
- }
- else {
- /* invalidate: less than two neighbors */
- eed->tmp.l = -1;
- }
- }
-
- eed= eed->next;
- }
-
-#define select_flat_neighbor(eed) { \
- i = eed->tmp.l; \
- if (i!=-1) { \
- if (! (efa1[i]->f & SELECT) ) { \
- EM_select_face(efa1[i], 1); \
- ++faceselcount; \
- } \
- if (! (efa2[i]->f & SELECT) ) { \
- EM_select_face(efa2[i], 1); \
- ++faceselcount; \
- } \
- } \
- }
-
- while (faceselcount != faceselcountold) {
- faceselcountold = faceselcount;
-
- efa= em->faces.first;
- while(efa) {
- if (efa->f & SELECT) {
- select_flat_neighbor(efa->e1);
- select_flat_neighbor(efa->e2);
- select_flat_neighbor(efa->e3);
- if (efa->e4) {
- select_flat_neighbor(efa->e4);
- }
- }
- efa= efa->next;
- }
- }
-
-#undef select_flat_neighbor
-
- MEM_freeN(efa1);
- MEM_freeN(efa2);
-
-// if (EM_texFaceCheck())
-
-}
-
-static int select_linked_flat_faces_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- select_linked_flat_faces(em, op, RNA_float_get(op->ptr, "sharpness"));
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_faces_select_linked_flat(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Linked Flat Faces";
- ot->description= "Select linked faces by angle";
- ot->idname= "MESH_OT_faces_select_linked_flat";
-
- /* api callbacks */
- ot->exec= select_linked_flat_faces_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_float(ot->srna, "sharpness", 135.0f, 0.0f, FLT_MAX, "sharpness", "", 0.0f, 180.0f);
-}
-
-static void select_non_manifold(EditMesh *em, wmOperator *op )
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- /* Selects isolated verts, and edges that do not have 2 neighboring
- * faces
- */
-
- if(em->selectmode==SCE_SELECT_FACE) {
- BKE_report(op->reports, RPT_WARNING, "Doesn't work in face selection mode");
- return;
- }
-
- eve= em->verts.first;
- while(eve) {
- /* this will count how many edges are connected
- * to this vert */
- eve->f1= 0;
- eve= eve->next;
- }
-
- eed= em->edges.first;
- while(eed) {
- /* this will count how many faces are connected to
- * this edge */
- eed->f1= 0;
- /* increase edge count for verts */
- ++eed->v1->f1;
- ++eed->v2->f1;
- eed= eed->next;
- }
-
- efa= em->faces.first;
- while(efa) {
- /* increase face count for edges */
- ++efa->e1->f1;
- ++efa->e2->f1;
- ++efa->e3->f1;
- if (efa->e4)
- ++efa->e4->f1;
- efa= efa->next;
- }
-
- /* select verts that are attached to an edge that does not
- * have 2 neighboring faces */
- eed= em->edges.first;
- while(eed) {
- if (eed->h==0 && eed->f1 != 2) {
- EM_select_edge(eed, 1);
- }
- eed= eed->next;
- }
-
- /* select isolated verts */
- if(em->selectmode & SCE_SELECT_VERTEX) {
- eve= em->verts.first;
- while(eve) {
- if (eve->f1 == 0) {
- if (!eve->h) eve->f |= SELECT;
- }
- eve= eve->next;
- }
- }
-
-// if (EM_texFaceCheck())
-
-}
-
-static int select_non_manifold_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- select_non_manifold(em, op);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_non_manifold(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Non Manifold";
- ot->description= "Select all non-manifold vertices or edges";
- ot->idname= "MESH_OT_select_non_manifold";
-
- /* api callbacks */
- ot->exec= select_non_manifold_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-void EM_select_swap(EditMesh *em) /* exported for UV */
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- if(em->selectmode & SCE_SELECT_VERTEX) {
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->h==0) {
- if(eve->f & SELECT) eve->f &= ~SELECT;
- else eve->f|= SELECT;
- }
- }
- }
- else if(em->selectmode & SCE_SELECT_EDGE) {
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0) {
- EM_select_edge(eed, !(eed->f & SELECT));
- }
- }
- }
- else {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- EM_select_face(efa, !(efa->f & SELECT));
- }
- }
- }
-
- EM_selectmode_flush(em);
-
-// if (EM_texFaceCheck())
-
-}
-
-static int select_inverse_mesh_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- EM_select_swap(em);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_inverse(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Inverse";
- ot->description= "Select inverse of (un)selected vertices, edges or faces";
- ot->idname= "MESH_OT_select_inverse";
-
- /* api callbacks */
- ot->exec= select_inverse_mesh_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-/* ******************** (de)select all operator **************** */
-
-void EM_toggle_select_all(EditMesh *em) /* exported for UV */
-{
- if(EM_nvertices_selected(em))
- EM_clear_flag_all(em, SELECT);
- else
- EM_set_flag_all_selectmode(em, SELECT);
-}
-
-void EM_select_all(EditMesh *em)
-{
- EM_set_flag_all_selectmode(em, SELECT);
-}
-
-void EM_deselect_all(EditMesh *em)
-{
- EM_clear_flag_all(em, SELECT);
-}
-
-static int select_all_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- int action = RNA_enum_get(op->ptr, "action");
-
- switch (action) {
- case SEL_TOGGLE:
- EM_toggle_select_all(em);
- break;
- case SEL_SELECT:
- EM_select_all(em);
- break;
- case SEL_DESELECT:
- EM_deselect_all(em);
- break;
- case SEL_INVERT:
- EM_select_swap(em);
- break;
- }
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select or Deselect All";
- ot->description= "Change selection of all vertices, edges or faces";
- ot->idname= "MESH_OT_select_all";
-
- /* api callbacks */
- ot->exec= select_all_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- WM_operator_properties_select_all(ot);
-}
-
-/* ******************** **************** */
-
-void EM_select_more(EditMesh *em)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) eve->f1= 1;
- else eve->f1 = 0;
- }
-
- /* set f1 flags in vertices to select 'more' */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0) {
- if (eed->v1->f & SELECT)
- eed->v2->f1 = 1;
- if (eed->v2->f & SELECT)
- eed->v1->f1 = 1;
- }
- }
-
- /* new selected edges, but not in facemode */
- if(em->selectmode <= SCE_SELECT_EDGE) {
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0) {
- if(eed->v1->f1 && eed->v2->f1) EM_select_edge(eed, 1);
- }
- }
- }
- /* new selected faces */
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1))
- EM_select_face(efa, 1);
- }
- }
-}
-
-static int select_more(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)) ;
-
- EM_select_more(em);
-
-// if (EM_texFaceCheck(em))
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_more(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select More";
- ot->description= "Select more vertices, edges or faces connected to initial selection";
- ot->idname= "MESH_OT_select_more";
-
- /* api callbacks */
- ot->exec= select_more;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static void EM_select_less(EditMesh *em)
-{
- EditEdge *eed;
- EditFace *efa;
-
- if(em->selectmode <= SCE_SELECT_EDGE) {
- /* eed->f1 == 1: edge with a selected and deselected vert */
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0;
- if(eed->h==0) {
-
- if ( !(eed->v1->f & SELECT) && (eed->v2->f & SELECT) )
- eed->f1= 1;
- if ( (eed->v1->f & SELECT) && !(eed->v2->f & SELECT) )
- eed->f1= 1;
- }
- }
-
- /* deselect edges with flag set */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (eed->h==0 && eed->f1 == 1) {
- EM_select_edge(eed, 0);
- }
- }
- EM_deselect_flush(em);
-
- }
- else {
- /* deselect faces with 1 or more deselect edges */
- /* eed->f1 == mixed selection edge */
- for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- if(efa->f & SELECT) {
- efa->e1->f1 |= 1;
- efa->e2->f1 |= 1;
- efa->e3->f1 |= 1;
- if(efa->e4) efa->e4->f1 |= 1;
- }
- else {
- efa->e1->f1 |= 2;
- efa->e2->f1 |= 2;
- efa->e3->f1 |= 2;
- if(efa->e4) efa->e4->f1 |= 2;
- }
- }
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- if(efa->e1->f1==3 || efa->e2->f1==3 || efa->e3->f1==3 || (efa->e4 && efa->e4->f1==3)) {
- EM_select_face(efa, 0);
- }
- }
- }
- EM_selectmode_flush(em);
-
- }
-}
-
-static int select_less(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- EM_select_less(em);
-
-// if (EM_texFaceCheck(em))
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_less(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Less";
- ot->description= "Select less vertices, edges or faces connected to initial selection";
- ot->idname= "MESH_OT_select_less";
-
- /* api callbacks */
- ot->exec= select_less;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static void selectrandom_mesh(EditMesh *em, float randfac) /* randomly selects a user-set % of vertices/edges/faces */
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- BLI_srand( BLI_rand() ); /* random seed */
-
- if(em->selectmode & SCE_SELECT_VERTEX) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->h==0) {
- if (BLI_frand() < randfac)
- eve->f |= SELECT;
- }
- }
- EM_selectmode_flush(em);
- }
- else if(em->selectmode & SCE_SELECT_EDGE) {
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0) {
- if (BLI_frand() < randfac)
- EM_select_edge(eed, 1);
- }
- }
- EM_selectmode_flush(em);
- }
- else {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- if (BLI_frand() < randfac)
- EM_select_face(efa, 1);
- }
- }
-
- EM_selectmode_flush(em);
- }
-// if (EM_texFaceCheck())
-}
-
-static int mesh_select_random_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- if(!RNA_boolean_get(op->ptr, "extend"))
- EM_deselect_all(em);
-
- selectrandom_mesh(em, RNA_float_get(op->ptr, "percent")/100.0f);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_random(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Random";
- ot->description= "Randomly select vertices";
- ot->idname= "MESH_OT_select_random";
-
- /* api callbacks */
- ot->exec= mesh_select_random_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* 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 Selection", "Extend selection instead of deselecting everything first.");
-}
-
-void EM_select_by_material(EditMesh *em, int index)
-{
- EditFace *efa;
-
- for (efa=em->faces.first; efa; efa= efa->next) {
- if (efa->mat_nr==index) {
- EM_select_face(efa, 1);
- }
- }
-
- EM_selectmode_flush(em);
-}
-
-void EM_deselect_by_material(EditMesh *em, int index)
-{
- EditFace *efa;
-
- for (efa=em->faces.first; efa; efa= efa->next) {
- if (efa->mat_nr==index) {
- EM_select_face(efa, 0);
- }
- }
-
- EM_selectmode_flush(em);
-}
-
-/* ************************* SEAMS AND EDGES **************** */
-
-static int editmesh_mark_seam(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- Mesh *me= ((Mesh *)obedit->data);
- EditEdge *eed;
- int clear = RNA_boolean_get(op->ptr, "clear");
-
- /* auto-enable seams drawing */
- if(clear==0) {
- me->drawflag |= ME_DRAWSEAMS;
- }
-
- if(clear) {
- eed= em->edges.first;
- while(eed) {
- if((eed->h==0) && (eed->f & SELECT)) {
- eed->seam = 0;
- }
- eed= eed->next;
- }
- }
- else {
- eed= em->edges.first;
- while(eed) {
- if((eed->h==0) && (eed->f & SELECT)) {
- eed->seam = 1;
- }
- eed= eed->next;
- }
- }
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_mark_seam(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Mark Seam";
- ot->description= "(un)mark selected edges as a seam";
- ot->idname= "MESH_OT_mark_seam";
-
- /* api callbacks */
- ot->exec= editmesh_mark_seam;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
-}
-
-static int editmesh_mark_sharp(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- Mesh *me= ((Mesh *)obedit->data);
- int clear = RNA_boolean_get(op->ptr, "clear");
- EditEdge *eed;
-
- /* auto-enable sharp edge drawing */
- if(clear == 0) {
- me->drawflag |= ME_DRAWSHARP;
- }
-
- if(!clear) {
- eed= em->edges.first;
- while(eed) {
- if(!eed->h && (eed->f & SELECT)) eed->sharp = 1;
- eed = eed->next;
- }
- } else {
- eed= em->edges.first;
- while(eed) {
- if(!eed->h && (eed->f & SELECT)) eed->sharp = 0;
- eed = eed->next;
- }
- }
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_mark_sharp(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Mark Sharp";
- ot->description= "(un)mark selected edges as sharp";
- ot->idname= "MESH_OT_mark_sharp";
-
- /* api callbacks */
- ot->exec= editmesh_mark_sharp;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
-}
-
-/* **************** NORMALS ************** */
-
-void EM_recalc_normal_direction(EditMesh *em, int inside, int select) /* makes faces righthand turning */
-{
- EditEdge *eed, *ed1, *ed2, *ed3, *ed4;
- EditFace *efa, *startvl;
- float maxx, nor[3], cent[3];
- int totsel, found, foundone, direct, turn, tria_nr;
-
- /* based at a select-connected to witness loose objects */
-
- /* count per edge the amount of faces */
-
- /* find the ultimate left, front, upper face (not manhattan dist!!) */
- /* also evaluate both triangle cases in quad, since these can be non-flat */
-
- /* put normal to the outside, and set the first direction flags in edges */
-
- /* then check the object, and set directions / direction-flags: but only for edges with 1 or 2 faces */
- /* this is in fact the 'select connected' */
-
- /* in case (selected) faces were not done: start over with 'find the ultimate ...' */
-
- waitcursor(1);
-
- eed= em->edges.first;
- while(eed) {
- eed->f2= 0; /* edge direction */
- eed->f1= 0; /* counter */
- eed= eed->next;
- }
-
- /* count faces and edges */
- totsel= 0;
- efa= em->faces.first;
- while(efa) {
- if(select==0 || (efa->f & SELECT) ) {
- efa->f1= 1;
- totsel++;
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->v4) efa->e4->f1++;
- }
- else efa->f1= 0;
-
- efa= efa->next;
- }
-
- while(totsel>0) {
- /* from the outside to the inside */
-
- efa= em->faces.first;
- startvl= NULL;
- maxx= -1.0e10;
- tria_nr= 0;
-
- while(efa) {
- if(efa->f1) {
- cent_tri_v3(cent, efa->v1->co, efa->v2->co, efa->v3->co);
- cent[0]= cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2];
-
- if(cent[0]>maxx) {
- maxx= cent[0];
- startvl= efa;
- tria_nr= 0;
- }
- if(efa->v4) {
- cent_tri_v3(cent, efa->v1->co, efa->v3->co, efa->v4->co);
- cent[0]= cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2];
-
- if(cent[0]>maxx) {
- maxx= cent[0];
- startvl= efa;
- tria_nr= 1;
- }
- }
- }
- efa= efa->next;
- }
-
- if (startvl==NULL)
- startvl= em->faces.first;
-
- /* set first face correct: calc normal */
-
- if(tria_nr==1) {
- normal_tri_v3( nor,startvl->v1->co, startvl->v3->co, startvl->v4->co);
- cent_tri_v3(cent, startvl->v1->co, startvl->v3->co, startvl->v4->co);
- } else {
- normal_tri_v3( nor,startvl->v1->co, startvl->v2->co, startvl->v3->co);
- cent_tri_v3(cent, startvl->v1->co, startvl->v2->co, startvl->v3->co);
- }
- /* first normal is oriented this way or the other */
- if(inside) {
- if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] > 0.0) flipface(em, startvl);
- }
- else {
- if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0) flipface(em, startvl);
- }
-
- eed= startvl->e1;
- if(eed->v1==startvl->v1) eed->f2= 1;
- else eed->f2= 2;
-
- eed= startvl->e2;
- if(eed->v1==startvl->v2) eed->f2= 1;
- else eed->f2= 2;
-
- eed= startvl->e3;
- if(eed->v1==startvl->v3) eed->f2= 1;
- else eed->f2= 2;
-
- eed= startvl->e4;
- if(eed) {
- if(eed->v1==startvl->v4) eed->f2= 1;
- else eed->f2= 2;
- }
-
- startvl->f1= 0;
- totsel--;
-
- /* test normals */
- found= 1;
- direct= 1;
- while(found) {
- found= 0;
- if(direct) efa= em->faces.first;
- else efa= em->faces.last;
- while(efa) {
- if(efa->f1) {
- turn= 0;
- foundone= 0;
-
- ed1= efa->e1;
- ed2= efa->e2;
- ed3= efa->e3;
- ed4= efa->e4;
-
- if(ed1->f2) {
- if(ed1->v1==efa->v1 && ed1->f2==1) turn= 1;
- if(ed1->v2==efa->v1 && ed1->f2==2) turn= 1;
- foundone= 1;
- }
- else if(ed2->f2) {
- if(ed2->v1==efa->v2 && ed2->f2==1) turn= 1;
- if(ed2->v2==efa->v2 && ed2->f2==2) turn= 1;
- foundone= 1;
- }
- else if(ed3->f2) {
- if(ed3->v1==efa->v3 && ed3->f2==1) turn= 1;
- if(ed3->v2==efa->v3 && ed3->f2==2) turn= 1;
- foundone= 1;
- }
- else if(ed4 && ed4->f2) {
- if(ed4->v1==efa->v4 && ed4->f2==1) turn= 1;
- if(ed4->v2==efa->v4 && ed4->f2==2) turn= 1;
- foundone= 1;
- }
-
- if(foundone) {
- found= 1;
- totsel--;
- efa->f1= 0;
-
- if(turn) {
- if(ed1->v1==efa->v1) ed1->f2= 2;
- else ed1->f2= 1;
- if(ed2->v1==efa->v2) ed2->f2= 2;
- else ed2->f2= 1;
- if(ed3->v1==efa->v3) ed3->f2= 2;
- else ed3->f2= 1;
- if(ed4) {
- if(ed4->v1==efa->v4) ed4->f2= 2;
- else ed4->f2= 1;
- }
-
- flipface(em, efa);
-
- }
- else {
- if(ed1->v1== efa->v1) ed1->f2= 1;
- else ed1->f2= 2;
- if(ed2->v1==efa->v2) ed2->f2= 1;
- else ed2->f2= 2;
- if(ed3->v1==efa->v3) ed3->f2= 1;
- else ed3->f2= 2;
- if(ed4) {
- if(ed4->v1==efa->v4) ed4->f2= 1;
- else ed4->f2= 2;
- }
- }
- }
- }
- if(direct) efa= efa->next;
- else efa= efa->prev;
- }
- direct= 1-direct;
- }
- }
-
- recalc_editnormals(em);
-
-// DAG_id_tag_update(obedit->data, 0);
-
- waitcursor(0);
-}
-
-
-static int normals_make_consistent_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- /* 'standard' behaviour - check if selected, then apply relevant selection */
-
- // XXX need other args
- EM_recalc_normal_direction(em, RNA_boolean_get(op->ptr, "inside"), 1);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); //TODO is this needed ?
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_normals_make_consistent(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Make Normals Consistent";
- ot->description= "Flip all selected vertex and face normals in a consistent direction";
- ot->idname= "MESH_OT_normals_make_consistent";
-
- /* api callbacks */
- ot->exec= normals_make_consistent_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
-}
-
-/* **************** VERTEX DEFORMS *************** */
-
-static int smooth_vertex(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- EditVert *eve, *eve_mir = NULL;
- EditEdge *eed;
- float *adror, *adr, fac;
- float fvec[3];
- int teller=0;
- ModifierData *md;
- int index;
-
- /* count */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & SELECT) teller++;
- eve= eve->next;
- }
- if(teller==0) {
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- adr=adror= (float *)MEM_callocN(3*sizeof(float *)*teller, "vertsmooth");
- eve= em->verts.first;
- while(eve) {
- if(eve->f & SELECT) {
- eve->tmp.p = (void*)adr;
- eve->f1= 0;
- eve->f2= 0;
- adr+= 3;
- }
- eve= eve->next;
- }
-
- /* if there is a mirror modifier with clipping, flag the verts that
- * are within tolerance of the plane(s) of reflection
- */
- for(md=obedit->modifiers.first; md; md=md->next) {
- if(md->type==eModifierType_Mirror) {
- MirrorModifierData *mmd = (MirrorModifierData*) md;
-
- if(mmd->flag & MOD_MIR_CLIPPING) {
- for (eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
-
- switch(mmd->axis){
- case 0:
- if (fabs(eve->co[0]) < mmd->tolerance)
- eve->f2 |= 1;
- break;
- case 1:
- if (fabs(eve->co[1]) < mmd->tolerance)
- eve->f2 |= 2;
- break;
- case 2:
- if (fabs(eve->co[2]) < mmd->tolerance)
- eve->f2 |= 4;
- break;
- }
- }
- }
- }
- }
- }
-
- eed= em->edges.first;
- while(eed) {
- if( (eed->v1->f & SELECT) || (eed->v2->f & SELECT) ) {
- fvec[0]= (eed->v1->co[0]+eed->v2->co[0])/2.0;
- fvec[1]= (eed->v1->co[1]+eed->v2->co[1])/2.0;
- fvec[2]= (eed->v1->co[2]+eed->v2->co[2])/2.0;
-
- if((eed->v1->f & SELECT) && eed->v1->f1<255) {
- eed->v1->f1++;
- add_v3_v3(eed->v1->tmp.p, fvec);
- }
- if((eed->v2->f & SELECT) && eed->v2->f1<255) {
- eed->v2->f1++;
- add_v3_v3(eed->v2->tmp.p, fvec);
- }
- }
- eed= eed->next;
- }
-
- index= 0;
- eve= em->verts.first;
- while(eve) {
- if(eve->f & SELECT) {
- if(eve->f1) {
-
- int xaxis= RNA_boolean_get(op->ptr, "xaxis");
- int yaxis= RNA_boolean_get(op->ptr, "yaxis");
- int zaxis= RNA_boolean_get(op->ptr, "zaxis");
-
- if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
- eve_mir= editmesh_get_x_mirror_vert(obedit, em, eve, eve->co, index);
- }
-
- adr = eve->tmp.p;
- fac= 0.5/(float)eve->f1;
-
- if(xaxis)
- eve->co[0]= 0.5*eve->co[0]+fac*adr[0];
- if(yaxis)
- eve->co[1]= 0.5*eve->co[1]+fac*adr[1];
- if(zaxis)
- eve->co[2]= 0.5*eve->co[2]+fac*adr[2];
-
-
- /* clip if needed by mirror modifier */
- if (eve->f2) {
- if (eve->f2 & 1) {
- eve->co[0]= 0.0f;
- }
- if (eve->f2 & 2) {
- eve->co[1]= 0.0f;
- }
- if (eve->f2 & 4) {
- eve->co[2]= 0.0f;
- }
- }
-
- if (eve_mir) {
- eve_mir->co[0]=-eve->co[0];
- eve_mir->co[1]= eve->co[1];
- eve_mir->co[2]= eve->co[2];
- }
-
- }
- eve->tmp.p= NULL;
- }
- index++;
- eve= eve->next;
- }
- MEM_freeN(adror);
-
- recalc_editnormals(em);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-static int smooth_vertex_exec(bContext *C, wmOperator *op)
-{
- int repeat = RNA_int_get(op->ptr, "repeat");
- int i;
-
- if (!repeat) repeat = 1;
-
- for (i=0; i<repeat; i++) {
- smooth_vertex(C, op);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_vertices_smooth(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Smooth Vertex";
- ot->description= "Flatten angles of selected vertices";
- ot->idname= "MESH_OT_vertices_smooth";
-
- /* api callbacks */
- ot->exec= smooth_vertex_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Smooth Iterations", "", 1, INT_MAX);
- RNA_def_boolean(ot->srna, "xaxis", 1, "X-Axis", "Smooth along the X axis.");
- RNA_def_boolean(ot->srna, "yaxis", 1, "Y-Axis", "Smooth along the Y axis.");
- RNA_def_boolean(ot->srna, "zaxis", 1, "Z-Axis", "Smooth along the Z axis.");
-}
-
-static int mesh_noise_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- Material *ma;
- Tex *tex;
- EditVert *eve;
- float fac= RNA_float_get(op->ptr, "factor");
-
- if(em==NULL) return OPERATOR_FINISHED;
-
- ma= give_current_material(obedit, obedit->actcol);
- if(ma==0 || ma->mtex[0]==0 || ma->mtex[0]->tex==0) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no material or texture assigned.");
- return OPERATOR_FINISHED;
- }
- tex= give_current_material_texture(ma);
-
-
- if(tex->type==TEX_STUCCI) {
- float b2, vec[3];
- float ofs= tex->turbul/200.0;
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
- b2= BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]);
- if(tex->stype) ofs*=(b2*b2);
- vec[0]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0]+ofs, eve->co[1], eve->co[2]));
- vec[1]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1]+ofs, eve->co[2]));
- vec[2]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]+ofs));
-
- add_v3_v3(eve->co, vec);
- }
- }
- }
- else {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
- float tin, dum;
- externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0);
- eve->co[2]+= fac*tin;
- }
- }
- }
-
- recalc_editnormals(em);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_noise(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Noise";
- ot->description= "Use vertex coordinate as texture coordinate";
- ot->idname= "MESH_OT_noise";
-
- /* api callbacks */
- ot->exec= mesh_noise_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_float(ot->srna, "factor", 0.1f, -FLT_MAX, FLT_MAX, "Factor", "", 0.0f, 1.0f);
-}
-
-void flipface(EditMesh *em, EditFace *efa)
-{
- if(efa->v4) {
- SWAP(EditVert *, efa->v2, efa->v4);
- SWAP(EditEdge *, efa->e1, efa->e4);
- SWAP(EditEdge *, efa->e2, efa->e3);
- EM_data_interp_from_faces(em, efa, NULL, efa, 0, 3, 2, 1);
- }
- else {
- SWAP(EditVert *, efa->v2, efa->v3);
- SWAP(EditEdge *, efa->e1, efa->e3);
- efa->e2->dir= 1-efa->e2->dir;
- EM_data_interp_from_faces(em, efa, NULL, efa, 0, 2, 1, 3);
- }
-
- if(efa->v4) normal_quad_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- else normal_tri_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co);
-}
-
-
-static int flip_normals(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- EditFace *efa;
-
- efa= em->faces.first;
- while(efa) {
- if( efa->f & SELECT ){
- flipface(em, efa);
- }
- efa= efa->next;
- }
-
- /* update vertex normals too */
- recalc_editnormals(em);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_flip_normals(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Flip Normals";
- ot->description= "Toggle the direction of selected face's vertex and face normals";
- ot->idname= "MESH_OT_flip_normals";
-
- /* api callbacks */
- ot->exec= flip_normals;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-
-static int solidify_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- float nor[3] = {0,0,1};
-
- float thickness= RNA_float_get(op->ptr, "thickness");
-
- extrudeflag(obedit, em, SELECT, nor, 1);
- EM_make_hq_normals(em);
- EM_solidify(em, thickness);
-
-
- /* update vertex normals too */
- recalc_editnormals(em);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-
-void MESH_OT_solidify(wmOperatorType *ot)
-{
- PropertyRNA *prop;
- /* identifiers */
- ot->name= "Solidify";
- ot->description= "Create a solid skin by extruding, compensating for sharp angles";
- ot->idname= "MESH_OT_solidify";
-
- /* api callbacks */
- ot->exec= solidify_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- prop= RNA_def_float(ot->srna, "thickness", 0.01f, -FLT_MAX, FLT_MAX, "Thickness", "", -10.0f, 10.0f);
- RNA_def_property_ui_range(prop, -10, 10, 0.1, 4);
-}
-
-static int mesh_select_nth_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- int nth = RNA_int_get(op->ptr, "nth");
-
- EM_deselect_nth(em, nth);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-
-void MESH_OT_select_nth(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Nth";
- ot->description= "";
- ot->idname= "MESH_OT_select_nth";
-
- /* api callbacks */
- ot->exec= mesh_select_nth_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_int(ot->srna, "nth", 2, 2, 100, "Nth Selection", "", 1, INT_MAX);
-}
-
diff --git a/source/blender/editors/mesh/knifetool.c b/source/blender/editors/mesh/knifetool.c
new file mode 100755
index 00000000000..60910497fad
--- /dev/null
+++ b/source/blender/editors/mesh/knifetool.c
@@ -0,0 +1,1685 @@
+/**
+ * $Id$
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Joseph Eagar, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <float.h>
+#define _USE_MATH_DEFINES
+#include <math.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#include "DNA_ID.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_object_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_dynstr.h" /*for WM_operator_pystring */
+#include "BLI_editVert.h"
+#include "BLI_array.h"
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+#include "BLI_mempool.h"
+#include "BLI_math.h"
+#include "BLI_kdopbvh.h"
+#include "BLI_smallhash.h"
+
+#include "BKE_blender.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_scene.h"
+#include "BKE_mesh.h"
+#include "BKE_tessmesh.h"
+#include "BKE_depsgraph.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h" /* for paint cursor */
+
+#include "IMB_imbuf_types.h"
+
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_view3d.h"
+#include "ED_mesh.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "mesh_intern.h"
+#include "editbmesh_bvh.h"
+
+#define MAXGROUP 30
+
+/* knifetool operator */
+typedef struct KnifeVert {
+ BMVert *v; /*non-NULL if this is an original vert*/
+ ListBase edges;
+
+ float co[3], sco[3]; /*sco is screen coordinates*/
+ short flag, draw, isface;
+} KnifeVert;
+
+typedef struct Ref {
+ struct Ref *next, *prev;
+ void *ref;
+} Ref;
+
+typedef struct KnifeEdge {
+ KnifeVert *v1, *v2;
+ BMFace *basef; /*face to restrict face fill to*/
+ ListBase faces;
+ int draw;
+
+ BMEdge *e, *oe; /*non-NULL if this is an original edge*/
+} KnifeEdge;
+
+#define KMAXDIST 12 /*max mouse distance from edge before not detecting it*/
+#define MARK 4
+#define DEL 8
+
+typedef struct BMEdgeHit {
+ KnifeEdge *kfe;
+ float hit[3];
+ float shit[3];
+ float l; /*lambda along line*/
+ BMVert *v; //set if snapped to a vert
+ BMFace *f;
+} BMEdgeHit;
+
+/* struct for properties used while drawing */
+typedef struct knifetool_opdata {
+ ARegion *ar; /* region that knifetool was activated in */
+ void *draw_handle; /* for drawing preview loop */
+ ViewContext vc;
+ bContext *C;
+
+ Object *ob;
+ BMEditMesh *em;
+
+ MemArena *arena;
+
+ GHash *origvertmap;
+ GHash *origedgemap;
+
+ GHash *kedgefacemap;
+
+ BMBVHTree *bmbvh;
+
+ BLI_mempool *kverts;
+ BLI_mempool *kedges;
+
+ float vthresh;
+ float ethresh;
+
+ float vertco[3];
+ float prevco[3];
+
+ /*used for drag-cutting*/
+ BMEdgeHit *linehits;
+ int totlinehit;
+
+ /*if curedge is NULL, attach to curvert;
+ if curvert is NULL, attach to curbmface,
+ otherwise create null vert*/
+ KnifeEdge *curedge, *prevedge;
+ KnifeVert *curvert, *prevvert;
+ BMFace *curbmface, *prevbmface;
+
+ int totkedge, totkvert, cutnr;
+
+ BLI_mempool *refs;
+
+ float projmat[4][4];
+ int is_ortho, clipsta, clipend;
+
+ enum {
+ MODE_IDLE,
+ MODE_DRAGGING,
+ MODE_CONNECT,
+ } mode;
+} knifetool_opdata;
+
+static ListBase *knife_get_face_kedges(knifetool_opdata *kcd, BMFace *f);
+
+void knife_project_v3(knifetool_opdata *kcd, float co[3], float sco[3])
+{
+ if (kcd->is_ortho) {
+ mul_v3_m4v3(sco, kcd->projmat, co);
+
+ sco[0] = (float)(kcd->ar->winx/2.0f)+(kcd->ar->winx/2.0f)*sco[0];
+ sco[1] = (float)(kcd->ar->winy/2.0f)+(kcd->ar->winy/2.0f)*sco[1];
+ } else
+ view3d_project_float(kcd->ar, co, sco, kcd->projmat);
+}
+
+static KnifeEdge *new_knife_edge(knifetool_opdata *kcd)
+{
+ kcd->totkedge++;
+ return BLI_mempool_calloc(kcd->kedges);
+}
+
+static KnifeVert *new_knife_vert(knifetool_opdata *kcd, float *co)
+{
+ KnifeVert *kfv = BLI_mempool_calloc(kcd->kverts);
+
+ kcd->totkvert++;
+
+ copy_v3_v3(kfv->co, co);
+ copy_v3_v3(kfv->sco, co);
+
+ knife_project_v3(kcd, kfv->co, kfv->sco);
+
+ return kfv;
+}
+
+/*get a KnifeVert wrapper for an existing BMVert*/
+static KnifeVert *get_bm_knife_vert(knifetool_opdata *kcd, BMVert *v)
+{
+ KnifeVert *kfv = BLI_ghash_lookup(kcd->origvertmap, v);
+
+ if (!kfv) {
+ kfv = new_knife_vert(kcd, v->co);
+ kfv->v = v;
+ BLI_ghash_insert(kcd->origvertmap, v, kfv);
+ }
+
+ return kfv;
+}
+
+/*get a KnifeEdge wrapper for an existing BMEdge*/
+static KnifeEdge *get_bm_knife_edge(knifetool_opdata *kcd, BMEdge *e)
+{
+ KnifeEdge *kfe = BLI_ghash_lookup(kcd->origedgemap, e);
+ if (!kfe) {
+ Ref *ref;
+ BMIter iter;
+ BMFace *f;
+
+ kfe = new_knife_edge(kcd);
+ kfe->e = e;
+ kfe->v1 = get_bm_knife_vert(kcd, e->v1);
+ kfe->v2 = get_bm_knife_vert(kcd, e->v2);
+
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = kfe;
+ BLI_addtail(&kfe->v1->edges, ref);
+
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = kfe;
+ BLI_addtail(&kfe->v2->edges, ref);
+
+ BLI_ghash_insert(kcd->origedgemap, e, kfe);
+
+ BM_ITER(f, &iter, kcd->em->bm, BM_FACES_OF_EDGE, e) {
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = f;
+ BLI_addtail(&kfe->faces, ref);
+
+ /*ensures the kedges lst for this f is initialized,
+ it automatically adds kfe by itself*/
+ knife_get_face_kedges(kcd, f);
+ }
+ }
+
+ return kfe;
+}
+
+static void knife_start_cut(knifetool_opdata *kcd)
+{
+ kcd->prevedge = kcd->curedge;
+ kcd->prevvert = kcd->curvert;
+ kcd->prevbmface = kcd->curbmface;
+ kcd->cutnr++;
+
+ copy_v3_v3(kcd->prevco, kcd->vertco);
+}
+
+static Ref *find_ref(ListBase *lb, void *ref)
+{
+ Ref *ref1;
+
+ for (ref1=lb->first; ref1; ref1=ref1->next) {
+ if (ref1->ref == ref)
+ return ref1;
+ }
+
+ return NULL;
+}
+
+static ListBase *knife_get_face_kedges(knifetool_opdata *kcd, BMFace *f)
+{
+ ListBase *lst = BLI_ghash_lookup(kcd->kedgefacemap, f);
+
+ if (!lst) {
+ BMIter iter;
+ BMEdge *e;
+
+ lst = BLI_memarena_alloc(kcd->arena, sizeof(ListBase));
+ lst->first = lst->last = NULL;
+
+ BM_ITER(e, &iter, kcd->em->bm, BM_EDGES_OF_FACE, f) {
+ Ref *ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = get_bm_knife_edge(kcd, e);
+ BLI_addtail(lst, ref);
+ }
+
+ BLI_ghash_insert(kcd->kedgefacemap, f, lst);
+ }
+
+ return lst;
+}
+
+/*finds the proper face to restrict face fill to*/
+void knife_find_basef(knifetool_opdata *kcd, KnifeEdge *kfe)
+{
+ if (!kfe->basef) {
+ Ref *r1, *r2, *r3, *r4;
+
+ if (kfe->v1->isface || kfe->v2->isface) {
+ if (kfe->v2->isface)
+ kfe->basef = kcd->curbmface;
+ else
+ kfe->basef = kcd->prevbmface;
+ } else {
+ for (r1=kfe->v1->edges.first; r1 && !kfe->basef; r1=r1->next) {
+ KnifeEdge *ke1 = r1->ref;
+ for (r2=ke1->faces.first; r2 && !kfe->basef; r2=r2->next) {
+ for (r3=kfe->v2->edges.first; r3 && !kfe->basef; r3=r3->next) {
+ KnifeEdge *ke2 = r3->ref;
+
+ for (r4=ke2->faces.first; r4 && !kfe->basef; r4=r4->next) {
+ if (r2->ref == r4->ref) {
+ kfe->basef = r2->ref;
+ }
+ }
+ }
+ }
+ }
+ }
+ /*ok, at this point kfe->basef should be set if any valid possibility
+ exists*/
+ }
+}
+
+static KnifeVert *knife_split_edge(knifetool_opdata *kcd, KnifeEdge *kfe, float co[3], KnifeEdge **newkfe_out)
+{
+ KnifeEdge *newkfe = new_knife_edge(kcd);
+ ListBase *lst;
+ Ref *ref;
+
+ newkfe->v1 = kfe->v1;
+ newkfe->v2 = new_knife_vert(kcd, co);
+ newkfe->v2->draw = 1;
+ newkfe->basef = kfe->basef;
+
+ ref = find_ref(&kfe->v1->edges, kfe);
+ BLI_remlink(&kfe->v1->edges, ref);
+
+ kfe->v1 = newkfe->v2;
+ BLI_addtail(&kfe->v1->edges, ref);
+
+ for (ref=kfe->faces.first; ref; ref=ref->next) {
+ Ref *ref2 = BLI_mempool_calloc(kcd->refs);
+
+ /*add kedge ref to bm faces*/
+ lst = knife_get_face_kedges(kcd, ref->ref);
+ ref2->ref = newkfe;
+ BLI_addtail(lst, ref2);
+
+ ref2 = BLI_mempool_calloc(kcd->refs);
+ ref2->ref = ref->ref;
+ BLI_addtail(&newkfe->faces, ref2);
+ }
+
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = newkfe;
+ BLI_addtail(&newkfe->v1->edges, ref);
+
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = newkfe;
+ BLI_addtail(&newkfe->v2->edges, ref);
+
+ newkfe->draw = kfe->draw;
+ newkfe->e = kfe->e;
+
+ *newkfe_out = newkfe;
+
+ return newkfe->v2;
+}
+
+static void knife_edge_append_face(knifetool_opdata *kcd, KnifeEdge *kfe, BMFace *f)
+{
+ ListBase *lst = knife_get_face_kedges(kcd, f);
+ Ref *ref = BLI_mempool_calloc(kcd->refs);
+
+ ref->ref = kfe;
+ BLI_addtail(lst, ref);
+
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = f;
+ BLI_addtail(&kfe->faces, ref);
+}
+
+static void knife_copy_edge_facelist(knifetool_opdata *kcd, KnifeEdge *dest, KnifeEdge *source)
+{
+ Ref *ref, *ref2;
+
+ for (ref2 = source->faces.first; ref2; ref2=ref2->next) {
+ ListBase *lst = knife_get_face_kedges(kcd, ref2->ref);
+
+ /*add new edge to face knife edge list*/
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = dest;
+ BLI_addtail(lst, ref);
+
+ /*add face to new edge's face list*/
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = ref2->ref;
+ BLI_addtail(&dest->faces, ref);
+ }
+}
+
+static void knife_add_single_cut(knifetool_opdata *kcd)
+{
+ KnifeEdge *kfe = new_knife_edge(kcd), *kfe2 = NULL, *kfe3 = NULL;
+ Ref *ref;
+
+ if (kcd->prevvert && kcd->prevvert == kcd->curvert)
+ return;
+ if (kcd->prevedge && kcd->prevedge == kcd->curedge)
+ return;
+
+ if (kcd->prevvert) {
+ kfe->v1 = kcd->prevvert;
+ } else if (kcd->prevedge) {
+ kfe->v1 = knife_split_edge(kcd, kcd->prevedge, kcd->prevco, &kfe2);
+ } else {
+ kfe->v1 = new_knife_vert(kcd, kcd->prevco);
+ kfe->v1->draw = 1;
+ kfe->v1->isface = 1;
+ }
+
+ if (kcd->curvert) {
+ kfe->v2 = kcd->curvert;
+ } else if (kcd->curedge) {
+ kfe->v2 = knife_split_edge(kcd, kcd->curedge, kcd->vertco, &kfe3);
+
+ kcd->curvert = kfe->v2;
+ } else {
+ kfe->v2 = new_knife_vert(kcd, kcd->vertco);
+ kfe->v2->draw = 1;
+ kfe->v2->isface = 1;
+
+ kcd->curvert = kfe->v2;
+ }
+
+ knife_find_basef(kcd, kfe);
+
+ kfe->draw = 1;
+
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = kfe;
+ BLI_addtail(&kfe->v1->edges, ref);
+
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = kfe;
+ BLI_addtail(&kfe->v2->edges, ref);
+
+ if (kfe->basef && !find_ref(&kfe->faces, kfe->basef))
+ knife_edge_append_face(kcd, kfe, kfe->basef);
+
+ /*sanity check to make sure we're in the right edge/face lists*/
+ if (kcd->curbmface) {
+ if (!find_ref(&kfe->faces, kcd->curbmface)) {
+ knife_edge_append_face(kcd, kfe, kcd->curbmface);
+ }
+
+ if (kcd->prevbmface && kcd->prevbmface != kcd->curbmface) {
+ if (!find_ref(&kfe->faces, kcd->prevbmface)) {
+ knife_edge_append_face(kcd, kfe, kcd->prevbmface);
+ }
+ }
+ }
+
+ /*set up for next cut*/
+ kcd->prevbmface = kcd->curbmface;
+ kcd->prevvert = kcd->curvert;
+ kcd->prevedge = kcd->curedge;
+ copy_v3_v3(kcd->prevco, kcd->vertco);
+}
+
+static int verge_linehit(const void *vlh1, const void *vlh2)
+{
+ const BMEdgeHit *lh1=vlh1, *lh2=vlh2;
+
+ if (lh1->l < lh2->l) return -1;
+ else if (lh1->l > lh2->l) return 1;
+ else return 0;
+}
+
+static void knife_add_cut(knifetool_opdata *kcd)
+{
+ BMEditMesh *em = kcd->em;
+ BMesh *bm = em->bm;
+ knifetool_opdata oldkcd = *kcd;
+
+ if (kcd->linehits) {
+ BMEdgeHit *lh, *lastlh, *firstlh;
+ int i;
+
+ qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit);
+
+ lh = kcd->linehits;
+ lastlh = firstlh = NULL;
+ for (i=0; i<kcd->totlinehit; i++, (lastlh=lh), lh++) {
+ BMFace *f = lastlh ? lastlh->f : lh->f;
+
+ if (lastlh && len_v3v3(lastlh->hit, lh->hit) == 0.0f) {
+ if (!firstlh)
+ firstlh = lastlh;
+ continue;
+ } else if (lastlh && firstlh) {
+ if (firstlh->v || lastlh->v) {
+ KnifeVert *kfv = firstlh->v ? firstlh->v : lastlh->v;
+
+ kcd->prevvert = kfv;
+ copy_v3_v3(kcd->prevco, firstlh->hit);
+ kcd->prevedge = NULL;
+ kcd->prevbmface = f;
+ }
+ lastlh = firstlh = NULL;
+ }
+
+ if (!lastlh && len_v3v3(kcd->prevco, lh->hit) < FLT_EPSILON*10)
+ continue;
+
+ kcd->curedge = lh->kfe;
+ kcd->curbmface = lh->f;
+ kcd->curvert = lh->v;
+ copy_v3_v3(kcd->vertco, lh->hit);
+
+ knife_add_single_cut(kcd);
+ }
+
+ kcd->curbmface = oldkcd.curbmface;
+ kcd->curvert = oldkcd.curvert;
+ kcd->curedge = oldkcd.curedge;
+ copy_v3_v3(kcd->vertco, oldkcd.vertco);
+
+ knife_add_single_cut(kcd);
+
+ MEM_freeN(kcd->linehits);
+ kcd->linehits = NULL;
+ kcd->totlinehit = 0;
+ } else {
+ knife_add_single_cut(kcd);
+ }
+}
+
+static void knife_finish_cut(knifetool_opdata *kcd)
+{
+
+}
+
+/* modal loop selection drawing callback */
+static void knifetool_draw(const bContext *C, ARegion *ar, void *arg)
+{
+ knifetool_opdata *kcd = arg;
+
+ glDisable(GL_DEPTH_TEST);
+
+ glPushMatrix();
+ glMultMatrixf(kcd->ob->obmat);
+
+ if (kcd->mode == MODE_DRAGGING) {
+ glColor3f(0.1, 0.1, 0.1);
+ glLineWidth(2.0);
+
+ glBegin(GL_LINES);
+ glVertex3fv(kcd->prevco);
+ glVertex3fv(kcd->vertco);
+ glEnd();
+
+ glLineWidth(1.0);
+ }
+
+ if (kcd->curedge) {
+ glColor3f(0.5, 0.3, 0.15);
+ glLineWidth(2.0);
+
+ glBegin(GL_LINES);
+ glVertex3fv(kcd->curedge->v1->co);
+ glVertex3fv(kcd->curedge->v2->co);
+ glEnd();
+
+ glLineWidth(1.0);
+ } else if (kcd->curvert) {
+ glColor3f(0.8, 0.2, 0.1);
+ glPointSize(9);
+
+ glBegin(GL_POINTS);
+ glVertex3fv(kcd->vertco);
+ glEnd();
+ }
+
+ if (kcd->curbmface) {
+ glColor3f(0.1, 0.8, 0.05);
+ glPointSize(7);
+
+ glBegin(GL_POINTS);
+ glVertex3fv(kcd->vertco);
+ glEnd();
+ }
+
+ if (kcd->totlinehit > 0) {
+ BMEdgeHit *lh;
+ int i;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ /*draw any snapped verts first*/
+ glColor4f(0.8, 0.2, 0.1, 0.4);
+ glPointSize(9);
+ glBegin(GL_POINTS);
+ lh = kcd->linehits;
+ for (i=0; i<kcd->totlinehit; i++, lh++) {
+ float sv1[3], sv2[3];
+
+ knife_project_v3(kcd, lh->kfe->v1->co, sv1);
+ knife_project_v3(kcd, lh->kfe->v2->co, sv2);
+
+ if (len_v2v2(lh->shit, sv1) < kcd->vthresh/4) {
+ copy_v3_v3(lh->hit, lh->kfe->v1->co);
+ glVertex3fv(lh->hit);
+ lh->v = lh->kfe->v1;
+ } else if (len_v2v2(lh->shit, sv2) < kcd->vthresh/4) {
+ copy_v3_v3(lh->hit, lh->kfe->v2->co);
+ glVertex3fv(lh->hit);
+ lh->v = lh->kfe->v2;
+ }
+ }
+ glEnd();
+
+ /*now draw the rest*/
+ glColor4f(0.1, 0.8, 0.05, 0.4);
+ glPointSize(5);
+ glBegin(GL_POINTS);
+ lh = kcd->linehits;
+ for (i=0; i<kcd->totlinehit; i++, lh++) {
+ glVertex3fv(lh->hit);
+ }
+ glEnd();
+ glDisable(GL_BLEND);
+ }
+
+ if (kcd->totkedge > 0) {
+ BLI_mempool_iter iter;
+ KnifeEdge *kfe;
+
+ glLineWidth(1.0);
+ glBegin(GL_LINES);
+
+ BLI_mempool_iternew(kcd->kedges, &iter);
+ for (kfe=BLI_mempool_iterstep(&iter); kfe; kfe=BLI_mempool_iterstep(&iter)) {
+ if (!kfe->draw)
+ continue;
+
+ glColor3f(0.2, 0.2, 0.2);
+
+ glVertex3fv(kfe->v1->co);
+ glVertex3fv(kfe->v2->co);
+ }
+
+ glEnd();
+ glLineWidth(1.0);
+ }
+
+ if (kcd->totkvert > 0) {
+ BLI_mempool_iter iter;
+ KnifeVert *kfv;
+
+ glPointSize(4.0);
+
+ glBegin(GL_POINTS);
+ BLI_mempool_iternew(kcd->kverts, &iter);
+ for (kfv=BLI_mempool_iterstep(&iter); kfv; kfv=BLI_mempool_iterstep(&iter)) {
+ if (!kfv->draw)
+ continue;
+
+ glColor3f(0.6, 0.1, 0.2);
+
+ glVertex3fv(kfv->co);
+ }
+
+ glEnd();
+ }
+
+ glPopMatrix();
+ glEnable(GL_DEPTH_TEST);
+}
+
+void _print_smhash(SmallHash *hash)
+{
+ int i, linecol=79, c=0;
+
+ printf("{");
+ for (i=0; i<hash->size; i++) {
+ if (hash->table[i].val == CELL_UNUSED) {
+ printf("--u-");
+ } else if (hash->table[i].val == CELL_FREE) {
+ printf("--f-");
+ } else {
+ printf("%2x", (intptr_t)hash->table[i].key);
+ }
+
+ if (i != hash->size-1)
+ printf(", ");
+
+ c += 6;
+
+ if (c >= linecol) {
+ printf("\n ");
+ c = 0;
+ }
+ }
+
+ fflush(stdout);
+}
+
+BMEdgeHit *knife_edge_tri_isect(knifetool_opdata *kcd, BMBVHTree *bmtree, float v1[3],
+ float v2[3], float v3[3], SmallHash *ehash, bglMats *mats, int *count)
+{
+ BVHTree *tree2 = BLI_bvhtree_new(3, FLT_EPSILON*4, 8, 8), *tree = BMBVH_BVHTree(bmtree);
+ BMEdgeHit *edges = NULL;
+ BLI_array_declare(edges);
+ BVHTreeOverlap *results, *result;
+ BMLoop **ls;
+ float cos[9], uv[3], lambda;
+ int tot=0, i, j;
+
+ copy_v3_v3(cos, v1);
+ copy_v3_v3(cos+3, v2);
+ copy_v3_v3(cos+6, v3);
+
+ BLI_bvhtree_insert(tree2, 0, cos, 3);
+ BLI_bvhtree_balance(tree2);
+
+ result = results = BLI_bvhtree_overlap(tree, tree2, &tot);
+
+ for (i=0; i<tot; i++, result++) {
+ float p[3];
+
+ ls = (BMLoop**)kcd->em->looptris[result->indexA];
+
+ for (j=0; j<3; j++) {
+ BMLoop *l1 = ls[j];
+ ListBase *lst = knife_get_face_kedges(kcd, l1->f);
+ Ref *ref;
+
+ for (ref=lst->first; ref; ref=ref->next) {
+ KnifeEdge *kfe = ref->ref;
+
+ if (isect_line_tri_v3(kfe->v1->co, kfe->v2->co, v1, v2, v3, &lambda, uv)) {
+ float no[3], view[3], sp[3];
+
+ sub_v3_v3v3(p, kfe->v2->co, kfe->v1->co);
+ mul_v3_fl(p, lambda);
+ add_v3_v3(p, kfe->v1->co);
+
+ knife_project_v3(kcd, p, sp);
+ view3d_unproject(mats, view, sp[0], sp[1], 0.0f);
+ mul_m4_v3(kcd->ob->imat, view);
+
+ sub_v3_v3v3(view, p, view);
+ normalize_v3(view);;
+
+ copy_v3_v3(no, view);
+ mul_v3_fl(no, -0.0003);
+
+ /*go backwards toward view a bit*/
+ add_v3_v3(p, no);
+
+ if (!BMBVH_RayCast(bmtree, p, no, NULL) && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
+ BMEdgeHit hit;
+
+ hit.kfe = kfe;
+ hit.v = NULL;
+
+ knife_find_basef(kcd, kfe);
+ hit.f = kfe->basef;
+
+ copy_v3_v3(hit.hit, p);
+ knife_project_v3(kcd, hit.hit, hit.shit);
+
+ BLI_array_append(edges, hit);
+ BLI_smallhash_insert(ehash, (intptr_t)kfe, NULL);
+ }
+ }
+ }
+ }
+ }
+
+ if (results)
+ MEM_freeN(results);
+
+ *count = BLI_array_count(edges);
+ return edges;
+}
+
+void knife_bgl_get_mats(knifetool_opdata *kcd, bglMats *mats)
+{
+ bgl_get_mats(mats);
+ //copy_m4_m4(mats->modelview, kcd->vc.rv3d->viewmat);
+ //copy_m4_m4(mats->projection, kcd->vc.rv3d->winmat);
+}
+
+/*finds (visible) edges that intersects the current screen drag line*/
+static void knife_find_line_hits(knifetool_opdata *kcd)
+{
+ bglMats mats;
+ BMEdgeHit *e1, *e2;
+ SmallHash hash, *ehash = &hash;
+ float v1[3], v2[3], v3[3], v4[4], s1[3], s2[3], view[3];
+ int i, c1, c2;
+
+ knife_bgl_get_mats(kcd, &mats);
+
+ if (kcd->linehits) {
+ MEM_freeN(kcd->linehits);
+ kcd->linehits = NULL;
+ kcd->totlinehit = 0;
+ }
+
+ /*project screen line's 3d coordinates back into 2d*/
+ knife_project_v3(kcd, kcd->prevco, s1);
+ knife_project_v3(kcd, kcd->vertco, s2);
+
+ if (len_v2v2(s1, s2) < 1)
+ return;
+
+ /*unproject screen line*/
+ view3d_unproject(&mats, v1, s1[0], s1[1], 0.0f);
+ view3d_unproject(&mats, v2, s2[0], s2[1], 0.0f);
+ view3d_unproject(&mats, v3, s1[0], s1[1], 1.0f-FLT_EPSILON);
+ view3d_unproject(&mats, v4, s2[0], s2[1], 1.0f-FLT_EPSILON);
+
+ mul_m4_v3(kcd->ob->imat, v1);
+ mul_m4_v3(kcd->ob->imat, v2);
+ mul_m4_v3(kcd->ob->imat, v3);
+ mul_m4_v3(kcd->ob->imat, v4);
+
+ sub_v3_v3v3(view, v4, v1);
+ normalize_v3(view);
+
+ BLI_smallhash_init(ehash);
+
+ /*test two triangles of sceen line's plane*/
+ e1 = knife_edge_tri_isect(kcd, kcd->bmbvh, v1, v2, v3, ehash, &mats, &c1);
+ e2 = knife_edge_tri_isect(kcd, kcd->bmbvh, v1, v3, v4, ehash, &mats, &c2);
+ if (c1 && c2) {
+ e1 = MEM_reallocN(e1, sizeof(BMEdgeHit)*(c1+c2));
+ memcpy(e1+c1, e2, sizeof(BMEdgeHit)*c2);
+ MEM_freeN(e2);
+ } else if (c2) {
+ e1 = e2;
+ }
+
+ kcd->linehits = e1;
+ kcd->totlinehit = c1+c2;
+
+ /*find position along screen line, used for sorting*/
+ for (i=0; i<kcd->totlinehit; i++) {
+ BMEdgeHit *lh = e1+i;
+
+ lh->l = len_v2v2(lh->shit, s1) / len_v2v2(s2, s1);
+ }
+
+ BLI_smallhash_release(ehash);
+}
+
+static BMFace *knife_find_closest_face(knifetool_opdata *kcd, float co[3])
+{
+ BMFace *f;
+ bglMats mats;
+ float origin[3], ray[3];
+ float mval[2];
+ int dist = KMAXDIST;
+
+ knife_bgl_get_mats(kcd, &mats);
+
+ mval[0] = kcd->vc.mval[0]; mval[1] = kcd->vc.mval[1];
+
+ /*unproject to find view ray*/
+ view3d_unproject(&mats, origin, mval[0], mval[1], 0.0f);
+
+ sub_v3_v3v3(ray, origin, kcd->vc.rv3d->viewinv[3]);
+ normalize_v3(ray);
+
+ /*transform into object space*/
+ mul_m4_v3(kcd->ob->imat, origin);
+ mul_m4_v3(kcd->ob->imat, ray);
+
+ f = BMBVH_RayCast(kcd->bmbvh, origin, ray, co);
+ if (!f) {
+ /*try to use backbuffer selection method if ray casting failed*/
+ f = EDBM_findnearestface(&kcd->vc, &dist);
+
+ /*cheat for now; just put in the origin instead
+ of a true coordinate on the face*/
+ copy_v3_v3(co, origin);
+ }
+
+ //copy_v3_v3(co, origin);
+
+ return f;
+}
+
+/*find the 2d screen space density of vertices within a radius. used to scale snapping
+ distance for picking edges/verts.*/
+static int knife_sample_screen_density(knifetool_opdata *kcd, float radius)
+{
+ BMFace *f;
+ float co[3], sco[3];
+
+ f = knife_find_closest_face(kcd, co);
+
+ if (f) {
+ ListBase *lst;
+ Ref *ref;
+ KnifeVert *curv = NULL;
+ float dis;
+ int c = 0;
+
+ knife_project_v3(kcd, co, sco);
+
+ lst = knife_get_face_kedges(kcd, f);
+ for (ref=lst->first; ref; ref=ref->next) {
+ KnifeEdge *kfe = ref->ref;
+ int i;
+
+ for (i=0; i<2; i++) {
+ KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
+
+ knife_project_v3(kcd, kfv->co, kfv->sco);
+
+ dis = len_v2v2(kfv->sco, sco);
+ if (dis < radius) {
+ if(kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ float vec[3];
+
+ copy_v3_v3(vec, kfv->co);
+ mul_m4_v3(kcd->vc.obedit->obmat, vec);
+
+ if(view3d_test_clipping(kcd->vc.rv3d, vec, 1)==0) {
+ c++;
+ }
+ } else {
+ c++;
+ }
+ }
+ }
+ }
+
+ return c;
+ }
+
+ return 0;
+}
+
+/*returns snapping distance for edges/verts, scaled by the density of the
+ surrounding mesh (in screen space)*/
+static float knife_snap_size(knifetool_opdata *kcd, float maxsize)
+{
+ float density = (float)knife_sample_screen_density(kcd, maxsize*2.0f);
+
+ density = MAX2(density, 1);
+
+ return MIN2(maxsize / (density*0.5f), maxsize);
+}
+
+/*p is closest point on edge to the mouse cursor*/
+static KnifeEdge *knife_find_closest_edge(knifetool_opdata *kcd, float p[3], BMFace **fptr)
+{
+ BMFace *f;
+ float co[3], sco[3], maxdist = knife_snap_size(kcd, kcd->ethresh);
+
+ f = knife_find_closest_face(kcd, co);
+ /*set p to co, in case we don't find anything, means a face cut*/
+ copy_v3_v3(p, co);
+
+ if (f) {
+ KnifeEdge *cure = NULL;
+ ListBase *lst;
+ Ref *ref;
+ float dis, curdis=FLT_MAX;
+
+ knife_project_v3(kcd, co, sco);
+
+ /*look through all edges associated with this face*/
+ lst = knife_get_face_kedges(kcd, f);
+ for (ref=lst->first; ref; ref=ref->next) {
+ KnifeEdge *kfe = ref->ref;
+
+ /*project edge vertices into screen space*/
+ knife_project_v3(kcd, kfe->v1->co, kfe->v1->sco);
+ knife_project_v3(kcd, kfe->v2->co, kfe->v2->sco);
+
+ dis = dist_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco);
+ if (dis < curdis && dis < maxdist) {
+ if(kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ float labda_PdistVL2Dfl(float *v1, float *v2, float *v3);
+ float labda= labda_PdistVL2Dfl(sco, kfe->v1->sco, kfe->v2->sco);
+ float vec[3];
+
+ vec[0]= kfe->v1->co[0] + labda*(kfe->v2->co[0] - kfe->v1->co[0]);
+ vec[1]= kfe->v1->co[1] + labda*(kfe->v2->co[1] - kfe->v1->co[1]);
+ vec[2]= kfe->v1->co[2] + labda*(kfe->v2->co[2] - kfe->v1->co[2]);
+ mul_m4_v3(kcd->vc.obedit->obmat, vec);
+
+ if(view3d_test_clipping(kcd->vc.rv3d, vec, 1)==0) {
+ cure = kfe;
+ curdis = dis;
+ }
+ } else {
+ cure = kfe;
+ curdis = dis;
+ }
+ }
+ }
+
+ if (fptr)
+ *fptr = f;
+
+ if (cure && p) {
+ closest_to_line_segment_v3(p, co, cure->v1->co, cure->v2->co);
+ }
+
+ return cure;
+ }
+
+ if (fptr)
+ *fptr = NULL;
+
+ return NULL;
+}
+
+/*find a vertex near the mouse cursor, if it exists*/
+static KnifeVert *knife_find_closest_vert(knifetool_opdata *kcd, float p[3], BMFace **fptr)
+{
+ BMFace *f;
+ float co[3], sco[3], maxdist = knife_snap_size(kcd, kcd->vthresh);
+
+ f = knife_find_closest_face(kcd, co);
+ /*set p to co, in case we don't find anything, means a face cut*/
+ copy_v3_v3(p, co);
+
+ if (f) {
+ ListBase *lst;
+ Ref *ref;
+ KnifeVert *curv = NULL;
+ float dis, curdis=FLT_MAX;
+
+ knife_project_v3(kcd, co, sco);
+
+ lst = knife_get_face_kedges(kcd, f);
+ for (ref=lst->first; ref; ref=ref->next) {
+ KnifeEdge *kfe = ref->ref;
+ int i;
+
+ for (i=0; i<2; i++) {
+ KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
+
+ knife_project_v3(kcd, kfv->co, kfv->sco);
+
+ dis = len_v2v2(kfv->sco, sco);
+ if (dis < curdis && dis < maxdist) {
+ if(kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ float vec[3];
+
+ copy_v3_v3(vec, kfv->co);
+ mul_m4_v3(kcd->vc.obedit->obmat, vec);
+
+ if(view3d_test_clipping(kcd->vc.rv3d, vec, 1)==0) {
+ curv = kfv;
+ curdis = dis;
+ }
+ } else {
+ curv = kfv;
+ curdis = dis;
+ }
+ }
+ }
+ }
+
+ if (fptr)
+ *fptr = f;
+
+ if (curv && p) {
+ copy_v3_v3(p, curv->co);
+ }
+
+ return curv;
+ }
+
+ if (fptr)
+ *fptr = NULL;
+
+ return NULL;
+}
+
+/*update active knife edge/vert pointers*/
+static int knife_update_active(knifetool_opdata *kcd)
+{
+ kcd->curvert = NULL; kcd->curedge = NULL; kcd->curbmface = NULL;
+
+ kcd->curvert = knife_find_closest_vert(kcd, kcd->vertco, &kcd->curbmface);
+ if (!kcd->curvert)
+ kcd->curedge = knife_find_closest_edge(kcd, kcd->vertco, &kcd->curbmface);
+
+ if (kcd->mode == MODE_DRAGGING) {
+ knife_find_line_hits(kcd);
+ }
+ return 1;
+}
+
+#define VERT_ON_EDGE 8
+#define VERT_ORIG 16
+#define FACE_FLIP 32
+
+/*use edgenet to fill faces. this is a bit annoying and convoluted.*/
+void knifenet_fill_faces(knifetool_opdata *kcd)
+{
+ BLI_mempool_iter iter;
+ BMOperator bmop;
+ BMesh *bm = kcd->em->bm;
+ BMOIter siter;
+ BMIter bmiter;
+ BMFace *f;
+ BMEdge *e;
+ KnifeVert *kfv;
+ KnifeEdge *kfe;
+ float (*vertcos)[3] = NULL;
+ void **blocks = NULL;
+ BLI_array_declare(blocks);
+ BLI_array_declare(vertcos);
+ float *w = NULL;
+ BLI_array_declare(w);
+
+ BMO_push(bm, NULL);
+
+ BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) {
+ BMINDEX_SET(f, 0);
+ }
+
+ /*assign a bit flag to each face. adjacent
+ faces cannot share the same bit flag, nor can
+ diagonally adjacent faces*/
+ BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) {
+ BMIter bmiter2;
+ BMLoop *l;
+ int group = 0, ok=0;
+
+ while (!ok) {
+ ok = 1;
+ BM_ITER(l, &bmiter2, bm, BM_LOOPS_OF_FACE, f) {
+ BMLoop *l2 = l->radial_next;
+ while (l2 != l) {
+ BMLoop *l3;
+ BMIter bmiter3;
+
+ if (l2->f == l->f) {
+ l2 = l2->radial_next;
+ continue;
+ }
+
+ if (BMINDEX_GET(l2->f) == (1<<group) && group <= MAXGROUP) {
+ group++;
+ ok = 0;
+ } else if (BMINDEX_GET(l2->f) == (1<<group)) {
+ printf("yeek! ran out of groups! 1\n");
+ }
+
+ BM_ITER(l3, &bmiter3, bm, BM_LOOPS_OF_FACE, l2->f) {
+ BMLoop *l4 = l3->radial_next;
+
+ do {
+ if (l4->f == l->f) {
+ l4 = l4->radial_next;
+ continue;
+ }
+
+ if (BMINDEX_GET(l4->f) == (1<<group) && group <= MAXGROUP) {
+ group++;
+ ok = 0;
+ } else if (BMINDEX_GET(l4->f) == (1<<group)) {
+ printf("yeek! ran out of groups! 2`\n");
+ }
+
+ l4 = l4->radial_next;
+ } while (l4 != l3);
+ }
+
+ l2 = l2->radial_next;
+ }
+ }
+ }
+
+ BMINDEX_SET(f, (1<<group));
+ }
+
+ /*turn knife verts into real verts, as necassary*/
+ BLI_mempool_iternew(kcd->kverts, &iter);
+ for (kfv=BLI_mempool_iterstep(&iter); kfv; kfv=BLI_mempool_iterstep(&iter)) {
+ if (!kfv->v) {
+ kfv->v = BM_Make_Vert(bm, kfv->co, NULL);
+ kfv->flag = 1;
+ } else {
+ kfv->flag = 0;
+ BMO_SetFlag(bm, kfv->v, VERT_ORIG);
+ }
+
+ BMO_SetFlag(bm, kfv->v, MARK);
+ }
+
+ BMO_InitOpf(bm, &bmop, "edgenet_fill use_restrict=%i", 1);
+
+ /*turn knife edges into real edges, and assigns bit masks representing
+ the faces they are adjacent too*/
+ BLI_mempool_iternew(kcd->kedges, &iter);
+ for (kfe=BLI_mempool_iterstep(&iter); kfe; kfe=BLI_mempool_iterstep(&iter)) {
+ int group = 0;
+
+ if (!kfe->v1 || !kfe->v2)
+ continue;
+
+ if (kfe->e) {
+ BM_ITER(f, &bmiter, bm, BM_FACES_OF_EDGE, kfe->e) {
+ group |= BMINDEX_GET(f);
+
+ if (kfe->v1->v != kfe->e->v1 || kfe->v2->v != kfe->e->v2) {
+ BMO_SetFlag(bm, f, DEL);
+ }
+ }
+
+ kfe->oe = kfe->e;
+
+ if (kfe->v1->v != kfe->e->v1 || kfe->v2->v != kfe->e->v2) {
+ BMO_SetFlag(bm, kfe->e, DEL);
+ BMO_ClearFlag(bm, kfe->e, MARK);
+
+ if (kfe->v1->v != kfe->e->v1)
+ BMO_SetFlag(bm, kfe->v1->v, VERT_ON_EDGE);
+ if (kfe->v2->v != kfe->e->v2)
+ BMO_SetFlag(bm, kfe->v2->v, VERT_ON_EDGE);
+
+ kfe->e = NULL;
+ }
+ }
+
+ if (!kfe->e) {
+ kfe->e = BM_Make_Edge(bm, kfe->v1->v, kfe->v2->v, NULL, 0);
+ }
+
+ BMO_SetFlag(bm, kfe->e, MARK);
+
+ if (kfe->basef) {
+ BMEdge *e;
+ BM_ITER(e, &bmiter, bm, BM_EDGES_OF_FACE, kfe->basef) {
+ BMO_SetFlag(bm, e, MARK);
+ }
+
+ BMO_SetFlag(bm, kfe->basef, DEL);
+ group |= BMINDEX_GET(kfe->basef);
+ }
+
+ if (!group) {
+ Ref *ref;
+
+ for (ref=kfe->faces.first; ref; ref=ref->next) {
+ kfe->basef = ref->ref;
+ group |= BMINDEX_GET(ref->ref);
+ }
+ }
+
+ if (group)
+ BMO_Insert_MapInt(bm, &bmop, "restrict", kfe->e, group);
+ else
+ printf("yeek!\n");
+ }
+
+ /*not sure why this is needed, sanity check to make sure del'd edges are not
+ marked as well*/
+ BM_ITER(e, &bmiter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (BMO_TestFlag(bm, e, DEL))
+ BMO_ClearFlag(bm, e, MARK);
+ }
+
+ BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) {
+ BMIter eiter;
+
+ if (!BMO_TestFlag(bm, f, DEL))
+ continue;
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_FACE, f) {
+ BMIter liter;
+ BMLoop *l;
+
+ BMO_SetFlag(bm, e, MARK);
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_EDGE, e) {
+ BMINDEX_SET(e, BMINDEX_GET(e)|BMINDEX_GET(l->f));
+ }
+ }
+ }
+
+ BMO_Flag_To_Slot(bm, &bmop, "edges", MARK, BM_EDGE);
+ BMO_Flag_To_Slot(bm, &bmop, "excludefaces", DEL, BM_FACE);
+
+ /*execute the edgenet fill operator. it will restrict filled faces to edges
+ belonging to the same group (note edges can belong to multiple groups, using
+ bitmasks)*/
+ BMO_Exec_Op(bm, &bmop);
+ BMO_Flag_Buffer(bm, &bmop, "faceout", MARK, BM_FACE);
+
+ BM_Compute_Normals(bm);
+
+ //void interp_weights_poly_v3(float *w,float v[][3], int n, float *co)
+
+ /* interpolate customdata */
+
+ /*first deal with interpolating vertices that lie on original edges*/
+ BLI_mempool_iternew(kcd->kedges, &iter);
+ for (kfe=BLI_mempool_iterstep(&iter); kfe; kfe=BLI_mempool_iterstep(&iter)) {
+ BMLoop *l1, *l2;
+ float fac, w[2];
+ void *blocks[2];
+
+ if (!kfe->oe)
+ continue;
+
+ BM_ITER(l1, &bmiter, bm, BM_LOOPS_OF_EDGE, kfe->oe) {
+ BMLoop *l2 = NULL;
+ BMIter liter;
+ int i, j;
+
+ BM_ITER(l2, &liter, bm, BM_LOOPS_OF_EDGE, kfe->e) {
+ if (!BM_Vert_In_Edge(kfe->e, l2->next->v)) {
+ l2 = l2->prev;
+ }
+
+ if (!BMO_InMap(bm, &bmop, "faceout_groupmap", l2->f))
+ continue;
+
+ if (BMINDEX_GET(l1->f) == BMO_Get_MapInt(bm, &bmop, "faceout_groupmap", l2->f))
+ break;
+ }
+
+ if (!l2)
+ continue;
+
+ if (dot_v3v3(l1->f->no, l2->f->no) < 0.0f) {
+ BMO_SetFlag(bm, l2->f, FACE_FLIP);
+ }
+
+ for (i=0; i<2; i++) {
+ if (i)
+ l2 = l2->next;
+
+ fac = len_v3v3(kfe->oe->v1->co, l2->v->co) / (len_v3v3(kfe->oe->v1->co, kfe->oe->v2->co)+FLT_EPSILON);
+
+ if (kfe->oe->v1 == l1->v) {
+ w[0] = 1.0-fac;
+ w[1] = fac;
+ } else {
+ w[0] = fac;
+ w[1] = 1.0-fac;
+ }
+
+ if (l1->e == kfe->oe) {
+ blocks[0] = l1->head.data;
+ blocks[1] = l1->next->head.data;
+ } else {
+ blocks[0] = l1->prev->head.data;
+ blocks[1] = l1->head.data;
+ }
+
+ BM_Copy_Attributes(bm, bm, l1->f, l2->f);
+ CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, 2, l2->head.data);
+ }
+ }
+ }
+
+ /*ensure normals are correct*/
+ BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) {
+ if (BMO_TestFlag(bm, f, FACE_FLIP)) {
+ BM_flip_normal(bm, f);
+ }
+ }
+
+ /*now deal with interior vertex interpolation
+ still kindof buggy*/
+ BMO_ITER(f, &siter, bm, &bmop, "faceout_groupmap", BM_FACE) {
+ BMLoop *l1, *l2;
+ BMFace *f2;
+ BMIter liter1, liter2;
+ int group = *(int*)BMO_IterMapVal(&siter);
+
+ BM_ITER(l1, &liter1, bm, BM_LOOPS_OF_FACE, f) {
+ float co[3], hit[3];
+ float dir[3];
+ int i;
+
+ if (BMO_TestFlag(bm, l1->v, VERT_ORIG) || BMO_TestFlag(bm, l1->v, VERT_ON_EDGE))
+ continue;
+
+ copy_v3_v3(co, l1->v->co);
+ copy_v3_v3(dir, l1->v->no);
+ mul_v3_fl(dir, 0.001f);
+
+ add_v3_v3(co, dir);
+ copy_v3_v3(dir, l1->v->no);
+ mul_v3_fl(dir, -1.0);
+
+ f2 = BMBVH_RayCast(kcd->bmbvh, co, dir, hit);
+ if (!f2) {
+ printf("eek!!\n");
+ continue;
+ }
+
+ BLI_array_empty(vertcos);
+ BLI_array_empty(blocks);
+ BLI_array_empty(w);
+ BM_ITER(l2, &liter2, bm, BM_LOOPS_OF_FACE, f2) {
+ BLI_array_growone(vertcos);
+ BLI_array_append(blocks, l2->head.data);
+
+ copy_v3_v3(vertcos[BLI_array_count(vertcos)-1], l2->v->co);
+ BLI_array_append(w, 0.0f);
+ }
+
+ BM_Copy_Attributes(bm, bm, f2, f);
+
+ interp_weights_poly_v3(w, vertcos, f2->len, l1->v->co);
+ CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, BLI_array_count(blocks), l1->head.data);
+ }
+ }
+
+ BMO_Finish_Op(bm, &bmop);
+
+ /*delete left over faces*/
+ BMO_CallOpf(bm, "del geom=%ff context=%i", DEL, DEL_ONLYFACES);
+ BMO_CallOpf(bm, "del geom=%fe context=%i", DEL, DEL_EDGES);
+
+ BMO_pop(bm);
+}
+
+/*called on tool confirmation*/
+static void knifetool_finish(bContext *C, wmOperator *op)
+{
+ knifetool_opdata *kcd= op->customdata;
+
+ knifenet_fill_faces(kcd);
+}
+
+/*copied from paint_image.c*/
+static int project_knife_view_clip(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
+{
+ int orth= get_view3d_cliprange(v3d, rv3d, clipsta, clipend);
+
+ if (orth) { /* only needed for ortho */
+ float fac = 2.0f / ((*clipend) - (*clipsta));
+ *clipsta *= fac;
+ *clipend *= fac;
+ }
+
+ return orth;
+}
+
+void knife_recalc_projmat(knifetool_opdata *kcd)
+{
+ ARegion *ar = CTX_wm_region(kcd->C);
+
+ if (!ar)
+ return;
+
+ invert_m4_m4(kcd->ob->imat, kcd->ob->obmat);
+ view3d_get_object_project_mat(ar->regiondata, kcd->ob, kcd->projmat);
+ //mul_m4_m4m4(kcd->projmat, kcd->vc.rv3d->viewmat, kcd->vc.rv3d->winmat);
+
+ kcd->is_ortho = project_knife_view_clip(kcd->vc.v3d, kcd->vc.rv3d,
+ &kcd->clipsta, &kcd->clipend);
+}
+
+/* called when modal loop selection is done... */
+static void knifetool_exit (bContext *C, wmOperator *op)
+{
+ knifetool_opdata *kcd= op->customdata;
+
+ if (!kcd)
+ return;
+
+ /* deactivate the extra drawing stuff in 3D-View */
+ ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle);
+
+ /* free the custom data */
+ BLI_mempool_destroy(kcd->refs);
+ BLI_mempool_destroy(kcd->kverts);
+ BLI_mempool_destroy(kcd->kedges);
+
+ BLI_ghash_free(kcd->origedgemap, NULL, NULL);
+ BLI_ghash_free(kcd->origvertmap, NULL, NULL);
+ BLI_ghash_free(kcd->kedgefacemap, NULL, NULL);
+
+ BMBVH_FreeBVH(kcd->bmbvh);
+ BLI_memarena_free(kcd->arena);
+
+ /* tag for redraw */
+ ED_region_tag_redraw(kcd->ar);
+
+ /* destroy kcd itself */
+ MEM_freeN(kcd);
+ op->customdata= NULL;
+}
+
+/* called when modal loop selection gets set up... */
+static int knifetool_init (bContext *C, wmOperator *op, int do_cut)
+{
+ knifetool_opdata *kcd;
+
+ /* alloc new customdata */
+ kcd= op->customdata= MEM_callocN(sizeof(knifetool_opdata), "knifetool Modal Op Data");
+
+ /* assign the drawing handle for drawing preview line... */
+ kcd->ar= CTX_wm_region(C);
+ kcd->C = C;
+ kcd->draw_handle= ED_region_draw_cb_activate(kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW);
+ em_setup_viewcontext(C, &kcd->vc);
+
+ kcd->ob = CTX_data_edit_object(C);
+ kcd->em= ((Mesh *)kcd->ob->data)->edit_btmesh;
+ kcd->bmbvh = BMBVH_NewBVH(kcd->em);
+ kcd->arena = BLI_memarena_new(1<<15, "knife");
+ kcd->vthresh = KMAXDIST-1;
+ kcd->ethresh = KMAXDIST;
+
+ knife_recalc_projmat(kcd);
+
+ ED_region_tag_redraw(kcd->ar);
+
+ kcd->refs = BLI_mempool_create(sizeof(Ref), 1, 2048, 0, 0);
+ kcd->kverts = BLI_mempool_create(sizeof(KnifeVert), 1, 512, 0, 1);
+ kcd->kedges = BLI_mempool_create(sizeof(KnifeEdge), 1, 512, 0, 1);
+
+ kcd->origedgemap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife origedgemap");
+ kcd->origvertmap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife origvertmap");
+ kcd->kedgefacemap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife origvertmap");
+
+ return 1;
+}
+
+static int knifetool_cancel (bContext *C, wmOperator *op)
+{
+ /* this is just a wrapper around exit() */
+ knifetool_exit(C, op);
+ return OPERATOR_CANCELLED;
+}
+
+static int knifetool_invoke (bContext *C, wmOperator *op, wmEvent *evt)
+{
+ knifetool_opdata *kcd;
+
+ view3d_operator_needs_opengl(C);
+
+ if (!knifetool_init(C, op, 0))
+ return OPERATOR_CANCELLED;
+
+ /* add a modal handler for this operator - handles loop selection */
+ WM_event_add_modal_handler(C, op);
+
+ kcd = op->customdata;
+ kcd->vc.mval[0] = evt->mval[0];
+ kcd->vc.mval[1] = evt->mval[1];
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int knifetool_modal (bContext *C, wmOperator *op, wmEvent *event)
+{
+ Object *obedit;
+ knifetool_opdata *kcd= op->customdata;
+
+ if (!C) {
+ return OPERATOR_FINISHED;
+ }
+
+ obedit = CTX_data_edit_object(C);
+ if (!obedit || obedit->type != OB_MESH || ((Mesh*)obedit->data)->edit_btmesh != kcd->em)
+ return OPERATOR_FINISHED;
+
+ view3d_operator_needs_opengl(C);
+
+ switch (event->type) {
+ case ESCKEY:
+ case RETKEY: /* confirm */ // XXX hardcoded
+ if (event->val == KM_RELEASE) {
+ if (kcd->mode == MODE_DRAGGING && event->type == ESCKEY) {
+ kcd->mode = MODE_IDLE;
+ ED_region_tag_redraw(kcd->ar);
+ } else {
+ /* finish */
+ ED_region_tag_redraw(kcd->ar);
+
+ knifetool_finish(C, op);
+ knifetool_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ }
+
+ ED_region_tag_redraw(kcd->ar);
+ return OPERATOR_RUNNING_MODAL;
+ case LEFTMOUSE:
+ knife_recalc_projmat(kcd);
+ if (event->val != KM_RELEASE)
+ break;
+
+ if (kcd->mode == MODE_DRAGGING) {
+ knife_add_cut(kcd);
+ if (!event->ctrl) {
+ knife_finish_cut(kcd);
+ kcd->mode = MODE_IDLE;
+ }
+ } else {
+ knife_start_cut(kcd);
+ kcd->mode = MODE_DRAGGING;
+ }
+
+ ED_region_tag_redraw(kcd->ar);
+ return OPERATOR_RUNNING_MODAL;
+ case LEFTCTRLKEY:
+ case RIGHTCTRLKEY:
+ knife_recalc_projmat(kcd);
+
+ if (event->val == KM_RELEASE) {
+ knife_finish_cut(kcd);
+ kcd->mode = MODE_IDLE;
+ }
+
+ ED_region_tag_redraw(kcd->ar);
+ return OPERATOR_RUNNING_MODAL;
+ case MOUSEMOVE: { /* mouse moved somewhere to select another loop */
+ knife_recalc_projmat(kcd);
+ kcd->vc.mval[0] = event->mval[0];
+ kcd->vc.mval[1] = event->mval[1];
+
+ if (knife_update_active(kcd))
+ ED_region_tag_redraw(kcd->ar);
+
+ break;
+ /*block undo*/
+ case ZKEY:
+ if (event->ctrl)
+ return OPERATOR_RUNNING_MODAL;
+ }
+ case KKEY:
+ if (!event->ctrl && !event->alt && !event->shift)
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ /* keep going until the user confirms */
+ return OPERATOR_PASS_THROUGH;
+}
+
+void MESH_OT_knifetool (wmOperatorType *ot)
+{
+ /* description */
+ ot->name= "Knife Topology Tool";
+ ot->idname= "MESH_OT_knifetool";
+ ot->description= "Cut new topology";
+
+ /* callbacks */
+ ot->invoke= knifetool_invoke;
+ ot->modal= knifetool_modal;
+ ot->cancel= knifetool_cancel;
+ ot->poll= ED_operator_editmesh_view3d;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
+}
diff --git a/source/blender/editors/mesh/loopcut.c b/source/blender/editors/mesh/loopcut.c
index 8001c4b1390..0c9f9d8d68d 100644
--- a/source/blender/editors/mesh/loopcut.c
+++ b/source/blender/editors/mesh/loopcut.c
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2007 Blender Foundation.
* All rights reserved.
@@ -27,6 +27,8 @@
*/
#include <float.h>
+#define _USE_MATH_DEFINES
+#include <math.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
@@ -45,7 +47,7 @@
#include "BLI_blenlib.h"
#include "BLI_dynstr.h" /*for WM_operator_pystring */
#include "BLI_editVert.h"
-#include "BLI_math.h"
+#include "BLI_array.h"
#include "BLI_utildefines.h"
#include "BKE_blender.h"
@@ -56,6 +58,8 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_array_mallocn.h"
+#include "BKE_tessmesh.h"
+#include "BKE_depsgraph.h"
#include "BIF_gl.h"
#include "BIF_glutil.h" /* for paint cursor */
@@ -90,8 +94,8 @@ typedef struct tringselOpData {
ViewContext vc;
Object *ob;
- EditMesh *em;
- EditEdge *eed;
+ BMEditMesh *em;
+ BMEdge *eed;
int extend;
int do_cut;
@@ -125,17 +129,60 @@ static void ringsel_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
}
}
+/*given two opposite edges in a face, finds the ordering of their vertices so
+ that cut preview lines won't cross each other*/
+static void edgering_find_order(BMEditMesh *em, BMEdge *lasteed, BMEdge *eed,
+ BMVert *lastv1, BMVert *v[2][2])
+{
+ BMIter liter;
+ BMLoop *l, *l2;
+ int rev;
+
+ l = eed->l;
+
+ /*find correct order for v[1]*/
+ if (!(BM_Edge_In_Face(l->f, eed) && BM_Edge_In_Face(l->f, lasteed))) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_LOOP, l) {
+ if (BM_Edge_In_Face(l->f, eed) && BM_Edge_In_Face(l->f, lasteed))
+ break;
+ }
+ }
+
+ /*this should never happen*/
+ if (!l) {
+ v[0][0] = eed->v1;
+ v[0][1] = eed->v2;
+ v[1][0] = lasteed->v1;
+ v[1][1] = lasteed->v2;
+ return;
+ }
+
+ l2 = BM_OtherFaceLoop(l->e, l->f, eed->v1);
+ rev = (l2 == (BMLoop*)l->prev);
+ while (l2->v != lasteed->v1 && l2->v != lasteed->v2) {
+ l2 = rev ? (BMLoop*)l2->prev : (BMLoop*)l2->next;
+ }
+
+ if (l2->v == lastv1) {
+ v[0][0] = eed->v1;
+ v[0][1] = eed->v2;
+ } else {
+ v[0][0] = eed->v2;
+ v[0][1] = eed->v1;
+ }
+}
+
static void edgering_sel(tringselOpData *lcd, int previewlines, int select)
{
- EditMesh *em = lcd->em;
- EditEdge *startedge = lcd->eed;
- EditEdge *eed;
- EditFace *efa;
- EditVert *v[2][2];
+ BMEditMesh *em = lcd->em;
+ BMEdge *startedge = lcd->eed;
+ BMEdge *eed, *lasteed;
+ BMVert *v[2][2], *lastv1;
+ BMWalker walker;
float (*edges)[2][3] = NULL;
- V_DYNDECLARE(edges);
+ BLI_array_declare(edges);
float co[2][3];
- int looking=1, i, tot=0;
+ int i, tot=0;
if (!startedge)
return;
@@ -147,110 +194,75 @@ static void edgering_sel(tringselOpData *lcd, int previewlines, int select)
}
if (!lcd->extend) {
- EM_clear_flag_all(lcd->em, SELECT);
+ EDBM_clear_flag_all(lcd->em, BM_SELECT);
}
- /* in eed->f1 we put the valence (amount of faces in edge) */
- /* in eed->f2 we put tagged flag as correct loop */
- /* in efa->f1 we put tagged flag as correct to select */
+ if (select) {
+ BMW_Init(&walker, em->bm, BMW_EDGERING, 0, 0);
+ eed = BMW_Begin(&walker, startedge);
+ for (; eed; eed=BMW_Step(&walker)) {
+ BM_Select(em->bm, eed, 1);
+ }
+ BMW_End(&walker);
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0;
- eed->f2= 0;
+ return;
}
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->f1= 0;
- if(efa->h==0) {
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4) efa->e4->f1++;
- }
- }
-
- // tag startedge OK
- startedge->f2= 1;
-
- while(looking) {
- looking= 0;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->e4 && efa->f1==0 && efa->h == 0) { // not done quad
- if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { // valence ok
-
- // if edge tagged, select opposing edge and mark face ok
- if(efa->e1->f2) {
- efa->e3->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- else if(efa->e2->f2) {
- efa->e4->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e3->f2) {
- efa->e1->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e4->f2) {
- efa->e2->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- }
+ BMW_Init(&walker, em->bm, BMW_EDGERING, 0, 0);
+ eed = startedge = BMW_Begin(&walker, startedge);
+ lastv1 = NULL;
+ for (lasteed=NULL; eed; eed=BMW_Step(&walker)) {
+ if (lasteed) {
+ if (lastv1) {
+ v[1][0] = v[0][0];
+ v[1][1] = v[0][1];
+ } else {
+ v[1][0] = lasteed->v1;
+ v[1][1] = lasteed->v2;
+ lastv1 = lasteed->v1;
+ }
+
+ edgering_find_order(em, lasteed, eed, lastv1, v);
+ lastv1 = v[0][0];
+
+ for(i=1;i<=previewlines;i++){
+ co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0];
+ co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1];
+ co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2];
+
+ co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0];
+ co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1];
+ co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2];
+
+ BLI_array_growone(edges);
+ VECCOPY(edges[tot][0], co[0]);
+ VECCOPY(edges[tot][1], co[1]);
+ tot++;
}
}
+ lasteed = eed;
}
- if(previewlines > 0 && !select){
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->v4 == NULL) { continue; }
- if(efa->h == 0){
- if(efa->e1->f2 == 1){
- if(efa->e1->h == 1 || efa->e3->h == 1 )
- continue;
-
- v[0][0] = efa->v1;
- v[0][1] = efa->v2;
- v[1][0] = efa->v4;
- v[1][1] = efa->v3;
- } else if(efa->e2->f2 == 1){
- if(efa->e2->h == 1 || efa->e4->h == 1)
- continue;
- v[0][0] = efa->v2;
- v[0][1] = efa->v3;
- v[1][0] = efa->v1;
- v[1][1] = efa->v4;
- } else { continue; }
-
- for(i=1;i<=previewlines;i++){
- co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0];
- co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1];
- co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2];
-
- co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0];
- co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1];
- co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2];
-
- V_GROW(edges);
- VECCOPY(edges[tot][0], co[0]);
- VECCOPY(edges[tot][1], co[1]);
- tot++;
- }
- }
- }
- } else {
- select = (startedge->f & SELECT) == 0;
+ if (BM_Edge_Share_Faces(lasteed, startedge)) {
+ edgering_find_order(em, lasteed, startedge, lastv1, v);
+
+ for(i=1;i<=previewlines;i++){
+ co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0];
+ co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1];
+ co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2];
- /* select the edges */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f2) EM_select_edge(eed, select);
+ co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0];
+ co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1];
+ co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2];
+
+ BLI_array_growone(edges);
+ VECCOPY(edges[tot][0], co[0]);
+ VECCOPY(edges[tot][1], co[1]);
+ tot++;
}
}
+ BMW_End(&walker);
lcd->edges = edges;
lcd->totedge = tot;
}
@@ -260,7 +272,8 @@ static void ringsel_find_edge(tringselOpData *lcd, int cuts)
if (lcd->eed) {
edgering_sel(lcd, cuts, 0);
} else if(lcd->edges) {
- MEM_freeN(lcd->edges);
+ if (lcd->edges)
+ MEM_freeN(lcd->edges);
lcd->edges = NULL;
lcd->totedge = 0;
}
@@ -269,17 +282,17 @@ static void ringsel_find_edge(tringselOpData *lcd, int cuts)
static void ringsel_finish(bContext *C, wmOperator *op)
{
tringselOpData *lcd= op->customdata;
- int cuts= (lcd->do_cut)? RNA_int_get(op->ptr,"number_cuts"): 0;
+ int cuts= RNA_int_get(op->ptr, "number_cuts");
if (lcd->eed) {
- EditMesh *em = BKE_mesh_get_editmesh(lcd->ob->data);
-
+ BMEditMesh *em = lcd->em;
+
edgering_sel(lcd, cuts, 1);
if (lcd->do_cut) {
-
- esubdivideflag(lcd->ob, em, SELECT, 0.0f, 0.0f, 0, cuts, 0, SUBDIV_SELECT_LOOPCUT);
-
+ BM_esubdivideflag(lcd->ob, em->bm, BM_SELECT, 0.0f,
+ 0.0f, 0, cuts, SUBDIV_SELECT_LOOPCUT,
+ SUBD_PATH, 0, 0);
/* force edge slide to edge select mode in in face select mode */
if (em->selectmode & SCE_SELECT_FACE) {
if (em->selectmode == SCE_SELECT_FACE)
@@ -287,30 +300,32 @@ static void ringsel_finish(bContext *C, wmOperator *op)
else
em->selectmode &= ~SCE_SELECT_FACE;
CTX_data_tool_settings(C)->selectmode= em->selectmode;
- EM_selectmode_set(em);
+ EDBM_selectmode_set(em);
+
+ WM_event_add_notifier(C, NC_SCENE|ND_TOOLSETTINGS, CTX_data_scene(C));
WM_event_add_notifier(C, NC_SCENE|ND_TOOLSETTINGS, CTX_data_scene(C));
}
-
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT|ND_DATA, lcd->ob->data);
DAG_id_tag_update(lcd->ob->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, lcd->ob->data);
}
else {
/* sets as active, useful for other tools */
if(em->selectmode & SCE_SELECT_VERTEX)
- EM_store_selection(em, lcd->eed->v1, EDITVERT);
+ EDBM_selectmode_flush(em);
if(em->selectmode & SCE_SELECT_EDGE)
- EM_store_selection(em, lcd->eed, EDITEDGE);
+ EDBM_selectmode_flush(em);
- EM_selectmode_flush(lcd->em);
+ EDBM_selectmode_flush(lcd->em);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, lcd->ob->data);
}
}
}
/* called when modal loop selection is done... */
-static void ringsel_exit(wmOperator *op)
+static void ringsel_exit(bContext *UNUSED(C), wmOperator *op)
{
tringselOpData *lcd= op->customdata;
@@ -339,7 +354,7 @@ static int ringsel_init (bContext *C, wmOperator *op, int do_cut)
lcd->ar= CTX_wm_region(C);
lcd->draw_handle= ED_region_draw_cb_activate(lcd->ar->type, ringsel_draw, lcd, REGION_DRAW_POST_VIEW);
lcd->ob = CTX_data_edit_object(C);
- lcd->em= BKE_mesh_get_editmesh((Mesh *)lcd->ob->data);
+ lcd->em= ((Mesh *)lcd->ob->data)->edit_btmesh;
lcd->extend = do_cut ? 0 : RNA_boolean_get(op->ptr, "extend");
lcd->do_cut = do_cut;
em_setup_viewcontext(C, &lcd->vc);
@@ -349,17 +364,17 @@ static int ringsel_init (bContext *C, wmOperator *op, int do_cut)
return 1;
}
-static int ringcut_cancel (bContext *UNUSED(C), wmOperator *op)
+static int ringcut_cancel (bContext *C, wmOperator *op)
{
/* this is just a wrapper around exit() */
- ringsel_exit(op);
+ ringsel_exit(C, op);
return OPERATOR_CANCELLED;
}
static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt)
{
tringselOpData *lcd;
- EditEdge *edge;
+ BMEdge *edge;
int dist = 75;
view3d_operator_needs_opengl(C);
@@ -367,10 +382,13 @@ static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt)
if (!ringsel_init(C, op, 0))
return OPERATOR_CANCELLED;
+ /* add a modal handler for this operator - handles loop selection */
+ WM_event_add_modal_handler(C, op);
+
lcd = op->customdata;
if (lcd->em->selectmode == SCE_SELECT_FACE) {
- ringsel_exit(op);
+ ringsel_exit(C, op);
WM_operator_name_call(C, "MESH_OT_loop_select", WM_OP_INVOKE_REGION_WIN, NULL);
return OPERATOR_CANCELLED;
}
@@ -378,26 +396,20 @@ static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt)
lcd->vc.mval[0] = evt->mval[0];
lcd->vc.mval[1] = evt->mval[1];
- edge = findnearestedge(&lcd->vc, &dist);
- if(!edge) {
- ringsel_exit(op);
- return OPERATOR_CANCELLED;
+ edge = EDBM_findnearestedge(&lcd->vc, &dist);
+ if (edge != lcd->eed) {
+ lcd->eed = edge;
+ ringsel_find_edge(lcd, 1);
}
- lcd->eed = edge;
- ringsel_find_edge(lcd, 1);
-
- ringsel_finish(C, op);
- ringsel_exit(op);
-
- return OPERATOR_FINISHED;
+ return OPERATOR_RUNNING_MODAL;
}
static int ringcut_invoke (bContext *C, wmOperator *op, wmEvent *evt)
{
Object *obedit= CTX_data_edit_object(C);
tringselOpData *lcd;
- EditEdge *edge;
+ BMEdge *edge;
int dist = 75;
if(modifiers_isDeformedByLattice(obedit) || modifiers_isDeformedByArmature(obedit))
@@ -415,7 +427,7 @@ static int ringcut_invoke (bContext *C, wmOperator *op, wmEvent *evt)
lcd->vc.mval[0] = evt->mval[0];
lcd->vc.mval[1] = evt->mval[1];
- edge = findnearestedge(&lcd->vc, &dist);
+ edge = EDBM_findnearestedge(&lcd->vc, &dist);
if (edge != lcd->eed) {
lcd->eed = edge;
ringsel_find_edge(lcd, 1);
@@ -425,7 +437,7 @@ static int ringcut_invoke (bContext *C, wmOperator *op, wmEvent *evt)
return OPERATOR_RUNNING_MODAL;
}
-static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event)
+static int ringsel_modal (bContext *C, wmOperator *op, wmEvent *event)
{
int cuts= RNA_int_get(op->ptr,"number_cuts");
tringselOpData *lcd= op->customdata;
@@ -434,13 +446,18 @@ static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event)
switch (event->type) {
- case LEFTMOUSE: /* confirm */ // XXX hardcoded
+ case LEFTMOUSE: /* abort */ // XXX hardcoded
+ ED_region_tag_redraw(lcd->ar);
+ ringsel_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ case RIGHTMOUSE: /* confirm */ // XXX hardcoded
if (event->val == KM_PRESS) {
/* finish */
ED_region_tag_redraw(lcd->ar);
ringsel_finish(C, op);
- ringsel_exit(op);
+ ringsel_exit(C, op);
ED_area_headerprint(CTX_wm_area(C), NULL);
return OPERATOR_FINISHED;
@@ -448,7 +465,6 @@ static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event)
ED_region_tag_redraw(lcd->ar);
break;
- case RIGHTMOUSE: /* abort */ // XXX hardcoded
case ESCKEY:
if (event->val == KM_RELEASE) {
/* cancel */
@@ -460,33 +476,94 @@ static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event)
ED_region_tag_redraw(lcd->ar);
break;
- case WHEELUPMOUSE: /* change number of cuts */
- case PAGEUPKEY:
- if (event->val == KM_PRESS) {
- cuts++;
- RNA_int_set(op->ptr, "number_cuts",cuts);
+ case MOUSEMOVE: { /* mouse moved somewhere to select another loop */
+ int dist = 75;
+ BMEdge *edge;
+
+ lcd->vc.mval[0] = event->mval[0];
+ lcd->vc.mval[1] = event->mval[1];
+ edge = EDBM_findnearestedge(&lcd->vc, &dist);
+
+ if (edge != lcd->eed) {
+ lcd->eed = edge;
ringsel_find_edge(lcd, cuts);
-
- ED_region_tag_redraw(lcd->ar);
}
+
+ ED_region_tag_redraw(lcd->ar);
break;
- case WHEELDOWNMOUSE: /* change number of cuts */
- case PAGEDOWNKEY:
- if (event->val == KM_PRESS) {
- cuts=MAX2(cuts-1,1);
- RNA_int_set(op->ptr,"number_cuts",cuts);
- ringsel_find_edge(lcd, cuts);
+ }
+ }
+
+ /* keep going until the user confirms */
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int loopcut_modal (bContext *C, wmOperator *op, wmEvent *event)
+{
+ int cuts= RNA_int_get(op->ptr,"number_cuts");
+ tringselOpData *lcd= op->customdata;
+
+ view3d_operator_needs_opengl(C);
+
+
+ switch (event->type) {
+ case LEFTMOUSE: /* confirm */ // XXX hardcoded
+ if (event->val == KM_RELEASE) {
+ /* finish */
+ ED_region_tag_redraw(lcd->ar);
+ ringsel_finish(C, op);
+ ringsel_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+
+ ED_region_tag_redraw(lcd->ar);
+ break;
+ case RIGHTMOUSE: /* abort */ // XXX hardcoded
+ ED_region_tag_redraw(lcd->ar);
+ ringsel_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ case ESCKEY:
+ if (event->val == KM_RELEASE) {
+ /* cancel */
ED_region_tag_redraw(lcd->ar);
+
+ return ringcut_cancel(C, op);
}
+
+ ED_region_tag_redraw(lcd->ar);
+ break;
+ case PAGEUPKEY:
+ case WHEELUPMOUSE: /* change number of cuts */
+ if (event->val == KM_RELEASE)
+ break;
+
+ cuts++;
+ RNA_int_set(op->ptr,"number_cuts",cuts);
+ ringsel_find_edge(lcd, cuts);
+
+ ED_region_tag_redraw(lcd->ar);
+ break;
+ case PAGEDOWNKEY:
+ case WHEELDOWNMOUSE: /* change number of cuts */
+ if (event->val == KM_RELEASE)
+ break;
+
+ cuts=MAX2(cuts-1,1);
+ RNA_int_set(op->ptr,"number_cuts",cuts);
+ ringsel_find_edge(lcd, cuts);
+
+ ED_region_tag_redraw(lcd->ar);
break;
case MOUSEMOVE: { /* mouse moved somewhere to select another loop */
int dist = 75;
- EditEdge *edge;
+ BMEdge *edge;
lcd->vc.mval[0] = event->mval[0];
lcd->vc.mval[1] = event->mval[1];
- edge = findnearestedge(&lcd->vc, &dist);
+ edge = EDBM_findnearestedge(&lcd->vc, &dist);
if (edge != lcd->eed) {
lcd->eed = edge;
@@ -511,10 +588,12 @@ void MESH_OT_edgering_select (wmOperatorType *ot)
/* callbacks */
ot->invoke= ringsel_invoke;
+ ot->modal= ringsel_modal;
+ ot->cancel= ringcut_cancel;
ot->poll= ED_operator_editmesh_region_view3d;
/* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
}
@@ -524,11 +603,11 @@ void MESH_OT_loopcut (wmOperatorType *ot)
/* description */
ot->name= "Loop Cut";
ot->idname= "MESH_OT_loopcut";
- ot->description= "Add a new loop between existing loops";
+ ot->description= "Add a new loop between existing loops.";
/* callbacks */
ot->invoke= ringcut_invoke;
- ot->modal= ringcut_modal;
+ ot->modal= loopcut_modal;
ot->cancel= ringcut_cancel;
ot->poll= ED_operator_editmesh_region_view3d;
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index f1123fdabcb..0ae3076170c 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -51,6 +51,7 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_report.h"
+#include "BKE_tessmesh.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -67,15 +68,27 @@
#include "mesh_intern.h"
+#define GET_CD_DATA(me, data) (me->edit_btmesh ? &me->edit_btmesh->bm->data : &me->data)
+
static void delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *layer)
{
Mesh *me = ob->data;
- CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata;
+ CustomData *data;
void *actlayerdata, *rndlayerdata, *clonelayerdata, *stencillayerdata, *layerdata=layer->data;
int type= layer->type;
- int index= CustomData_get_layer_index(data, type);
- int i, actindex, rndindex, cloneindex, stencilindex;
+ int index;
+ int i, actindex, rndindex, cloneindex, stencilindex, tot;
+
+ if (layer->type == CD_MLOOPCOL || layer->type == CD_MLOOPUV) {
+ data = (me->edit_btmesh)? &me->edit_btmesh->bm->ldata: &me->ldata;
+ tot = me->totloop;
+ } else {
+ data = (me->edit_btmesh)? &me->edit_btmesh->bm->pdata: &me->pdata;
+ tot = me->totpoly;
+ }
+ index = CustomData_get_layer_index(data, type);
+
/* ok, deleting a non-active layer needs to preserve the active layer indices.
to do this, we store a pointer to the .data member of both layer and the active layer,
(to detect if we're deleting the active layer or not), then use the active
@@ -89,15 +102,15 @@ static void delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *la
stencillayerdata = data->layers[CustomData_get_stencil_layer_index(data, type)].data;
CustomData_set_layer_active(data, type, layer - &data->layers[index]);
- if(me->edit_mesh) {
- EM_free_data_layer(me->edit_mesh, data, type);
+ if(me->edit_btmesh) {
+ BM_free_data_layer(me->edit_btmesh->bm, data, type);
}
else {
- CustomData_free_layer_active(data, type, me->totface);
+ CustomData_free_layer_active(data, type, tot);
mesh_update_customdata_pointers(me);
}
- if(!CustomData_has_layer(data, type) && (type == CD_MCOL && (ob->mode & OB_MODE_VERTEX_PAINT)))
+ if(!CustomData_has_layer(data, type) && (type == CD_MLOOPCOL && (ob->mode & OB_MODE_VERTEX_PAINT)))
ED_object_toggle_modes(C, OB_MODE_VERTEX_PAINT);
/* reconstruct active layer */
@@ -160,33 +173,44 @@ static void delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *la
int ED_mesh_uv_texture_add(bContext *C, Mesh *me, const char *name, int active_set)
{
- EditMesh *em;
+ BMEditMesh *em;
int layernum;
- if(me->edit_mesh) {
- em= me->edit_mesh;
+ if(me->edit_btmesh) {
+ em= me->edit_btmesh;
- layernum= CustomData_number_of_layers(&em->fdata, CD_MTFACE);
+ layernum= CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY);
if(layernum >= MAX_MTFACE)
return 0;
- EM_add_data_layer(em, &em->fdata, CD_MTFACE, name);
+ BM_add_data_layer(em->bm, &em->bm->pdata, CD_MTEXPOLY);
+ CustomData_set_layer_active(&em->bm->pdata, CD_MTEXPOLY, layernum);
+ if(active_set || layernum==0)
+ CustomData_set_layer_active(&em->bm->pdata, CD_MTEXPOLY, layernum);
+
+ BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPUV);
+ CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPUV, layernum);
if(active_set || layernum==0)
- CustomData_set_layer_active(&em->fdata, CD_MTFACE, layernum);
+ CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPUV, layernum);
}
else {
- layernum= CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ layernum= CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
if(layernum >= MAX_MTFACE)
return 0;
- if(me->mtface)
- CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DUPLICATE, me->mtface, me->totface, name);
- else
- CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface, name);
-
- if(active_set || layernum==0)
- CustomData_set_layer_active(&me->fdata, CD_MTFACE, layernum);
-
+ if(me->mtpoly) {
+ CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DUPLICATE, me->mtpoly, me->totpoly, name);
+ CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DUPLICATE, me->mloopuv, me->totloop, name);
+ } else {
+ CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, name);
+ CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, name);
+ }
+
+ if(active_set || layernum==0) {
+ CustomData_set_layer_active(&me->pdata, CD_MTEXPOLY, layernum);
+ CustomData_set_layer_active(&me->ldata, CD_MLOOPUV, layernum);
+ }
+
mesh_update_customdata_pointers(me);
}
@@ -198,17 +222,22 @@ int ED_mesh_uv_texture_add(bContext *C, Mesh *me, const char *name, int active_s
int ED_mesh_uv_texture_remove(bContext *C, Object *ob, Mesh *me)
{
- CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata;
- CustomDataLayer *cdl;
+ CustomData *pdata = GET_CD_DATA(me, pdata), *ldata = GET_CD_DATA(me, ldata);
+ CustomDataLayer *cdlp, *cdlu;
int index;
- index= CustomData_get_active_layer_index(data, CD_MTFACE);
- cdl= (index == -1) ? NULL: &data->layers[index];
+ index= CustomData_get_active_layer_index(pdata, CD_MTEXPOLY);
+ cdlp= (index == -1)? NULL: &pdata->layers[index];
- if(!cdl)
+ index= CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
+ cdlu= (index == -1)? NULL: &ldata->layers[index];
+
+ if (!cdlp || !cdlu)
return 0;
- delete_customdata_layer(C, ob, cdl);
+ delete_customdata_layer(C, ob, cdlp);
+ delete_customdata_layer(C, ob, cdlu);
+
DAG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
@@ -217,40 +246,45 @@ int ED_mesh_uv_texture_remove(bContext *C, Object *ob, Mesh *me)
int ED_mesh_color_add(bContext *C, Scene *scene, Object *ob, Mesh *me, const char *name, int active_set)
{
- EditMesh *em;
- MCol *mcol;
+ BMEditMesh *em;
+ MLoopCol *mcol;
int layernum;
- if(me->edit_mesh) {
- em= me->edit_mesh;
+ if(me->edit_btmesh) {
+ em= me->edit_btmesh;
- layernum= CustomData_number_of_layers(&em->fdata, CD_MCOL);
+ layernum= CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL);
if(layernum >= MAX_MCOL)
return 0;
- EM_add_data_layer(em, &em->fdata, CD_MCOL, name);
+ BM_add_data_layer(em->bm, &em->bm->pdata, CD_MLOOPCOL);
+ CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum);
+
if(active_set || layernum==0)
- CustomData_set_layer_active(&em->fdata, CD_MCOL, layernum);
+ CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum);
+
}
else {
- layernum= CustomData_number_of_layers(&me->fdata, CD_MCOL);
- if(layernum >= MAX_MCOL)
+ layernum= CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
+ if(layernum >= CD_MLOOPCOL)
return 0;
- mcol= me->mcol;
+ mcol= me->mloopcol;
- if(me->mcol)
- CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DUPLICATE, me->mcol, me->totface, name);
+ if(me->mloopcol)
+ CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DUPLICATE, me->mloopcol, me->totloop, name);
else
- CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface, name);
+ CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop, name);
if(active_set || layernum==0)
- CustomData_set_layer_active(&me->fdata, CD_MCOL, layernum);
+ CustomData_set_layer_active(&me->ldata, CD_MLOOPCOL, layernum);
mesh_update_customdata_pointers(me);
+ /*BMESH_TODO
if(!mcol)
shadeMeshMCol(scene, ob, me);
+ */
}
DAG_id_tag_update(&me->id, 0);
@@ -261,12 +295,11 @@ int ED_mesh_color_add(bContext *C, Scene *scene, Object *ob, Mesh *me, const cha
int ED_mesh_color_remove(bContext *C, Object *ob, Mesh *me)
{
- CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata;
CustomDataLayer *cdl;
int index;
- index= CustomData_get_active_layer_index(data, CD_MCOL);
- cdl= (index == -1)? NULL: &data->layers[index];
+ index= CustomData_get_active_layer_index(&me->ldata, CD_MLOOPCOL);
+ cdl= (index == -1)? NULL: &me->ldata.layers[index];
if(!cdl)
return 0;
@@ -347,25 +380,25 @@ static int drop_named_image_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_CANCELLED;
}
- /* turn mesh in editmode */
- /* BKE_mesh_get/end_editmesh: ED_uvedit_assign_image also calls this */
+ /* put mesh in editmode */
obedit= base->object;
me= obedit->data;
- if(me->edit_mesh==NULL) {
- make_editMesh(scene, obedit);
+ if(me->edit_btmesh==NULL) {
+ EDBM_MakeEditBMesh(scene->toolsettings, scene, obedit);
exitmode= 1;
}
- if(me->edit_mesh==NULL)
+
+ if(me->edit_btmesh==NULL)
return OPERATOR_CANCELLED;
ED_uvedit_assign_image(scene, obedit, ima, NULL);
if(exitmode) {
- load_editMesh(scene, obedit);
- free_editMesh(me->edit_mesh);
- MEM_freeN(me->edit_mesh);
- me->edit_mesh= NULL;
+ EDBM_LoadEditBMesh(scene, obedit);
+ EDBM_FreeEditBMesh(me->edit_btmesh);
+ MEM_freeN(me->edit_btmesh);
+ me->edit_btmesh= NULL;
}
/* dummie drop support; ensure view shows a result :) */
@@ -661,7 +694,7 @@ static void mesh_add_faces(Mesh *mesh, int len)
/*
void ED_mesh_geometry_add(Mesh *mesh, ReportList *reports, int verts, int edges, int faces)
{
- if(mesh->edit_mesh) {
+ if(mesh->edit_btmesh) {
BKE_report(reports, RPT_ERROR, "Can't add geometry in edit mode.");
return;
}
@@ -677,19 +710,18 @@ void ED_mesh_geometry_add(Mesh *mesh, ReportList *reports, int verts, int edges,
void ED_mesh_faces_add(Mesh *mesh, ReportList *reports, int count)
{
- if(mesh->edit_mesh) {
+ if(mesh->edit_btmesh) {
BKE_report(reports, RPT_ERROR, "Can't add faces in edit mode.");
return;
}
-
mesh_add_faces(mesh, count);
}
void ED_mesh_edges_add(Mesh *mesh, ReportList *reports, int count)
{
- if(mesh->edit_mesh) {
+ if(mesh->edit_btmesh) {
BKE_report(reports, RPT_ERROR, "Can't add edges in edit mode.");
- return;
+ return;
}
mesh_add_edges(mesh, count);
@@ -697,7 +729,7 @@ void ED_mesh_edges_add(Mesh *mesh, ReportList *reports, int count)
void ED_mesh_vertices_add(Mesh *mesh, ReportList *reports, int count)
{
- if(mesh->edit_mesh) {
+ if(mesh->edit_btmesh) {
BKE_report(reports, RPT_ERROR, "Can't add vertices in edit mode.");
return;
}
@@ -709,3 +741,4 @@ void ED_mesh_calc_normals(Mesh *me)
{
mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
}
+
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 1ed9598e0b4..ba5f87f47a2 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -32,15 +32,67 @@
#ifndef MESH_INTERN_H
#define MESH_INTERN_H
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BKE_tessmesh.h"
+
+#include "BLI_editVert.h"
+
+#include "RNA_types.h"
+
struct bContext;
struct wmOperatorType;
+struct ViewContext;
+struct BMEditMesh;
+struct BMesh;
+struct BMEdge;
+struct BMFace;
struct wmOperator;
+/* ******************** bmeshutils.c */
+
+/*
+ok: the EDBM module is for editmode bmesh stuff. in contrast, the
+ BMEdit module is for code shared with blenkernel that concerns
+ the BMEditMesh structure.
+*/
+
+/*calls a bmesh op, reporting errors to the user, etc*/
+int EDBM_CallOpf(struct BMEditMesh *em, struct wmOperator *op, const char *fmt, ...);
+
+/*calls a bmesh op, reporting errors to the user, etc.
+
+ selects an output slot specified by selslot*/
+//int EDBM_CallAndSelectOpf(struct BMEditMesh *em, struct wmOperator *op, char *selslot, char *fmt, ...);
+//moved to ED_mesh.h
+
+/*same as above, but doesn't report errors.*/
+int EDBM_CallOpfSilent(struct BMEditMesh *em, const char *fmt, ...);
+
+/*these next two functions are the split version of EDBM_CallOpf, so you can
+ do stuff with a bmesh operator, after initializing it but before executing
+ it.
+
+ execute the operator with BM_Exec_Op*/
+int EDBM_InitOpf(struct BMEditMesh *em, struct BMOperator *bmop,
+ struct wmOperator *op, const char *fmt, ...);
+/*cleans up after a bmesh operator*/
+int EDBM_FinishOp(struct BMEditMesh *em, struct BMOperator *bmop,
+ struct wmOperator *op, int report);
+
+void EDBM_clear_flag_all(struct BMEditMesh *em, int flag);
+void EDBM_store_selection(struct BMEditMesh *em, void *data);
+void EDBM_validate_selections(struct BMEditMesh *em);
+void EDBM_remove_selection(struct BMEditMesh *em, void *data);
+void EDBM_stats_update(struct BMEditMesh *em);
+
/* ******************** editface.c */
-int edgetag_context_check(Scene *scene, EditEdge *eed);
-void edgetag_context_set(Scene *scene, EditEdge *eed, int val);
-int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge *target);
+int edgetag_context_check(Scene *scene, BMEditMesh *em, BMEdge *eed);
+void edgetag_context_set(BMEditMesh *em, Scene *scene, BMEdge *eed, int val);
+int edgetag_shortest_path(Scene *scene, BMEditMesh *em, BMEdge *source, BMEdge *target);
/* ******************* editmesh.c */
@@ -48,6 +100,10 @@ extern void free_editvert(EditMesh *em, EditVert *eve);
extern void free_editedge(EditMesh *em, EditEdge *eed);
extern void free_editface(EditMesh *em, EditFace *efa);;
+/*frees dst mesh, then copies the contents of
+ *src (the struct) to dst. */
+void set_editMesh(EditMesh *dst, EditMesh *src);
+
extern void free_vertlist(EditMesh *em, ListBase *edve);
extern void free_edgelist(EditMesh *em, ListBase *lb);
extern void free_facelist(EditMesh *em, ListBase *lb);
@@ -59,7 +115,7 @@ extern struct EditEdge *addedgelist(EditMesh *em, struct EditVert *v1, struct Ed
extern struct EditFace *addfacelist(EditMesh *em, struct EditVert *v1, struct EditVert *v2, struct EditVert *v3, struct EditVert *v4, struct EditFace *example, struct EditFace *exampleEdges);
extern struct EditEdge *findedgelist(EditMesh *em, struct EditVert *v1, struct EditVert *v2);
-void em_setup_viewcontext(struct bContext *C, ViewContext *vc);
+void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc);
void MESH_OT_separate(struct wmOperatorType *ot);
@@ -138,12 +194,15 @@ void MESH_OT_knife_cut(struct wmOperatorType *ot);
/* ******************* editmesh_mods.c */
void MESH_OT_loop_select(struct wmOperatorType *ot);
void MESH_OT_select_all(struct wmOperatorType *ot);
+void MESH_OT_bmesh_test(struct wmOperatorType *ot);
void MESH_OT_select_more(struct wmOperatorType *ot);
void MESH_OT_select_less(struct wmOperatorType *ot);
void MESH_OT_select_inverse(struct wmOperatorType *ot);
void MESH_OT_select_non_manifold(struct wmOperatorType *ot);
void MESH_OT_select_linked(struct wmOperatorType *ot);
void MESH_OT_select_linked_pick(struct wmOperatorType *ot);
+void MESH_OT_pin(struct wmOperatorType *ot);
+void MESH_OT_unpin(struct wmOperatorType *ot);
void MESH_OT_hide(struct wmOperatorType *ot);
void MESH_OT_reveal(struct wmOperatorType *ot);
void MESH_OT_select_by_number_vertices(struct wmOperatorType *ot);
@@ -163,28 +222,6 @@ void MESH_OT_flip_normals(struct wmOperatorType *ot);
void MESH_OT_solidify(struct wmOperatorType *ot);
void MESH_OT_select_nth(struct wmOperatorType *ot);
-
-extern EditEdge *findnearestedge(ViewContext *vc, int *dist);
-void editmesh_select_by_material(EditMesh *em, int index);
-void EM_recalc_normal_direction(EditMesh *em, int inside, int select); /* makes faces righthand turning */
-void EM_select_more(EditMesh *em);
-void selectconnected_mesh_all(EditMesh *em);
-void faceloop_select(EditMesh *em, EditEdge *startedge, int select);
-
-/**
- * findnearestvert
- *
- * dist (in/out): minimal distance to the nearest and at the end, actual distance
- * sel: selection bias
- * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
- * if 0, unselected vertice are given the bias
- * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
- */
-extern EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short strict);
-
-
-/* ******************* editmesh_tools.c */
-
#define SUBDIV_SELECT_ORIG 0
#define SUBDIV_SELECT_INNER 1
#define SUBDIV_SELECT_INNER_SEL 2
@@ -227,9 +264,12 @@ void MESH_OT_region_to_loop(struct wmOperatorType *ot);
void MESH_OT_select_axis(struct wmOperatorType *ot);
void MESH_OT_uvs_rotate(struct wmOperatorType *ot);
-void MESH_OT_uvs_mirror(struct wmOperatorType *ot);
+//void MESH_OT_uvs_mirror(struct wmOperatorType *ot);
+void MESH_OT_uvs_reverse(struct wmOperatorType *ot);
void MESH_OT_colors_rotate(struct wmOperatorType *ot);
-void MESH_OT_colors_mirror(struct wmOperatorType *ot);
+//void MESH_OT_colors_mirror(struct wmOperatorType *ot);
+
+void MESH_OT_colors_reverse(struct wmOperatorType *ot);
void MESH_OT_delete(struct wmOperatorType *ot);
void MESH_OT_rip(struct wmOperatorType *ot);
@@ -248,8 +288,19 @@ void MESH_OT_sticky_add(struct wmOperatorType *ot);
void MESH_OT_sticky_remove(struct wmOperatorType *ot);
void MESH_OT_drop_named_image(struct wmOperatorType *ot);
+/* ************* bmesh_tools.c ***********/
+void MESH_OT_vert_connect(struct wmOperatorType *ot);
+void MESH_OT_edge_split(struct wmOperatorType *ot);
+void MESH_OT_extrude_region(struct wmOperatorType *ot);
+void MESH_OT_extrude_verts_indiv(struct wmOperatorType *ot);
+void MESH_OT_extrude_edges_indiv(struct wmOperatorType *ot);
+void MESH_OT_extrude_faces_indiv(struct wmOperatorType *ot);
+void MESH_OT_bm_test(struct wmOperatorType *ot);
+
void MESH_OT_edgering_select(struct wmOperatorType *ot);
void MESH_OT_loopcut(struct wmOperatorType *ot);
+void MESH_OT_knifetool(struct wmOperatorType *ot);
+
#endif // MESH_INTERN_H
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index ef68f6e89a0..519a77fa4aa 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -82,16 +82,18 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_primitive_monkey_add);
WM_operatortype_append(MESH_OT_primitive_uv_sphere_add);
WM_operatortype_append(MESH_OT_primitive_ico_sphere_add);
- WM_operatortype_append(MESH_OT_fgon_clear);
- WM_operatortype_append(MESH_OT_fgon_make);
WM_operatortype_append(MESH_OT_duplicate);
WM_operatortype_append(MESH_OT_remove_doubles);
WM_operatortype_append(MESH_OT_vertices_sort);
WM_operatortype_append(MESH_OT_vertices_randomize);
- WM_operatortype_append(MESH_OT_extrude);
WM_operatortype_append(MESH_OT_spin);
WM_operatortype_append(MESH_OT_screw);
-
+
+ WM_operatortype_append(MESH_OT_extrude_region);
+ WM_operatortype_append(MESH_OT_extrude_faces_indiv);
+ WM_operatortype_append(MESH_OT_extrude_edges_indiv);
+ WM_operatortype_append(MESH_OT_extrude_verts_indiv);
+
WM_operatortype_append(MESH_OT_split);
WM_operatortype_append(MESH_OT_extrude_repeat);
WM_operatortype_append(MESH_OT_edge_rotate);
@@ -101,9 +103,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_select_axis);
WM_operatortype_append(MESH_OT_uvs_rotate);
- WM_operatortype_append(MESH_OT_uvs_mirror);
WM_operatortype_append(MESH_OT_colors_rotate);
- WM_operatortype_append(MESH_OT_colors_mirror);
WM_operatortype_append(MESH_OT_fill);
WM_operatortype_append(MESH_OT_beautify_fill);
@@ -112,7 +112,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_edge_flip);
WM_operatortype_append(MESH_OT_faces_shade_smooth);
WM_operatortype_append(MESH_OT_faces_shade_flat);
- WM_operatortype_append(MESH_OT_sort_faces);
+ //WM_operatortype_append(MESH_OT_sort_faces);
WM_operatortype_append(MESH_OT_delete);
@@ -146,6 +146,8 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_solidify);
WM_operatortype_append(MESH_OT_select_nth);
+ WM_operatortype_append(MESH_OT_vert_connect);
+ WM_operatortype_append(MESH_OT_knifetool);
}
#if 0 /* UNUSED, remove? */
@@ -153,7 +155,7 @@ static int ED_operator_editmesh_face_select(bContext *C)
{
Object *obedit= CTX_data_edit_object(C);
if(obedit && obedit->type==OB_MESH) {
- EditMesh *em = ((Mesh *)obedit->data)->edit_mesh;
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
if (em && em->selectmode & SCE_SELECT_FACE) {
return 1;
}
@@ -188,31 +190,28 @@ void ED_operatormacros_mesh(void)
ot= WM_operatortype_append_macro("MESH_OT_extrude_region_move", "Extrude Region and Move", OPTYPE_UNDO|OPTYPE_REGISTER);
ot->description = "Extrude region and move result";
- otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude");
- RNA_enum_set(otmacro->ptr, "type", 1);
+ otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude_region");
otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_enum_set(otmacro->ptr, "proportional", 0);
RNA_boolean_set(otmacro->ptr, "mirror", 0);
ot= WM_operatortype_append_macro("MESH_OT_extrude_faces_move", "Extrude Individual Faces and Move", OPTYPE_UNDO|OPTYPE_REGISTER);
ot->description = "Extrude faces and move result";
- otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude");
- RNA_enum_set(otmacro->ptr, "type", 2);
+ otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude_faces_indiv");
otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_shrink_fatten");
RNA_enum_set(otmacro->ptr, "proportional", 0);
RNA_boolean_set(otmacro->ptr, "mirror", 0);
ot= WM_operatortype_append_macro("MESH_OT_extrude_edges_move", "Extrude Only Edges and Move", OPTYPE_UNDO|OPTYPE_REGISTER);
ot->description = "Extrude edges and move result";
- otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude");
- RNA_enum_set(otmacro->ptr, "type", 3);
+ otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude_edges_indiv");
otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_enum_set(otmacro->ptr, "proportional", 0);
RNA_boolean_set(otmacro->ptr, "mirror", 0);
ot= WM_operatortype_append_macro("MESH_OT_extrude_vertices_move", "Extrude Only Vertices and Move", OPTYPE_UNDO|OPTYPE_REGISTER);
ot->description = "Extrude vertices and move result";
- otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude");
+ otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude_verts_indiv");
RNA_enum_set(otmacro->ptr, "type", 4);
otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_enum_set(otmacro->ptr, "proportional", 0);
@@ -277,7 +276,7 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "MESH_OT_fill", FKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "MESH_OT_beautify_fill", FKEY, KM_PRESS, KM_SHIFT|KM_ALT, 0);
- WM_keymap_add_item(keymap, "MESH_OT_sort_faces", FKEY, KM_PRESS, KM_ALT|KM_CTRL, 0);
+ //WM_keymap_add_item(keymap, "MESH_OT_sort_faces", FKEY, KM_PRESS, KM_ALT|KM_CTRL, 0);
WM_keymap_add_item(keymap, "MESH_OT_quads_convert_to_tris", TKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "MESH_OT_tris_convert_to_quads", JKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "MESH_OT_edge_flip", FKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
@@ -295,7 +294,7 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
WM_keymap_add_menu(keymap, "INFO_MT_mesh_add", AKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "MESH_OT_separate", PKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MESH_OT_split", YKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "MESH_OT_vert_connect", YKEY, KM_PRESS, 0, 0);
/* use KM_CLICK because same key is used for tweaks */
WM_keymap_add_item(keymap, "MESH_OT_dupli_extrude_cursor", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0);
@@ -304,8 +303,8 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "MESH_OT_delete", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "MESH_OT_delete", DELKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MESH_OT_knife_cut", LEFTMOUSE, KM_PRESS, 0, KKEY);
- RNA_enum_set(WM_keymap_add_item(keymap, "MESH_OT_knife_cut", LEFTMOUSE, KM_PRESS, KM_SHIFT, KKEY)->ptr, "type", 2/*KNIFE_MIDPOINT*/);
+ WM_keymap_add_item(keymap, "MESH_OT_knifetool", KKEY, KM_PRESS, 0, 0);
+ //RNA_enum_set(WM_keymap_add_item(keymap, "MESH_OT_knife_cut", LEFTMOUSE, KM_PRESS, KM_SHIFT, KKEY)->ptr, "type", 2/*KNIFE_MIDPOINT*/);
WM_keymap_add_item(keymap, "OBJECT_OT_vertex_parent_set", PKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index a7d6cfee6c3..153153552bd 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -63,6 +63,7 @@
#include "BKE_mesh.h"
#include "BKE_material.h"
#include "BKE_report.h"
+#include "BKE_tessmesh.h"
#include "BKE_multires.h"
#include "BLO_sys_types.h" // for intptr_t support
@@ -76,14 +77,14 @@
/* own include */
#include "mesh_intern.h"
-
+#include "uvedit_intern.h"
/* * ********************** no editmode!!! *********** */
/*********************** JOIN ***************************/
/* join selected meshes into the active mesh, context sensitive
-return 0 if no join is made (error) and 1 of the join is done */
+return 0 if no join is made (error) and 1 if the join is done */
int join_mesh_exec(bContext *C, wmOperator *op)
{
@@ -95,15 +96,17 @@ int join_mesh_exec(bContext *C, wmOperator *op)
MVert *mvert, *mv;
MEdge *medge = NULL;
MFace *mface = NULL;
+ MPoly *mpoly = NULL;
+ MLoop *mloop = NULL;
Key *key, *nkey=NULL;
KeyBlock *kb, *okb, *kbn;
float imat[4][4], cmat[4][4], *fp1, *fp2, curpos;
int a, b, totcol, totmat=0, totedge=0, totvert=0, totface=0, ok=0;
- int vertofs, *matmap=NULL;
- int i, j, index, haskey=0, edgeofs, faceofs;
+ int totloop=0, totpoly=0, vertofs, *matmap=NULL;
+ int i, j, index, haskey=0, edgeofs, faceofs, loopofs, polyofs;
bDeformGroup *dg, *odg;
MDeformVert *dvert;
- CustomData vdata, edata, fdata;
+ CustomData vdata, edata, fdata, ldata, pdata;
if(scene->obedit) {
BKE_report(op->reports, RPT_WARNING, "Cant join while in editmode");
@@ -124,6 +127,8 @@ int join_mesh_exec(bContext *C, wmOperator *op)
totvert+= me->totvert;
totedge+= me->totedge;
totface+= me->totface;
+ totloop+= me->totloop;
+ totpoly+= me->totpoly;
totmat+= base->object->totcol;
if(base->object == ob)
@@ -276,14 +281,20 @@ int join_mesh_exec(bContext *C, wmOperator *op)
memset(&vdata, 0, sizeof(vdata));
memset(&edata, 0, sizeof(edata));
memset(&fdata, 0, sizeof(fdata));
+ memset(&ldata, 0, sizeof(ldata));
+ memset(&pdata, 0, sizeof(pdata));
mvert= CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
medge= CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
mface= CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface);
+ mloop= CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloop);
+ mpoly= CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpoly);
vertofs= 0;
edgeofs= 0;
faceofs= 0;
+ loopofs= 0;
+ polyofs= 0;
/* inverse transform for all selected meshes in this object */
invert_m4_m4(imat, ob->obmat);
@@ -436,14 +447,48 @@ int join_mesh_exec(bContext *C, wmOperator *op)
medge->v1+= vertofs;
medge->v2+= vertofs;
}
+ }
+
+ if (me->totloop) {
+ CustomData_merge(&me->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloop);
+ CustomData_copy_data(&me->ldata, &ldata, 0, loopofs, me->totloop);
- edgeofs += me->totedge;
+ for(a=0; a<me->totloop; a++, mloop++) {
+ mloop->v += vertofs;
+ mloop->e += edgeofs;
+ }
}
- /* vertofs is used to help newly added verts be reattached to their edge/face
- * (cannot be set earlier, or else reattaching goes wrong)
+ if(me->totpoly) {
+ /* make mapping for materials */
+ for(a=1; a<=base->object->totcol; a++) {
+ ma= give_current_material(base->object, a);
+
+ for(b=0; b<totcol; b++) {
+ if(ma == matar[b]) {
+ matmap[a-1]= b;
+ break;
+ }
+ }
+ }
+
+ CustomData_merge(&me->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpoly);
+ CustomData_copy_data(&me->pdata, &pdata, 0, polyofs, me->totpoly);
+
+ for(a=0; a<me->totpoly; a++, mpoly++) {
+ mpoly->loopstart += loopofs;
+ mpoly->mat_nr= matmap[(int)mpoly->mat_nr];
+ }
+
+ polyofs += me->totpoly;
+ }
+
+ /* these are used for relinking (cannot be set earlier,
+ * or else reattaching goes wrong)
*/
vertofs += me->totvert;
+ edgeofs += me->totedge;
+ loopofs += me->totloop;
/* free base, now that data is merged */
if(base->object != ob)
@@ -458,14 +503,20 @@ int join_mesh_exec(bContext *C, wmOperator *op)
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
me->totvert= totvert;
me->totedge= totedge;
me->totface= totface;
+ me->totloop= totloop;
+ me->totpoly= totpoly;
me->vdata= vdata;
me->edata= edata;
me->fdata= fdata;
+ me->ldata= ldata;
+ me->pdata= pdata;
mesh_update_customdata_pointers(me);
@@ -524,11 +575,11 @@ int join_mesh_exec(bContext *C, wmOperator *op)
ED_object_exit_editmode(C, EM_FREEDATA|EM_WAITCURSOR|EM_DO_UNDO);
#else
/* toggle editmode using lower level functions so this can be called from python */
- make_editMesh(scene, ob);
- load_editMesh(scene, ob);
- free_editMesh(me->edit_mesh);
- MEM_freeN(me->edit_mesh);
- me->edit_mesh= NULL;
+ EDBM_MakeEditBMesh(scene->toolsettings, scene, ob);
+ EDBM_LoadEditBMesh(scene, ob);
+ EDBM_FreeEditBMesh(me->edit_btmesh);
+ MEM_freeN(me->edit_btmesh);
+ me->edit_btmesh= NULL;
DAG_id_tag_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA);
#endif
WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
@@ -755,7 +806,7 @@ static struct {
/* mode is 's' start, or 'e' end, or 'u' use */
/* if end, ob can be NULL */
-intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode)
+intptr_t mesh_octree_table(Object *ob, BMEditMesh *em, float *co, char mode)
{
MocNode **bt;
@@ -781,10 +832,11 @@ intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode)
* we are using the undeformed coordinates*/
INIT_MINMAX(min, max);
- if(em && me->edit_mesh==em) {
- EditVert *eve;
+ if(em && me->edit_btmesh==em) {
+ BMIter iter;
+ BMVert *eve;
- for(eve= em->verts.first; eve; eve= eve->next)
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL)
DO_MINMAX(eve->co, min, max)
}
else {
@@ -816,10 +868,11 @@ intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode)
MeshOctree.table= MEM_callocN(MOC_RES*MOC_RES*MOC_RES*sizeof(void *), "sym table");
- if(em && me->edit_mesh==em) {
- EditVert *eve;
+ if(em && me->edit_btmesh==em) {
+ BMVert *eve;
+ BMIter iter;
- for(eve= em->verts.first; eve; eve= eve->next) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
mesh_octree_add_nodes(MeshOctree.table, eve->co, MeshOctree.offs, MeshOctree.div, (intptr_t)(eve));
}
}
@@ -881,27 +934,23 @@ long mesh_mirrtopo_table(Object *ob, char mode)
Mesh *me= ob->data;
if( (mesh_topo_lookup==NULL) ||
(mesh_topo_lookup_mode != ob->mode) ||
- (me->edit_mesh && me->edit_mesh->totvert != mesh_topo_lookup_tot) ||
- (me->edit_mesh==NULL && me->totvert != mesh_topo_lookup_tot)
+ (me->edit_btmesh && me->edit_btmesh->bm->totvert != mesh_topo_lookup_tot) ||
+ (me->edit_btmesh==NULL && me->totvert != mesh_topo_lookup_tot)
) {
mesh_mirrtopo_table(ob, 's');
}
} else if(mode=='s') { /* start table */
Mesh *me= ob->data;
MEdge *medge;
- EditMesh *em= me->edit_mesh;
- void **eve_tmp_back= NULL; /* some of the callers are using eve->tmp so restore after */
-
-
- /* editmode*/
- EditEdge *eed;
-
- int a, last, totvert;
- int totUnique= -1, totUniqueOld= -1;
-
+ BMEditMesh *em= me->edit_btmesh;
+ BMEdge *eed;
+ BMIter iter;
MIRRHASH_TYPE *MirrTopoHash = NULL;
MIRRHASH_TYPE *MirrTopoHash_Prev = NULL;
MirrTopoPair *MirrTopoPairs;
+ int a, last, totvert;
+ int totUnique= -1, totUniqueOld= -1;
+
mesh_topo_lookup_mode= ob->mode;
/* reallocate if needed */
@@ -911,12 +960,12 @@ long mesh_mirrtopo_table(Object *ob, char mode)
}
if(em) {
- EditVert *eve;
+ BMVert *eve;
+
totvert= 0;
- eve_tmp_back= MEM_callocN( em->totvert * sizeof(void *), "TopoMirr" );
- for(eve= em->verts.first; eve; eve= eve->next) {
- eve_tmp_back[totvert]= eve->tmp.p;
- eve->tmp.l = totvert++;
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(eve, totvert);
+ totvert++;
}
}
else {
@@ -927,9 +976,9 @@ long mesh_mirrtopo_table(Object *ob, char mode)
/* Initialize the vert-edge-user counts used to detect unique topology */
if(em) {
- for(eed=em->edges.first; eed; eed= eed->next) {
- MirrTopoHash[eed->v1->tmp.l]++;
- MirrTopoHash[eed->v2->tmp.l]++;
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ MirrTopoHash[BMINDEX_GET(eed->v1)]++;
+ MirrTopoHash[BMINDEX_GET(eed->v2)]++;
}
} else {
for(a=0, medge=me->medge; a<me->totedge; a++, medge++) {
@@ -945,9 +994,9 @@ long mesh_mirrtopo_table(Object *ob, char mode)
/* use the number of edges per vert to give verts unique topology IDs */
if(em) {
- for(eed=em->edges.first; eed; eed= eed->next) {
- MirrTopoHash[eed->v1->tmp.l] += MirrTopoHash_Prev[eed->v2->tmp.l];
- MirrTopoHash[eed->v2->tmp.l] += MirrTopoHash_Prev[eed->v1->tmp.l];
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ MirrTopoHash[BMINDEX_GET(eed->v1)] += MirrTopoHash_Prev[BMINDEX_GET(eed->v2)];
+ MirrTopoHash[BMINDEX_GET(eed->v2)] += MirrTopoHash_Prev[BMINDEX_GET(eed->v1)];
}
} else {
for(a=0, medge=me->medge; a<me->totedge; a++, medge++) {
@@ -979,19 +1028,6 @@ long mesh_mirrtopo_table(Object *ob, char mode)
memcpy(MirrTopoHash_Prev, MirrTopoHash, sizeof(MIRRHASH_TYPE) * totvert);
}
- /* restore eve->tmp.* */
- if(eve_tmp_back) {
- EditVert *eve;
- totvert= 0;
- for(eve= em->verts.first; eve; eve= eve->next) {
- eve->tmp.p= eve_tmp_back[totvert++];
- }
-
- MEM_freeN(eve_tmp_back);
- eve_tmp_back= NULL;
- }
-
-
/* Hash/Index pairs are needed for sorting to find index pairs */
MirrTopoPairs= MEM_callocN( sizeof(MirrTopoPair) * totvert, "MirrTopoPairs");
@@ -999,7 +1035,7 @@ long mesh_mirrtopo_table(Object *ob, char mode)
mesh_topo_lookup = MEM_mallocN( totvert * sizeof(long), "mesh_topo_lookup" );
if(em) {
- EM_init_index_arrays(em,1,0,0);
+ EDBM_init_index_arrays(em,1,0,0);
}
@@ -1023,8 +1059,8 @@ long mesh_mirrtopo_table(Object *ob, char mode)
if ((a==totvert) || (MirrTopoPairs[a-1].hash != MirrTopoPairs[a].hash)) {
if (a-last==2) {
if(em) {
- mesh_topo_lookup[MirrTopoPairs[a-1].vIndex] = (long)EM_get_vert_for_index(MirrTopoPairs[a-2].vIndex);
- mesh_topo_lookup[MirrTopoPairs[a-2].vIndex] = (long)EM_get_vert_for_index(MirrTopoPairs[a-1].vIndex);
+ mesh_topo_lookup[MirrTopoPairs[a-1].vIndex] = (long)EDBM_get_vert_for_index(em, MirrTopoPairs[a-2].vIndex);
+ mesh_topo_lookup[MirrTopoPairs[a-2].vIndex] = (long)EDBM_get_vert_for_index(em, MirrTopoPairs[a-1].vIndex);
} else {
mesh_topo_lookup[MirrTopoPairs[a-1].vIndex] = MirrTopoPairs[a-2].vIndex;
mesh_topo_lookup[MirrTopoPairs[a-2].vIndex] = MirrTopoPairs[a-1].vIndex;
@@ -1034,7 +1070,7 @@ long mesh_mirrtopo_table(Object *ob, char mode)
}
}
if(em) {
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
}
MEM_freeN( MirrTopoPairs );
@@ -1084,9 +1120,10 @@ int mesh_get_x_mirror_vert(Object *ob, int index)
} else {
return mesh_get_x_mirror_vert_spacial(ob, index);
}
+ return 0;
}
-static EditVert *editmesh_get_x_mirror_vert_spacial(Object *ob, EditMesh *em, float *co)
+static BMVert *editbmesh_get_x_mirror_vert_spacial(Object *ob, BMEditMesh *em, float *co)
{
float vec[3];
intptr_t poinval;
@@ -1104,20 +1141,28 @@ static EditVert *editmesh_get_x_mirror_vert_spacial(Object *ob, EditMesh *em, fl
poinval= mesh_octree_table(ob, em, vec, 'u');
if(poinval != -1)
- return (EditVert *)(poinval);
+ return (BMVert *)(poinval);
return NULL;
}
-static EditVert *editmesh_get_x_mirror_vert_topo(Object *ob, struct EditMesh *em, EditVert *eve, int index)
+static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob, struct BMEditMesh *em, BMVert *eve, int index)
{
long poinval;
if (mesh_mirrtopo_table(ob, 'u')==-1)
return NULL;
if (index == -1) {
- index = BLI_findindex(&em->verts, eve);
-
- if (index == -1) {
+ BMIter iter;
+ BMVert *v;
+
+ index = 0;
+ BM_ITER(v, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (v == eve)
+ break;
+ index++;
+ }
+
+ if (index == em->bm->totvert) {
return NULL;
}
}
@@ -1125,22 +1170,23 @@ static EditVert *editmesh_get_x_mirror_vert_topo(Object *ob, struct EditMesh *em
poinval= mesh_topo_lookup[ index ];
if(poinval != -1)
- return (EditVert *)(poinval);
+ return (BMVert *)(poinval);
return NULL;
}
-EditVert *editmesh_get_x_mirror_vert(Object *ob, struct EditMesh *em, EditVert *eve, float *co, int index)
+BMVert *editbmesh_get_x_mirror_vert(Object *ob, struct BMEditMesh *em, BMVert *eve, float *co, int index)
{
+ //BMESH_TODO use this flag, ME_EDIT_MIRROR_TOPO, at appropriate places
if (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_TOPO) {
- return editmesh_get_x_mirror_vert_topo(ob, em, eve, index);
+ return editbmesh_get_x_mirror_vert_topo(ob, em, eve, index);
} else {
- return editmesh_get_x_mirror_vert_spacial(ob, em, co);
+ return editbmesh_get_x_mirror_vert_spacial(ob, em, co);
}
}
-#if 0
-float *editmesh_get_mirror_uv(int axis, float *uv, float *mirrCent, float *face_cent)
+
+float *editmesh_get_mirror_uv(BMEditMesh *em, int axis, float *uv, float *mirrCent, float *face_cent)
{
float vec[2];
float cent_vec[2];
@@ -1168,26 +1214,29 @@ float *editmesh_get_mirror_uv(int axis, float *uv, float *mirrCent, float *face_
/* TODO - Optimize */
{
- EditFace *efa;
- int i, len;
- for(efa=em->faces.first; efa; efa=efa->next) {
- MTFace *tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- uv_center(tf->uv, cent, (void *)efa->v4);
-
+ BMIter iter;
+ BMFace *efa;
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ poly_uv_center(em, efa, cent);
+
if ( (fabs(cent[0] - cent_vec[0]) < 0.001) && (fabs(cent[1] - cent_vec[1]) < 0.001) ) {
- len = efa->v4 ? 4 : 3;
- for (i=0; i<len; i++) {
- if ( (fabs(tf->uv[i][0] - vec[0]) < 0.001) && (fabs(tf->uv[i][1] - vec[1]) < 0.001) ) {
- return tf->uv[i];
- }
+ BMIter liter;
+ BMLoop *l;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ if ( (fabs(luv->uv[0] - vec[0]) < 0.001) && (fabs(luv->uv[1] - vec[1]) < 0.001) ) {
+ return luv->uv;
+
}
}
}
}
+ }
return NULL;
}
-#endif
static unsigned int mirror_facehash(const void *ptr)
{
@@ -1235,7 +1284,7 @@ static int mirror_facecmp(const void *a, const void *b)
return (mirror_facerotation((MFace*)a, (MFace*)b) == -1);
}
-int *mesh_get_x_mirror_faces(Object *ob, EditMesh *em)
+int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em)
{
Mesh *me= ob->data;
MVert *mv, *mvert= me->mvert;
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index da0fb256572..48750e9c6b8 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -550,7 +550,7 @@ static void freeMetaElemlist(ListBase *lb)
}
-static void undoMball_to_editMball(void *lbu, void *lbe)
+static void undoMball_to_editMball(void *lbu, void *lbe, void *obdata)
{
ListBase *lb= lbu;
ListBase *editelems= lbe;
@@ -568,7 +568,7 @@ static void undoMball_to_editMball(void *lbu, void *lbe)
}
-static void *editMball_to_undoMball(void *lbe)
+static void *editMball_to_undoMball(void *lbe, void *obdata)
{
ListBase *editelems= lbe;
ListBase *lb;
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index 47cb4d00938..edf3834002e 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenkernel
../../blenloader
../../blenlib
+ ../../bmesh
../../gpu
../../ikplugin
../../imbuf
diff --git a/source/blender/editors/object/SConscript b/source/blender/editors/object/SConscript
index 660643fbb0f..5db12f32d8b 100644
--- a/source/blender/editors/object/SConscript
+++ b/source/blender/editors/object/SConscript
@@ -5,7 +5,7 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc ../../blenloader'
-incs += ' ../../makesrna ../../python ../../ikplugin'
+incs += ' ../../makesrna ../../python ../../ikplugin ../../bmesh'
incs += ' ../../render/extern/include ../../gpu' # for object_bake.c
defs = []
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index c74d532c95f..c997baa3a30 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1803,7 +1803,6 @@ static int join_poll(bContext *C)
return 0;
}
-
static int join_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
@@ -1817,7 +1816,7 @@ static int join_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Can't edit external libdata.");
return OPERATOR_CANCELLED;
}
-
+
if(ob->type == OB_MESH)
return join_mesh_exec(C, op);
else if(ELEM(ob->type, OB_CURVE, OB_SURF))
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 2f90d722240..306f5f89275 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -382,7 +382,7 @@ static void test_constraints (Object *owner, bPoseChannel *pchan)
}
else if (curcon->type == CONSTRAINT_TYPE_SPLINEIK) {
bSplineIKConstraint *data = curcon->data;
-
+
/* if the number of points does not match the amount required by the chain length,
* free the points array and request a rebind...
*/
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index c07c770cf66..ba336ad388c 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -76,6 +76,7 @@
#include "BKE_sca.h"
#include "BKE_softbody.h"
#include "BKE_modifier.h"
+#include "BKE_tessmesh.h"
#include "ED_armature.h"
#include "ED_curve.h"
@@ -316,22 +317,24 @@ void ED_object_exit_editmode(bContext *C, int flag)
// if(retopo_mesh_paint_check())
// retopo_end_okee();
- if(me->edit_mesh->totvert>MESH_MAX_VERTS) {
+ if(me->edit_btmesh->bm->totvert>MESH_MAX_VERTS) {
error("Too many vertices");
return;
}
- load_editMesh(scene, obedit);
+
+ EDBM_LoadEditBMesh(scene, obedit);
if(freedata) {
- free_editMesh(me->edit_mesh);
- MEM_freeN(me->edit_mesh);
- me->edit_mesh= NULL;
+ EDBM_FreeEditBMesh(me->edit_btmesh);
+ MEM_freeN(me->edit_btmesh);
+ me->edit_btmesh= NULL;
}
-
+#if 0 //BMESH_TODO
if(obedit->restore_mode & OB_MODE_WEIGHT_PAINT) {
mesh_octree_table(NULL, NULL, NULL, 'e');
mesh_mirrtopo_table(NULL, 'e');
}
+#endif
}
else if (obedit->type==OB_ARMATURE) {
ED_armature_from_edit(obedit);
@@ -371,7 +374,7 @@ void ED_object_exit_editmode(bContext *C, int flag)
}
BLI_freelistN(&pidlist);
- BKE_ptcache_object_reset(scene, obedit, PTCACHE_RESET_OUTDATED);
+ BKE_ptcache_object_reset(scene, obedit, PTCACHE_RESET_DEPSGRAPH);
/* also flush ob recalc, doesn't take much overhead, but used for particles */
DAG_id_tag_update(&obedit->id, OB_RECALC_OB|OB_RECALC_DATA);
@@ -407,7 +410,7 @@ void ED_object_enter_editmode(bContext *C, int flag)
if(base==NULL) return;
else if(v3d && (base->lay & v3d->lay)==0) return;
- else if(!v3d && (base->lay & scene->lay)==0) return;
+ else if(!v3d && (base->lay & scene->lay)==0) return;
}
else {
base= scene->basact;
@@ -440,7 +443,7 @@ void ED_object_enter_editmode(bContext *C, int flag)
ok= 1;
scene->obedit= ob; // context sees this
- make_editMesh(scene, ob);
+ EDBM_MakeEditBMesh(CTX_data_tool_settings(C), scene, ob);
WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_MESH, scene);
}
@@ -1839,7 +1842,7 @@ static void ofs_timeoffs(Scene *scene, View3D *v3d)
ob->sf += offset;
if (ob->sf < -MAXFRAMEF) ob->sf = -MAXFRAMEF;
else if (ob->sf > MAXFRAMEF) ob->sf = MAXFRAMEF;
- }
+ }
CTX_DATA_END;
}
@@ -1922,11 +1925,16 @@ static int object_mode_set_compat(bContext *UNUSED(C), wmOperator *op, Object *o
{
ObjectMode mode = RNA_enum_get(op->ptr, "mode");
- if(ob) {
- if(mode == OB_MODE_OBJECT)
- return 1;
+ if(mode == OB_MODE_OBJECT)
+ return 1;
+ if(ob) {
switch(ob->type) {
+ case OB_EMPTY:
+ case OB_LAMP:
+ case OB_CAMERA:
+ return 0;
+
case OB_MESH:
if(mode & (OB_MODE_EDIT|OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT|OB_MODE_PARTICLE_EDIT))
return 1;
@@ -1935,14 +1943,14 @@ static int object_mode_set_compat(bContext *UNUSED(C), wmOperator *op, Object *o
case OB_SURF:
case OB_FONT:
case OB_MBALL:
- if(mode & (OB_MODE_EDIT))
+ if(mode & (OB_MODE_OBJECT|OB_MODE_EDIT))
return 1;
return 0;
case OB_LATTICE:
- if(mode & (OB_MODE_EDIT|OB_MODE_WEIGHT_PAINT))
+ if(mode & (OB_MODE_OBJECT|OB_MODE_EDIT|OB_MODE_WEIGHT_PAINT))
return 1;
case OB_ARMATURE:
- if(mode & (OB_MODE_EDIT|OB_MODE_POSE))
+ if(mode & (OB_MODE_OBJECT|OB_MODE_EDIT|OB_MODE_POSE))
return 1;
}
}
@@ -1958,7 +1966,7 @@ static int object_mode_set_exec(bContext *C, wmOperator *op)
int toggle = RNA_boolean_get(op->ptr, "toggle");
if(!ob || !object_mode_set_compat(C, op, ob))
- return OPERATOR_PASS_THROUGH;
+ return OPERATOR_CANCELLED;
/* Exit current mode if it's not the mode we're setting */
if(ob->mode != OB_MODE_OBJECT && ob->mode != mode)
@@ -1999,7 +2007,7 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
/* flags */
ot->flag= 0; /* no register/undo here, leave it to operators being called */
- prop= RNA_def_enum(ot->srna, "mode", object_mode_items, OB_MODE_OBJECT, "Mode", "");
+ prop= RNA_def_enum(ot->srna, "mode", object_mode_items, 0, "Mode", "");
RNA_def_enum_funcs(prop, object_mode_set_itemsf);
RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index a0b6e28191c..aeb26035722 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -51,6 +51,7 @@
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_tessmesh.h"
#include "RNA_define.h"
#include "RNA_access.h"
@@ -67,13 +68,14 @@
#include "object_intern.h"
-static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float *cent)
+static int return_editmesh_indexar(BMEditMesh *em, int *tot, int **indexar, float *cent)
{
- EditVert *eve;
+ BMVert *eve;
+ BMIter iter;
int *index, nr, totvert=0;
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) totvert++;
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if(BM_TestHFlag(eve, BM_SELECT)) totvert++;
}
if(totvert==0) return 0;
@@ -82,8 +84,8 @@ static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float
nr= 0;
cent[0]= cent[1]= cent[2]= 0.0;
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if(BM_TestHFlag(eve, BM_SELECT)) {
*index= nr; index++;
add_v3_v3(cent, eve->co);
}
@@ -95,10 +97,11 @@ static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float
return totvert;
}
-static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, float *cent)
+static int return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *name, float *cent)
{
MDeformVert *dvert;
- EditVert *eve;
+ BMVert *eve;
+ BMIter iter;
int i, totvert=0;
cent[0]= cent[1]= cent[2]= 0.0;
@@ -106,8 +109,8 @@ static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, floa
if(obedit->actdef) {
/* find the vertices */
- for(eve= em->verts.first; eve; eve= eve->next) {
- dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
if(dvert) {
for(i=0; i<dvert->totweight; i++){
@@ -129,25 +132,27 @@ static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, floa
return 0;
}
-static void select_editmesh_hook(Object *ob, HookModifierData *hmd)
+static void select_editbmesh_hook(Object *ob, HookModifierData *hmd)
{
Mesh *me= ob->data;
- EditMesh *em= BKE_mesh_get_editmesh(me);
- EditVert *eve;
+ BMEditMesh *em= me->edit_btmesh;
+ BMVert *eve;
+ BMIter iter;
int index=0, nr=0;
if (hmd->indexar == NULL)
return;
- for(eve= em->verts.first; eve; eve= eve->next, nr++) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
if(nr==hmd->indexar[index]) {
- eve->f |= SELECT;
+ BM_Select(em->bm, eve, 1);
if(index < hmd->totindex-1) index++;
}
+
+ nr++;
}
- EM_select_flush(em);
- BKE_mesh_end_editmesh(me, em);
+ EDBM_selectmode_flush(em);
}
static int return_editlattice_indexar(Lattice *editlatt, int *tot, int **indexar, float *cent)
@@ -297,15 +302,13 @@ static int object_hook_index_array(Object *obedit, int *tot, int **indexar, char
case OB_MESH:
{
Mesh *me= obedit->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
+ BMEditMesh *em = me->edit_btmesh;
/* check selected vertices first */
if( return_editmesh_indexar(em, tot, indexar, cent_r)) {
- BKE_mesh_end_editmesh(me, em);
return 1;
} else {
int ret = return_editmesh_vgroup(obedit, em, name, cent_r);
- BKE_mesh_end_editmesh(me, em);
return ret;
}
}
@@ -374,7 +377,7 @@ static void object_hook_select(Object *ob, HookModifierData *hmd)
if (hmd->indexar == NULL)
return;
- if(ob->type==OB_MESH) select_editmesh_hook(ob, hmd);
+ if(ob->type==OB_MESH) select_editbmesh_hook(ob, hmd);
else if(ob->type==OB_LATTICE) select_editlattice_hook(ob, hmd);
else if(ob->type==OB_CURVE) select_editcurve_hook(ob, hmd);
else if(ob->type==OB_SURF) select_editcurve_hook(ob, hmd);
diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c
index e4e23b05a7e..97794e18e4d 100644
--- a/source/blender/editors/object/object_lattice.c
+++ b/source/blender/editors/object/object_lattice.c
@@ -362,7 +362,7 @@ typedef struct UndoLattice {
int pntsu, pntsv, pntsw;
} UndoLattice;
-static void undoLatt_to_editLatt(void *data, void *edata)
+static void undoLatt_to_editLatt(void *data, void *edata, void *obdata)
{
UndoLattice *ult= (UndoLattice*)data;
EditLatt *editlatt= (EditLatt *)edata;
@@ -371,7 +371,7 @@ static void undoLatt_to_editLatt(void *data, void *edata)
memcpy(editlatt->latt->def, ult->def, a*sizeof(BPoint));
}
-static void *editLatt_to_undoLatt(void *edata)
+static void *editLatt_to_undoLatt(void *edata, void *obdata)
{
UndoLattice *ult= MEM_callocN(sizeof(UndoLattice), "UndoLattice");
EditLatt *editlatt= (EditLatt *)edata;
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 96953736f69..95771c9e5f9 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -62,6 +62,7 @@
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_softbody.h"
+#include "BKE_tessmesh.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -201,15 +202,15 @@ int ED_object_modifier_remove(ReportList *reports, Main *bmain, Scene *scene, Ob
else if(md->type == eModifierType_Multires) {
Mesh *me= ob->data;
- if(me->edit_mesh) {
- EditMesh *em= me->edit_mesh;
+ if(me->edit_btmesh) {
+ BMEditMesh *em= me->edit_btmesh;
/* CustomData_external_remove is used here only to mark layer as non-external
for further free-ing, so zero element count looks safer than em->totface */
- CustomData_external_remove(&em->fdata, &me->id, CD_MDISPS, 0);
- EM_free_data_layer(em, &em->fdata, CD_MDISPS);
+ CustomData_external_remove(&em->bm->ldata, &me->id, CD_MDISPS, 0);
+ BM_free_data_layer(em, &em->bm->ldata, CD_MDISPS);
} else {
- CustomData_external_remove(&me->fdata, &me->id, CD_MDISPS, me->totface);
- CustomData_free_layer_active(&me->fdata, CD_MDISPS, me->totface);
+ CustomData_external_remove(&me->ldata, &me->id, CD_MDISPS, me->totloop);
+ CustomData_free_layer_active(&me->ldata, CD_MDISPS, me->totloop);
}
}
@@ -377,6 +378,17 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, ModifierData *md)
{
+ /*
+ It should be ridiculously easy to extract the original verts that we want
+ and form the shape data. We can probably use the CD KEYINDEX layer (or
+ whatever I ended up calling it, too tired to check now), though this would
+ by necassity have to make some potentially ugly assumptions about the order
+ of the mesh data :-/ you can probably assume in 99% of cases that the first
+ element of a given index is the original, and any subsequent duplicates are
+ copies/interpolates, but that's an assumption that would need to be tested
+ and then predominantly stated in comments in a half dozen headers.
+ */
+
if (ob->type==OB_MESH) {
DerivedMesh *dm;
Mesh *me= ob->data;
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 43057108b60..b3b1d9123aa 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -71,6 +71,7 @@
#include "BKE_sca.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
+#include "BKE_tessmesh.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -103,7 +104,8 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
Main *bmain= CTX_data_main(C);
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
- EditVert *eve;
+ BMVert *eve;
+ BMIter iter;
Curve *cu;
Nurb *nu;
BezTriple *bezt;
@@ -115,22 +117,17 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
if(obedit->type==OB_MESH) {
Mesh *me= obedit->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
+ BMEditMesh *em = me->edit_btmesh;
- eve= em->verts.first;
- while(eve) {
- if(eve->f & 1) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_SELECT)) {
if(v1==0) v1= nr;
else if(v2==0) v2= nr;
else if(v3==0) v3= nr;
else if(v4==0) v4= nr;
else break;
}
- nr++;
- eve= eve->next;
}
-
- BKE_mesh_end_editmesh(me, em);
}
else if(ELEM(obedit->type, OB_SURF, OB_CURVE)) {
ListBase *editnurb= curve_get_editcurve(obedit);
@@ -952,7 +949,7 @@ static int track_set_exec(bContext *C, wmOperator *op)
Object *obact= ED_object_active_context(C);
int type= RNA_enum_get(op->ptr, "type");
-
+
if(type == 1) {
bConstraint *con;
bDampTrackConstraint *data;
@@ -1130,6 +1127,8 @@ static int move_to_layer_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, scene);
WM_event_add_notifier(C, NC_SCENE|ND_LAYER_CONTENT, scene);
+ WM_event_add_notifier(C, NC_SCENE|ND_LAYER_CONTENT, scene);
+
DAG_scene_sort(bmain, scene);
return OPERATOR_FINISHED;
@@ -1190,7 +1189,7 @@ static int make_links_scene_exec(bContext *C, wmOperator *op)
if(scene_to == CTX_data_scene(C)) {
BKE_report(op->reports, RPT_ERROR, "Can't link objects into the same scene");
return OPERATOR_CANCELLED;
- }
+ }
if(scene_to->id.lib) {
BKE_report(op->reports, RPT_ERROR, "Can't link objects into a linked scene");
@@ -1201,11 +1200,11 @@ static int make_links_scene_exec(bContext *C, wmOperator *op)
{
if(!object_in_scene(base->object, scene_to)) {
Base *nbase= MEM_mallocN( sizeof(Base), "newbase");
- *nbase= *base;
+ *nbase= *base;
BLI_addhead( &(scene_to->base), nbase);
- id_us_plus((ID *)base->object);
- }
- }
+ id_us_plus((ID *)base->object);
+ }
+ }
CTX_DATA_END;
DAG_ids_flush_update(bmain, 0);
@@ -1295,7 +1294,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
object_link_modifiers(obt, ob);
obt->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME;
break;
- }
+ }
}
}
}
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index 8cd0ee81f21..e3c3a4372c1 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -184,10 +184,10 @@ static int object_shape_key_mirror(bContext *C, Object *ob)
Mesh *me= ob->data;
MVert *mv;
- mesh_octree_table(ob, NULL, NULL, 's');
+ //BMESH_TODO mesh_octree_table(ob, NULL, NULL, 's');
for(i1=0, mv=me->mvert; i1<me->totvert; i1++, mv++) {
- i2= mesh_get_x_mirror_vert(ob, i1);
+ i2= -1; //BMESH_TODO mesh_get_x_mirror_vert(ob, i1);
if(i2==i1) {
fp1= ((float *)kb->data) + i1*3;
fp1[0] = -fp1[0];
@@ -210,7 +210,7 @@ static int object_shape_key_mirror(bContext *C, Object *ob)
}
}
- mesh_octree_table(ob, NULL, NULL, 'e');
+ //BMESH_TODO mesh_octree_table(ob, NULL, NULL, 'e');
}
/* todo, other types? */
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 48d12982691..92040cdbf03 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -48,6 +48,7 @@
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "BKE_tessmesh.h"
#include "BKE_multires.h"
#include "RNA_define.h"
@@ -727,45 +728,44 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
if(v3d && !RNA_property_is_set(op->ptr, "around"))
around= v3d->around;
}
-
zero_v3(cent);
if(obedit) {
- INIT_MINMAX(min, max);
-
- if(obedit->type==OB_MESH) {
+ INIT_MINMAX(min, max);
+
+ if(obedit->type==OB_MESH) {
Mesh *me= obedit->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
- EditVert *eve;
-
- if(around==V3D_CENTROID) {
- int total= 0;
- for(eve= em->verts.first; eve; eve= eve->next) {
- total++;
- add_v3_v3(cent, eve->co);
- }
- if(total) {
- mul_v3_fl(cent, 1.0f/(float)total);
- }
- }
- else {
- for(eve= em->verts.first; eve; eve= eve->next) {
- DO_MINMAX(eve->co, min, max);
+ BMEditMesh *em = me->edit_btmesh;
+ BMVert *eve;
+ BMIter iter;
+ int total = 0;
+
+ if(centermode == ORIGIN_TO_CURSOR) {
+ copy_v3_v3(cent, cursor);
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_m4_v3(obedit->imat, cent);
+ } else {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if(around==V3D_CENTROID) {
+ total++;
+ add_v3_v3(cent, eve->co);
+ mul_v3_fl(cent, 1.0f/(float)total);
+ }
+ else {
+ DO_MINMAX(eve->co, min, max);
+ mid_v3_v3v3(cent, min, max);
+ }
}
- mid_v3_v3v3(cent, min, max);
}
-
- if(!is_zero_v3(cent)) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- sub_v3_v3(eve->co, cent);
- }
-
- recalc_editnormals(em);
- tot_change++;
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ sub_v3_v3(eve->co, cent);
}
- BKE_mesh_end_editmesh(me, em);
- }
+
+ EDBM_RecalcNormals(em);
+ tot_change++;
+ DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ }
}
/* reset flags */
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index b6baca5733f..b568edad636 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -38,6 +38,7 @@
#include "DNA_curve_types.h"
#include "DNA_lattice_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
@@ -45,7 +46,7 @@
#include "DNA_particle_types.h"
#include "BLI_blenlib.h"
-#include "BLI_editVert.h"
+#include "BLI_cellalloc.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
@@ -54,6 +55,7 @@
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
+#include "BKE_tessmesh.h"
#include "BKE_report.h"
#include "RNA_access.h"
@@ -86,7 +88,7 @@ static Lattice *vgroup_edit_lattice(Object *ob)
int ED_vgroup_object_is_edit_mode(Object *ob)
{
if(ob->type == OB_MESH)
- return (((Mesh*)ob->data)->edit_mesh != NULL);
+ return (((Mesh*)ob->data)->edit_btmesh != NULL);
else if(ob->type == OB_LATTICE)
return (((Lattice*)ob->data)->editlatt != NULL);
@@ -158,25 +160,27 @@ static int ED_vgroup_give_parray(ID *id, MDeformVert ***dvert_arr, int *dvert_to
{
Mesh *me = (Mesh *)id;
- if(me->edit_mesh) {
- EditMesh *em = me->edit_mesh;
- EditVert *eve;
+ if(me->edit_btmesh) {
+ BMEditMesh *em = me->edit_btmesh;
+ BMIter iter;
+ BMVert *eve;
int i;
- if (!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
+ if (!CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) {
*dvert_tot = 0;
*dvert_arr = NULL;
return 0;
}
- i= BLI_countlist(&em->verts);
+ i = em->bm->totvert;
*dvert_arr= MEM_mallocN(sizeof(void*)*i, "vgroup parray from me");
*dvert_tot = i;
i = 0;
- for (eve=em->verts.first; eve; eve=eve->next, i++) {
- (*dvert_arr)[i] = CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ (*dvert_arr)[i] = CustomData_em_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
+ i++;
}
return 1;
@@ -347,13 +351,13 @@ static void ED_vgroup_nr_vert_remove(Object *ob, int def_nr, int vertnum)
* deform weight, and reshuffle the others
*/
if(dvert->totweight) {
- newdw = MEM_mallocN(sizeof(MDeformWeight)*(dvert->totweight),
+ newdw = BLI_cellalloc_malloc(sizeof(MDeformWeight)*(dvert->totweight),
"deformWeight");
if(dvert->dw){
memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*i);
memcpy(newdw+i, dvert->dw+i+1,
sizeof(MDeformWeight)*(dvert->totweight-i));
- MEM_freeN(dvert->dw);
+ BLI_cellalloc_free(dvert->dw);
}
dvert->dw=newdw;
}
@@ -443,11 +447,11 @@ static void ED_vgroup_nr_vert_add(Object *ob, int def_nr, int vertnum, float wei
/* if we are doing an additive assignment, then
* we need to create the deform weight
*/
- newdw = MEM_callocN(sizeof(MDeformWeight)*(dv->totweight+1),
+ newdw = BLI_cellalloc_calloc(sizeof(MDeformWeight)*(dv->totweight+1),
"deformWeight");
if(dv->dw){
memcpy(newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight);
- MEM_freeN(dv->dw);
+ BLI_cellalloc_free(dv->dw);
}
dv->dw=newdw;
@@ -499,10 +503,11 @@ void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
ED_vgroup_nr_vert_remove(ob, def_nr, vertnum);
}
+
static float get_vert_def_nr(Object *ob, int def_nr, int vertnum)
{
MDeformVert *dvert= NULL;
- EditVert *eve;
+ BMVert *eve;
Mesh *me;
int i;
@@ -510,10 +515,10 @@ static float get_vert_def_nr(Object *ob, int def_nr, int vertnum)
if(ob->type==OB_MESH) {
me= ob->data;
- if(me->edit_mesh) {
- eve= BLI_findlink(&me->edit_mesh->verts, vertnum);
+ if(me->edit_btmesh) {
+ eve= BMIter_AtIndex(me->edit_btmesh->bm, BM_VERTS_OF_MESH, NULL, vertnum);
if(!eve) return 0.0f;
- dvert= CustomData_em_get(&me->edit_mesh->vdata, eve->data, CD_MDEFORMVERT);
+ dvert= CustomData_bmesh_get(&me->edit_btmesh->bm->vdata, eve->head.data, CD_MDEFORMVERT);
vertnum= 0;
}
else
@@ -560,34 +565,32 @@ void ED_vgroup_select_by_name(Object *ob, const char *name)
/* only in editmode */
static void vgroup_select_verts(Object *ob, int select)
{
- EditVert *eve;
+ BMVert *eve;
MDeformVert *dvert;
int i;
if(ob->type == OB_MESH) {
Mesh *me= ob->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
+ BMEditMesh *em = me->edit_btmesh;
+ BMIter iter;
- for(eve=em->verts.first; eve; eve=eve->next){
- dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
if(dvert && dvert->totweight){
for(i=0; i<dvert->totweight; i++){
if(dvert->dw[i].def_nr == (ob->actdef-1)){
- if(!eve->h) {
- if(select) eve->f |= SELECT;
- else eve->f &= ~SELECT;
+ if (!BM_TestHFlag(eve, BM_HIDDEN)) {
+ BM_Select(em->bm, eve, select);
+ break;
}
- break;
}
}
}
}
/* this has to be called, because this function operates on vertices only */
- if(select) EM_select_flush(em); // vertices to edges/faces
- else EM_deselect_flush(em);
-
- BKE_mesh_end_editmesh(me, em);
+ if(select) EDBM_selectmode_flush(em); // vertices to edges/faces
+ else EDBM_deselect_flush(em);
}
else if(ob->type == OB_LATTICE) {
Lattice *lt= vgroup_edit_lattice(ob);
@@ -854,12 +857,12 @@ static void vgroup_invert(Object *ob, int auto_assign, int auto_remove)
static void vgroup_blend(Object *ob)
{
+ BMEditMesh *em= ((Mesh *)ob->data)->edit_btmesh;
bDeformGroup *dg;
MDeformWeight *dw;
MDeformVert *dvert_array=NULL, *dvert;
int i, def_nr, dvert_tot=0;
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)ob->data));
// ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
if(em==NULL)
@@ -868,46 +871,47 @@ static void vgroup_blend(Object *ob)
dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
if(dg) {
- int sel1, sel2;
- int i1, i2;
-
- EditEdge *eed;
- EditVert *eve;
+ BMEdge *eed;
+ BMVert *eve;
+ BMIter iter;
float *vg_weights;
float *vg_users;
+ int sel1, sel2;
+ int i1, i2;
def_nr= ob->actdef-1;
i= 0;
- for(eve= em->verts.first; eve; eve= eve->next)
- eve->tmp.l= i++;
-
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(eve, i);
+ i++;
+ }
dvert_tot= i;
vg_weights= MEM_callocN(sizeof(float)*dvert_tot, "vgroup_blend_f");
vg_users= MEM_callocN(sizeof(int)*dvert_tot, "vgroup_blend_i");
- for(eed= em->edges.first; eed; eed= eed->next) {
- sel1= eed->v1->f & SELECT;
- sel2= eed->v2->f & SELECT;
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ sel1= BM_TestHFlag(eed->v1, BM_SELECT);
+ sel2= BM_TestHFlag(eed->v2, BM_SELECT);
if(sel1 != sel2) {
/* i1 is always the selected one */
if(sel1==TRUE && sel2==FALSE) {
- i1= eed->v1->tmp.l;
- i2= eed->v2->tmp.l;
+ i1= BMINDEX_GET(eed->v1);
+ i2= BMINDEX_GET(eed->v2);
eve= eed->v2;
}
else {
- i2= eed->v1->tmp.l;
- i1= eed->v2->tmp.l;
+ i2= BMINDEX_GET(eed->v1);
+ i1= BMINDEX_GET(eed->v2);
eve= eed->v1;
}
vg_users[i1]++;
/* TODO, we may want object mode blending */
- if(em) dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+ if(em) dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
else dvert= dvert_array+i2;
dw= defvert_find_index(dvert, def_nr);
@@ -919,10 +923,10 @@ static void vgroup_blend(Object *ob)
}
i= 0;
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT && vg_users[i] > 0) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if(BM_TestHFlag(eve, BM_SELECT) && vg_users[i] > 0) {
/* TODO, we may want object mode blending */
- if(em) dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+ if(em) dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
else dvert= dvert_array+i;
dw= defvert_verify_index(dvert, def_nr);
@@ -1000,7 +1004,7 @@ static void vgroup_clean_all(Object *ob, float eul, int keep_single)
void ED_vgroup_mirror(Object *ob, int mirror_weights, int flip_vgroups)
{
- EditVert *eve, *eve_mirr;
+ BMVert *eve, *eve_mirr;
MDeformVert *dvert, *dvert_mirr;
int *flip_map;
@@ -1010,8 +1014,9 @@ void ED_vgroup_mirror(Object *ob, int mirror_weights, int flip_vgroups)
/* only the active group */
if(ob->type == OB_MESH) {
Mesh *me= ob->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
-
+ BMEditMesh *em = me->edit_btmesh;
+ BMIter iter;
+#if 0 //BMESH_TODO
EM_cache_x_mirror_vert(ob, em);
if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT))
@@ -1057,6 +1062,7 @@ void ED_vgroup_mirror(Object *ob, int mirror_weights, int flip_vgroups)
MEM_freeN(flip_map);
BKE_mesh_end_editmesh(me, em);
+#endif
}
}
@@ -1150,12 +1156,11 @@ static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg)
ob->actdef= 1;
}
-
/* only in editmode */
/* removes from active defgroup, if allverts==0 only selected vertices */
static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGroup *dg)
{
- EditVert *eve;
+ BMVert *eve;
MDeformVert *dvert;
MDeformWeight *newdw;
bDeformGroup *eg;
@@ -1163,19 +1168,20 @@ static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGr
if(ob->type == OB_MESH) {
Mesh *me= ob->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
+ BMEditMesh *em = me->edit_btmesh;
+ BMIter iter;
- for(eve=em->verts.first; eve; eve=eve->next){
- dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
- if(dvert && dvert->dw && ((eve->f & SELECT) || allverts)){
+ if(dvert && dvert->dw && (BM_TestHFlag(eve, BM_SELECT) || allverts)){
for(i=0; i<dvert->totweight; i++){
/* Find group */
eg = BLI_findlink(&ob->defbase, dvert->dw[i].def_nr);
if(eg == dg){
dvert->totweight--;
- if(dvert->totweight){
- newdw = MEM_mallocN(sizeof(MDeformWeight)*(dvert->totweight), "deformWeight");
+ if (dvert->totweight){
+ newdw = BLI_cellalloc_malloc (sizeof(MDeformWeight)*(dvert->totweight), "deformWeight");
if(dvert->dw){
memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*i);
@@ -1185,7 +1191,7 @@ static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGr
dvert->dw=newdw;
}
else{
- MEM_freeN(dvert->dw);
+ BLI_cellalloc_free (dvert->dw);
dvert->dw=NULL;
break;
}
@@ -1193,7 +1199,6 @@ static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGr
}
}
}
- BKE_mesh_end_editmesh(me, em);
}
else if(ob->type == OB_LATTICE) {
Lattice *lt= vgroup_edit_lattice(ob);
@@ -1223,19 +1228,19 @@ static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *dg)
/* Make sure that any verts with higher indices are adjusted accordingly */
if(ob->type==OB_MESH) {
Mesh *me= ob->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
- EditVert *eve;
+ BMEditMesh *em = me->edit_btmesh;
+ BMIter iter;
+ BMVert *eve;
MDeformVert *dvert;
- for(eve=em->verts.first; eve; eve=eve->next){
- dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
if(dvert)
for(i=0; i<dvert->totweight; i++)
if(dvert->dw[i].def_nr > dg_index)
dvert->dw[i].def_nr--;
}
- BKE_mesh_end_editmesh(me, em);
}
else if(ob->type==OB_LATTICE) {
Lattice *lt= vgroup_edit_lattice(ob);
@@ -1285,7 +1290,7 @@ static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *dg)
static int vgroup_object_in_edit_mode(Object *ob)
{
if(ob->type == OB_MESH)
- return (((Mesh*)ob->data)->edit_mesh != NULL);
+ return (((Mesh*)ob->data)->edit_btmesh != NULL);
else if(ob->type == OB_LATTICE)
return (((Lattice*)ob->data)->editlatt != NULL);
@@ -1330,7 +1335,7 @@ static void vgroup_delete_all(Object *ob)
/* only in editmode */
static void vgroup_assign_verts(Object *ob, float weight)
{
- EditVert *eve;
+ BMVert *eve;
bDeformGroup *dg, *eg;
MDeformWeight *newdw;
MDeformVert *dvert;
@@ -1342,16 +1347,17 @@ static void vgroup_assign_verts(Object *ob, float weight)
if(ob->type == OB_MESH) {
Mesh *me= ob->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
+ BMEditMesh *em = me->edit_btmesh;
+ BMIter iter;
- if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT))
- EM_add_data_layer(em, &em->vdata, CD_MDEFORMVERT, NULL);
+ if(!CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT))
+ BM_add_data_layer(em->bm, &em->bm->vdata, CD_MDEFORMVERT);
/* Go through the list of editverts and assign them */
- for(eve=em->verts.first; eve; eve=eve->next){
- dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
- if(dvert && (eve->f & SELECT)){
+ if(dvert && BM_TestHFlag(eve, BM_SELECT)) {
/* See if this vert already has a reference to this group */
/* If so: Change its weight */
done=0;
@@ -1366,10 +1372,10 @@ static void vgroup_assign_verts(Object *ob, float weight)
}
/* If not: Add the group and set its weight */
if(!done){
- newdw = MEM_callocN(sizeof(MDeformWeight)*(dvert->totweight+1), "deformWeight");
+ newdw = BLI_cellalloc_calloc(sizeof(MDeformWeight)*(dvert->totweight+1), "deformWeight");
if(dvert->dw){
memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*dvert->totweight);
- MEM_freeN(dvert->dw);
+ BLI_cellalloc_free(dvert->dw);
}
dvert->dw=newdw;
@@ -1381,7 +1387,6 @@ static void vgroup_assign_verts(Object *ob, float weight)
}
}
}
- BKE_mesh_end_editmesh(me, em);
}
else if(ob->type == OB_LATTICE) {
Lattice *lt= vgroup_edit_lattice(ob);
@@ -2033,11 +2038,12 @@ static int vgroup_do_remap(Object *ob, char *name_array, wmOperator *op)
if(ob->mode == OB_MODE_EDIT) {
if(ob->type==OB_MESH) {
- EditMesh *em = BKE_mesh_get_editmesh(ob->data);
- EditVert *eve;
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMIter iter;
+ BMVert *eve;
- for(eve=em->verts.first; eve; eve=eve->next){
- dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
if(dvert && dvert->totweight){
defvert_remap(dvert, sort_map);
}
diff --git a/source/blender/editors/physics/SConscript b/source/blender/editors/physics/SConscript
index 274819c918c..b3425be7d35 100644
--- a/source/blender/editors/physics/SConscript
+++ b/source/blender/editors/physics/SConscript
@@ -5,7 +5,11 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
+<<<<<<< .working
+incs += ' ../../gpu ../../bmesh'
+=======
incs += ' ../../gpu ../../blenloader'
+>>>>>>> .merge-right.r35190
incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern'
defs = ''
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 9ea8dde058f..b5d07025ca5 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -1051,7 +1051,7 @@ static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
BLI_kdtree_free(edit->emitter_field);
- totface=dm->getNumFaces(dm);
+ totface=dm->getNumTessFaces(dm);
/*totvert=dm->getNumVerts(dm);*/ /*UNSUED*/
edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float),"emitter cosnos");
@@ -1062,7 +1062,7 @@ static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
nor=vec+3;
for(i=0; i<totface; i++, vec+=6, nor+=6) {
- MFace *mface=dm->getFaceData(dm,i,CD_MFACE);
+ MFace *mface=dm->getTessFaceData(dm,i,CD_MFACE);
MVert *mvert;
mvert=dm->getVertData(dm,mface->v1,CD_MVERT);
@@ -2676,7 +2676,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
if(!psmd->dm)
return;
- mirrorfaces= mesh_get_x_mirror_faces(ob, NULL);
+ //BMESH_TODO mirrorfaces= mesh_get_x_mirror_faces(ob, NULL);
if(!edit->mirror_cache)
PE_update_mirror_cache(ob, psys);
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index efd44c68db6..7f830478f2a 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -641,7 +641,7 @@ static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
if(psmd->dm->deformedOnly)
/* we don't want to mess up psmd->dm when converting to global coordinates below */
- dm= CDDM_copy(psmd->dm);
+ dm= CDDM_copy(psmd->dm, 0);
else
dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
@@ -667,7 +667,7 @@ static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
continue;
}
- mface = CDDM_get_face(dm,nearest.index);
+ mface = CDDM_get_tessface(dm,nearest.index);
copy_v3_v3(v[0], CDDM_get_vert(dm,mface->v1)->co);
copy_v3_v3(v[1], CDDM_get_vert(dm,mface->v2)->co);
diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt
index 3e3d42e9454..ec62588b8fa 100644
--- a/source/blender/editors/render/CMakeLists.txt
+++ b/source/blender/editors/render/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../blenloader
../../gpu
../../imbuf
+ ../../bmesh
../../makesdna
../../makesrna
../../render/extern/include
diff --git a/source/blender/editors/render/SConscript b/source/blender/editors/render/SConscript
index 2b9737557cd..bd6dcf73546 100644
--- a/source/blender/editors/render/SConscript
+++ b/source/blender/editors/render/SConscript
@@ -7,7 +7,7 @@ incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../gpu'
incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern'
-incs += ' ../../blenloader'
+incs += ' ../../blenloader ../../bmesh'
if env['OURPLATFORM'] == 'linux2':
cflags='-pthread'
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index c3b2ad38c46..e4e3ee7576c 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -60,6 +60,7 @@
#include "BKE_scene.h"
#include "BKE_texture.h"
#include "BKE_world.h"
+#include "BKE_tessmesh.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -329,13 +330,15 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
if(ob && ob->actcol>0) {
if(ob->type == OB_MESH) {
- EditMesh *em= ((Mesh*)ob->data)->edit_mesh;
- EditFace *efa;
+ BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh;
+ BMFace *efa;
+ BMIter iter;
if(em) {
- for(efa= em->faces.first; efa; efa=efa->next)
- if(efa->f & SELECT)
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if(BM_TestHFlag(efa, BM_SELECT))
efa->mat_nr= ob->actcol-1;
+ }
}
}
else if(ELEM(ob->type, OB_CURVE, OB_SURF)) {
@@ -387,14 +390,15 @@ static int material_slot_de_select(bContext *C, int select)
return OPERATOR_CANCELLED;
if(ob->type == OB_MESH) {
- EditMesh *em= ((Mesh*)ob->data)->edit_mesh;
-
+ BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh;
+/*BMESH_TODO
if(em) {
if(select)
EM_select_by_material(em, ob->actcol-1);
else
EM_deselect_by_material(em, ob->actcol-1);
}
+*/
}
else if ELEM(ob->type, OB_CURVE, OB_SURF) {
ListBase *nurbs= ED_curve_editnurbs((Curve*)ob->data);
diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt
index f276cc30c0f..5663a9ee750 100644
--- a/source/blender/editors/screen/CMakeLists.txt
+++ b/source/blender/editors/screen/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
../../blenkernel
../../blenloader
../../blenlib
+ ../../bmesh
../../imbuf
../../makesdna
../../makesrna
diff --git a/source/blender/editors/screen/Makefile b/source/blender/editors/screen/Makefile
new file mode 100644
index 00000000000..85b9e069620
--- /dev/null
+++ b/source/blender/editors/screen/Makefile
@@ -0,0 +1,68 @@
+#
+# $Id$
+#
+# ***** 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) 2007 Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL LICENSE BLOCK *****
+#
+# Makes module object directory and bounces make to subdirectories.
+
+LIBNAME = ed_screen
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I$(NAN_GLEW)/include
+CPPFLAGS += -I$(OPENGL_HEADERS)
+
+# not very neat....
+CPPFLAGS += -I../../windowmanager
+CPPFLAGS += -I../../blenloader
+CPPFLAGS += -I../../blenkernel
+CPPFLAGS += -I../../bmesh
+CPPFLAGS += -I../../blenlib
+CPPFLAGS += -I../../makesdna
+CPPFLAGS += -I../../makesrna
+CPPFLAGS += -I../../imbuf
+CPPFLAGS += -I../../python
+CPPFLAGS += -I../../render/extern/include
+CPPFLAGS += -I../../blenfont
+CPPFLAGS += -I../../gpu
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+
+# own include
+
+CPPFLAGS += -I../include
+
+ifeq ($(WITH_OPENEXR), true)
+ CPPFLAGS += -DWITH_OPENEXR
+endif
+
+ifeq ($(OS), darwin)
+ ifeq ($(WITH_BF_OPENMP), true)
+ CPPFLAGS += -DPARALLEL=1
+ endif
+endif
diff --git a/source/blender/editors/screen/SConscript b/source/blender/editors/screen/SConscript
index 61f3429521d..6370c9d3153 100644
--- a/source/blender/editors/screen/SConscript
+++ b/source/blender/editors/screen/SConscript
@@ -5,7 +5,7 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../blenfont ../../makesdna ../../imbuf'
incs += ' ../../blenloader ../../windowmanager ../../makesrna ../../gpu'
-incs += ' ../../render/extern/include'
+incs += ' ../../render/extern/include ../../bmesh'
incs += ' #/intern/guardedalloc #/extern/glew/include'
defs = ''
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 4f92cec39af..f2f11f42204 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -1424,8 +1424,8 @@ void ED_screen_set_scene(bContext *C, Scene *scene)
if(rv3d->persp==RV3D_CAMOB)
rv3d->persp= RV3D_PERSP;
- }
- }
+ }
+ }
}
}
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 75f28b6541f..2c9a11b2112 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -49,6 +49,7 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_tessmesh.h"
#include "BKE_sound.h"
#include "WM_api.h"
@@ -280,7 +281,7 @@ int ED_operator_editmesh(bContext *C)
{
Object *obedit= CTX_data_edit_object(C);
if(obedit && obedit->type==OB_MESH)
- return NULL != ((Mesh *)obedit->data)->edit_mesh;
+ return NULL != ((Mesh *)obedit->data)->edit_btmesh;
return 0;
}
@@ -327,24 +328,21 @@ int ED_operator_uvedit(bContext *C)
{
SpaceImage *sima= CTX_wm_space_image(C);
Object *obedit= CTX_data_edit_object(C);
+
return ED_space_image_show_uvedit(sima, obedit);
}
int ED_operator_uvmap(bContext *C)
{
Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= NULL;
+ BMEditMesh *em= NULL;
if(obedit && obedit->type==OB_MESH)
- em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ em= ((Mesh *)obedit->data)->edit_btmesh;
- if(em && (em->faces.first)) {
- BKE_mesh_end_editmesh(obedit->data, em);
+ if(em && (em->bm->totface))
return 1;
- }
- if(obedit)
- BKE_mesh_end_editmesh(obedit->data, em);
return 0;
}
@@ -2710,7 +2708,7 @@ int ED_screen_animation_play(bContext *C, int sync, int mode)
ScreenAnimData *sad= wt->customdata;
sad->ar= CTX_wm_region(C);
- }
+ }
}
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/sculpt_paint/SConscript b/source/blender/editors/sculpt_paint/SConscript
index 90b56ded2cd..6c1fe79d8bc 100644
--- a/source/blender/editors/sculpt_paint/SConscript
+++ b/source/blender/editors/sculpt_paint/SConscript
@@ -8,7 +8,11 @@ defs = []
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../render/extern/include'
+<<<<<<< .working
+incs += ' ../../gpu ../../makesrna ../../bmesh'
+=======
incs += ' ../../gpu ../../makesrna ../../blenloader'
+>>>>>>> .merge-right.r35190
if env['OURPLATFORM'] == 'linux2':
cflags='-pthread'
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 44dbe447d3e..72eb72e19f0 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -2852,11 +2852,11 @@ static void project_paint_begin(ProjPaintState *ps)
}
ps->dm_mvert = ps->dm->getVertArray(ps->dm);
- ps->dm_mface = ps->dm->getFaceArray(ps->dm);
- ps->dm_mtface= ps->dm->getFaceDataArray(ps->dm, CD_MTFACE);
+ ps->dm_mface = ps->dm->getTessFaceArray(ps->dm);
+ ps->dm_mtface= ps->dm->getTessFaceDataArray(ps->dm, CD_MTFACE);
ps->dm_totvert = ps->dm->getNumVerts(ps->dm);
- ps->dm_totface = ps->dm->getNumFaces(ps->dm);
+ ps->dm_totface = ps->dm->getNumTessFaces(ps->dm);
/* use clone mtface? */
@@ -2893,11 +2893,13 @@ static void project_paint_begin(ProjPaintState *ps)
ps->dm_mvert= MEM_dupallocN(ps->dm_mvert);
ps->dm_mface= MEM_dupallocN(ps->dm_mface);
/* looks like these are ok for now.*/
- /*
+
ps->dm_mtface= MEM_dupallocN(ps->dm_mtface);
- ps->dm_mtface_clone= MEM_dupallocN(ps->dm_mtface_clone);
- ps->dm_mtface_stencil= MEM_dupallocN(ps->dm_mtface_stencil);
- */
+ if (ps->dm_mtface_clone)
+ ps->dm_mtface_clone= MEM_dupallocN(ps->dm_mtface_clone);
+ if (ps->dm_mtface_stencil)
+ ps->dm_mtface_stencil= MEM_dupallocN(ps->dm_mtface_stencil);
+
}
ps->viewDir[0] = 0.0f;
@@ -4657,9 +4659,29 @@ static int texture_paint_init(bContext *C, wmOperator *op)
pop->orig_brush_size= brush_size(brush);
if(pop->mode != PAINT_MODE_2D) {
+ Mesh *me;
+
pop->s.ob = OBACT;
+ if (!pop->ps.ob)
+ pop->ps.ob = pop->s.ob;
+
pop->s.me = get_mesh(pop->s.ob);
if (!pop->s.me) return 0;
+
+ me = pop->s.me;
+
+ /*recalc mesh tesselation so the face origindex values point
+ to the tesselation faces themselves, instead of polys*/
+ me->totface = mesh_recalcTesselation(&me->fdata, &me->ldata,
+ &me->pdata, me->mvert, me->totface, me->totloop, me->totpoly, 0, 1);
+ mesh_update_customdata_pointers(me);
+
+ /*force customdata update*/
+ makeDerivedMesh(scene, pop->ps.ob, NULL, CD_MASK_BAREMESH);
+
+ /* Dont allow brush size below 2 */
+ if (pop->ps.brush && pop->ps.brush->size<=1)
+ pop->ps.brush->size = 2;
}
else {
pop->s.image = pop->s.sima->image;
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 000db4c28f2..9090093bd7c 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -144,9 +144,9 @@ static void imapaint_tri_weights(Object *ob, float *v1, float *v2, float *v3, fl
void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, int *xy, float *uv)
{
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
- int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
- MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf;
- int numfaces = dm->getNumFaces(dm), a, findex;
+ int *index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ MTFace *tface = dm->getTessFaceDataArray(dm, CD_MTFACE), *tf;
+ int numfaces = dm->getNumTessFaces(dm), a, findex;
float p[2], w[3], absw, minabsw;
MFace mf;
MVert mv[4];
@@ -159,7 +159,7 @@ void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, int *xy,
findex= (index)? index[a]: a;
if(findex == faceindex) {
- dm->getFace(dm, a, &mf);
+ dm->getTessFace(dm, a, &mf);
dm->getVert(dm, mf.v1, &mv[0]);
dm->getVert(dm, mf.v2, &mv[1]);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 09c70b70368..e16dac94076 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -40,6 +40,8 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_cellalloc.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -188,7 +190,7 @@ unsigned int vpaint_get_current_col(VPaint *vp)
return rgba_to_mcol(brush->rgb[0], brush->rgb[1], brush->rgb[2], 1.0f);
}
-static void do_shared_vertexcol(Mesh *me)
+static void do_shared_vertex_tesscol(Mesh *me)
{
/* if no mcol: do not do */
/* if tface: only the involved faces, otherwise all */
@@ -254,31 +256,90 @@ static void do_shared_vertexcol(Mesh *me)
MEM_freeN(scolmain);
}
+void do_shared_vertexcol(Mesh *me)
+{
+ MLoop *ml = me->mloop;
+ MLoopCol *lcol = me->mloopcol;
+ MTexPoly *mtp = me->mtpoly;
+ MPoly *mp = me->mpoly;
+ float (*scol)[5];
+ int i;
+
+ /* if no mloopcol: do not do */
+ /* if mtexpoly: only the involved faces, otherwise all */
+
+ if(me->mloopcol==0 || me->totvert==0 || me->totpoly==0) return;
+
+ scol = MEM_callocN(sizeof(float)*me->totvert*5, "scol");
+
+ for (i=0; i<me->totloop; i++, ml++, lcol++) {
+ if (i >= mp->loopstart + mp->totloop) {
+ mp++;
+ if (mtp) mtp++;
+ }
+
+ if (mtp && !(mtp->mode & TF_SHAREDCOL))
+ continue;
+
+ scol[ml->v][0] += lcol->r;
+ scol[ml->v][1] += lcol->g;
+ scol[ml->v][2] += lcol->b;
+ scol[ml->v][3] += lcol->a;
+ scol[ml->v][4] += 1.0;
+ }
+
+ for (i=0; i<me->totvert; i++) {
+ if (!scol[i][4]) continue;
+
+ scol[i][0] /= scol[i][4];
+ scol[i][1] /= scol[i][4];
+ scol[i][2] /= scol[i][4];
+ scol[i][3] /= scol[i][4];
+ }
+
+ ml = me->mloop;
+ lcol = me->mloopcol;
+ for (i=0; i<me->totloop; i++, ml++, lcol++) {
+ if (!scol[ml->v][4]) continue;
+
+ lcol->r = scol[ml->v][0];
+ lcol->g = scol[ml->v][1];
+ lcol->b = scol[ml->v][2];
+ lcol->a = scol[ml->v][3];
+ }
+
+ MEM_freeN(scol);
+
+ do_shared_vertex_tesscol(me);
+}
+
static void make_vertexcol(Object *ob) /* single ob */
{
Mesh *me;
if(!ob || ob->id.lib) return;
me= get_mesh(ob);
if(me==0) return;
- if(me->edit_mesh) return;
+ if(me->edit_btmesh) return;
/* copies from shadedisplist to mcol */
- if(!me->mcol) {
- CustomData_add_layer(&me->fdata, CD_MCOL, CD_CALLOC, NULL, me->totface);
- mesh_update_customdata_pointers(me);
- }
+ if(!me->mcol)
+ CustomData_add_layer(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface);
+ if (!me->mloopcol)
+ CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop);
+
+ mesh_update_customdata_pointers(me);
//if(shade)
// shadeMeshMCol(scene, ob, me);
//else
memset(me->mcol, 255, 4*sizeof(MCol)*me->totface);
-
+
DAG_id_tag_update(&me->id, 0);
}
-static void copy_vpaint_prev(VPaint *vp, unsigned int *mcol, int tot)
+static void copy_vpaint_prev(VPaint *vp, unsigned int *lcol, int tot)
{
if(vp->vpaint_prev) {
MEM_freeN(vp->vpaint_prev);
@@ -286,10 +347,10 @@ static void copy_vpaint_prev(VPaint *vp, unsigned int *mcol, int tot)
}
vp->tot= tot;
- if(mcol==NULL || tot==0) return;
+ if(lcol==NULL || tot==0) return;
- vp->vpaint_prev= MEM_mallocN(4*sizeof(int)*tot, "vpaint_prev");
- memcpy(vp->vpaint_prev, mcol, 4*sizeof(int)*tot);
+ vp->vpaint_prev= MEM_mallocN(sizeof(int)*tot, "vpaint_prev");
+ memcpy(vp->vpaint_prev, lcol, sizeof(int)*tot);
}
@@ -312,9 +373,11 @@ static void copy_wpaint_prev (VPaint *wp, MDeformVert *dverts, int dcount)
void vpaint_fill(Object *ob, unsigned int paintcol)
{
Mesh *me;
- MFace *mf;
+ MFace *mf;
+ MPoly *mp;
+ MLoopCol *lcol;
unsigned int *mcol;
- int i, selected;
+ int i, j, selected;
me= get_mesh(ob);
if(me==0 || me->totface==0) return;
@@ -334,6 +397,18 @@ void vpaint_fill(Object *ob, unsigned int paintcol)
mcol[3] = paintcol;
}
}
+
+ mp = me->mpoly;
+ lcol = me->mloopcol;
+ for (i=0; i<me->totpoly; i++, mp++) {
+ if (!(!selected || mp->flag & ME_FACE_SEL))
+ continue;
+
+ lcol = me->mloopcol + mp->loopstart;
+ for (j=0; j<mp->totloop; j++, lcol++) {
+ *(int*)lcol = paintcol;
+ }
+ }
DAG_id_tag_update(&me->id, 0);
}
@@ -419,7 +494,7 @@ void wpaint_fill(VPaint *wp, Object *ob, float paintweight)
dw->weight= paintweight;
if(me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */
- int j= mesh_get_x_mirror_vert(ob, faceverts[i]);
+ int j= -1; //BMESH_TODO mesh_get_x_mirror_vert(ob, faceverts[i]);
if(j>=0) {
/* copy, not paint again */
if(vgroup_mirror != -1) {
@@ -853,13 +928,14 @@ static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float
/* else */
/* sets wp->weight to the closest weight value to vertex */
/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */
+#if 0
static void sample_wpaint(Scene *scene, ARegion *ar, View3D *UNUSED(v3d), int mode)
{
ViewContext vc;
ToolSettings *ts= scene->toolsettings;
Object *ob= OBACT;
Mesh *me= get_mesh(ob);
- int index;
+ int index, i;
short mval[2] = {0, 0}, sco[2];
int vgroup= ob->actdef-1;
@@ -868,13 +944,13 @@ static void sample_wpaint(Scene *scene, ARegion *ar, View3D *UNUSED(v3d), int mo
// getmouseco_areawin(mval);
index= view3d_sample_backbuf(&vc, mval[0], mval[1]);
- if(index && index<=me->totface) {
- MFace *mface;
-
- mface= ((MFace *)me->mface) + index-1;
+ if(index && index<=me->totpoly) {
+ MPoly *mpoly;
+ mpoly= ((MPoly *)me->mpoly) + index-1;
if(mode==1) { /* sampe which groups are in here */
MDeformVert *dv;
+ MLoop *ml;
int a, totgroup;
totgroup= BLI_countlist(&ob->defbase);
@@ -882,28 +958,14 @@ static void sample_wpaint(Scene *scene, ARegion *ar, View3D *UNUSED(v3d), int mo
int totmenu=0;
int *groups=MEM_callocN(totgroup*sizeof(int), "groups");
- dv= me->dvert+mface->v1;
- for(a=0; a<dv->totweight; a++) {
- if (dv->dw[a].def_nr<totgroup)
- groups[dv->dw[a].def_nr]= 1;
- }
- dv= me->dvert+mface->v2;
- for(a=0; a<dv->totweight; a++) {
- if (dv->dw[a].def_nr<totgroup)
- groups[dv->dw[a].def_nr]= 1;
- }
- dv= me->dvert+mface->v3;
- for(a=0; a<dv->totweight; a++) {
+ ml = me->mloop+mpoly->loopstart;
+ for (i=0; i<mpoly->totloop; i++, ml++) {
+ dv = me->dvert+ml->v;
if (dv->dw[a].def_nr<totgroup)
groups[dv->dw[a].def_nr]= 1;
+
}
- if(mface->v4) {
- dv= me->dvert+mface->v4;
- for(a=0; a<dv->totweight; a++) {
- if (dv->dw[a].def_nr<totgroup)
- groups[dv->dw[a].def_nr]= 1;
- }
- }
+
for(a=0; a<totgroup; a++)
if(groups[a]) totmenu++;
@@ -936,28 +998,19 @@ static void sample_wpaint(Scene *scene, ARegion *ar, View3D *UNUSED(v3d), int mo
}
else {
DerivedMesh *dm;
- float w1, w2, w3, w4, co[3], fac;
+ MLoop *ml;
+ float w, co[3], fmin = 10000000.0f;
+ int loopi = mpoly->loopstart;
dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
if(dm->getVertCo==NULL) {
//notice("Not supported yet");
}
else {
- /* calc 3 or 4 corner weights */
- dm->getVertCo(dm, mface->v1, co);
- project_short_noclip(ar, co, sco);
- w1= ((mval[0]-sco[0])*(mval[0]-sco[0]) + (mval[1]-sco[1])*(mval[1]-sco[1]));
-
- dm->getVertCo(dm, mface->v2, co);
- project_short_noclip(ar, co, sco);
- w2= ((mval[0]-sco[0])*(mval[0]-sco[0]) + (mval[1]-sco[1])*(mval[1]-sco[1]));
-
- dm->getVertCo(dm, mface->v3, co);
- project_short_noclip(ar, co, sco);
- w3= ((mval[0]-sco[0])*(mval[0]-sco[0]) + (mval[1]-sco[1])*(mval[1]-sco[1]));
-
- if(mface->v4) {
- dm->getVertCo(dm, mface->v4, co);
+ /* find minimum distance */
+ ml = me->mloop + mpoly->loopstart;
+ for (i=0; i<mpoly->totloop; i++, ml++) {
+ dm->getVertCo(dm, ml->v, co);
project_short_noclip(ar, co, sco);
w4= ((mval[0]-sco[0])*(mval[0]-sco[0]) + (mval[1]-sco[1])*(mval[1]-sco[1]));
}
@@ -976,8 +1029,13 @@ static void sample_wpaint(Scene *scene, ARegion *ar, View3D *UNUSED(v3d), int mo
else if(w4==fac) {
if(mface->v4) {
ts->vgroup_weight= defvert_find_weight(me->dvert+mface->v4, vgroup);
+>>>>>>> .merge-right.r23146
}
}
+
+ ml = me->mloop + loopi;
+ dw= get_defweight(me->dvert+ml->v, ob->actdef-1);
+ if(dw) ts->vgroup_weight= dw->weight; else ts->vgroup_weight= 0.0f;
}
dm->release(dm);
}
@@ -985,6 +1043,7 @@ static void sample_wpaint(Scene *scene, ARegion *ar, View3D *UNUSED(v3d), int mo
}
}
+#endif
static void do_weight_paint_auto_normalize(MDeformVert *dvert,
int paint_nr, char *map)
@@ -1044,7 +1103,7 @@ static void do_weight_paint_vertex(VPaint *wp, Object *ob, int index,
do_weight_paint_auto_normalize(me->dvert+index, vgroup, validmap);
if(me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */
- int j= mesh_get_x_mirror_vert(ob, index);
+ int j= -1; //BMESH_TODO mesh_get_x_mirror_vert(ob, index);
if(j>=0) {
/* copy, not paint again */
if(vgroup_mirror != -1)
@@ -1092,7 +1151,7 @@ static int set_wpaint(bContext *C, wmOperator *UNUSED(op)) /* toggle */
paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT);
paint_cursor_start(C, weight_paint_poll);
- mesh_octree_table(ob, NULL, NULL, 's');
+ //BMESH_TODO mesh_octree_table(ob, NULL, NULL, 's');
/* verify if active weight group is also active bone */
par= modifiers_isDeformedByArmature(ob);
@@ -1104,8 +1163,8 @@ static int set_wpaint(bContext *C, wmOperator *UNUSED(op)) /* toggle */
}
}
else {
- mesh_octree_table(NULL, NULL, NULL, 'e');
- mesh_mirrtopo_table(NULL, 'e');
+ //BMESH_TODO mesh_octree_table(NULL, NULL, NULL, 'e');
+ //BMESH_TODO mesh_mirrtopo_table(NULL, 'e');
}
WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene);
@@ -1331,6 +1390,13 @@ static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *UNUSED
me= get_mesh(ob);
if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH;
+ /*we can't assume mfaces have a correct origindex layer that indices to mpolys.
+ so instead we have to regenerate the tesselation faces altogether.*/
+ me->totface = mesh_recalcTesselation(&me->fdata, &me->ldata, &me->pdata,
+ me->mvert, me->totface, me->totloop, me->totpoly, 1, 0);
+ mesh_update_customdata_pointers(me);
+ makeDerivedMesh(scene, ob, NULL, CD_MASK_BAREMESH);
+
/* if nothing was added yet, we make dverts and a vertex deform group */
if (!me->dvert) {
ED_vgroup_data_create(&me->id);
@@ -1474,22 +1540,22 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
if(wp->flag & VP_COLINDEX) {
for(index=0; index<totindex; index++) {
- if(indexar[index] && indexar[index]<=me->totface) {
- MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
+ if(indexar[index] && indexar[index]<=me->totpoly) {
+ MPoly *mpoly= ((MPoly *)me->mpoly) + (indexar[index]-1);
- if(mface->mat_nr!=ob->actcol-1) {
+ if(mpoly->mat_nr!=ob->actcol-1) {
indexar[index]= 0;
}
}
}
}
- if((me->editflag & ME_EDIT_PAINT_MASK) && me->mface) {
+ if((me->editflag & ME_EDIT_PAINT_MASK) && me->mpoly) {
for(index=0; index<totindex; index++) {
- if(indexar[index] && indexar[index]<=me->totface) {
- MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
+ if(indexar[index] && indexar[index]<=me->totpoly) {
+ MPoly *mpoly= ((MPoly *)me->mpoly) + (indexar[index]-1);
- if((mface->flag & ME_FACE_SEL)==0) {
+ if((mpoly->flag & ME_FACE_SEL)==0) {
indexar[index]= 0;
}
}
@@ -1505,13 +1571,14 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
paintweight= ts->vgroup_weight;
for(index=0; index<totindex; index++) {
- if(indexar[index] && indexar[index]<=me->totface) {
- MFace *mface= me->mface + (indexar[index]-1);
-
- (me->dvert+mface->v1)->flag= 1;
- (me->dvert+mface->v2)->flag= 1;
- (me->dvert+mface->v3)->flag= 1;
- if(mface->v4) (me->dvert+mface->v4)->flag= 1;
+ if(indexar[index] && indexar[index]<=me->totpoly) {
+ MPoly *mpoly= me->mpoly + (indexar[index]-1);
+ MLoop *ml = me->mloop + mpoly->loopstart;
+ int i;
+
+ for (i=0; i<mpoly->totloop; i++, ml++) {
+ (me->dvert+ml->v)->flag = 1;
+ }
if(brush->vertexpaint_tool==VP_BLUR) {
MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int);
@@ -1521,15 +1588,13 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
else
dw_func= defvert_verify_index;
- dw= dw_func(me->dvert+mface->v1, ob->actdef-1);
- if(dw) {paintweight+= dw->weight; totw++;}
- dw= dw_func(me->dvert+mface->v2, ob->actdef-1);
- if(dw) {paintweight+= dw->weight; totw++;}
- dw= dw_func(me->dvert+mface->v3, ob->actdef-1);
- if(dw) {paintweight+= dw->weight; totw++;}
- if(mface->v4) {
- dw= dw_func(me->dvert+mface->v4, ob->actdef-1);
- if(dw) {paintweight+= dw->weight; totw++;}
+ ml = me->mloop + mpoly->loopstart;
+ for (i=0; i<mpoly->totloop; i++, ml++) {
+ dw = dw_func(me->dvert+ml->v, ob->actdef-1);
+ if (dw) {
+ paintweight += dw->weight;
+ totw++;
+ }
}
}
}
@@ -1539,49 +1604,20 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
paintweight/= (float)totw;
for(index=0; index<totindex; index++) {
-
- if(indexar[index] && indexar[index]<=me->totface) {
- MFace *mface= me->mface + (indexar[index]-1);
-
- if((me->dvert+mface->v1)->flag) {
- alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v1, mval, pressure);
- if(alpha) {
- do_weight_paint_vertex(wp, ob, mface->v1,
- alpha, paintweight, flip, wpd->vgroup_mirror,
- wpd->vgroup_validmap);
- }
- (me->dvert+mface->v1)->flag= 0;
- }
-
- if((me->dvert+mface->v2)->flag) {
- alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v2, mval, pressure);
- if(alpha) {
- do_weight_paint_vertex(wp, ob, mface->v2,
- alpha, paintweight, flip, wpd->vgroup_mirror,
- wpd->vgroup_validmap);
- }
- (me->dvert+mface->v2)->flag= 0;
- }
-
- if((me->dvert+mface->v3)->flag) {
- alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v3, mval, pressure);
- if(alpha) {
- do_weight_paint_vertex(wp, ob, mface->v3,
- alpha, paintweight, flip, wpd->vgroup_mirror,
- wpd->vgroup_validmap);
- }
- (me->dvert+mface->v3)->flag= 0;
- }
-
- if((me->dvert+mface->v4)->flag) {
- if(mface->v4) {
- alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v4, mval, pressure);
- if(alpha) {
- do_weight_paint_vertex(wp, ob, mface->v4,
- alpha, paintweight, flip, wpd->vgroup_mirror,
+ if(indexar[index] && indexar[index]<=me->totpoly) {
+ MPoly *mpoly= me->mpoly + (indexar[index]-1);
+ MLoop *ml=me->mloop+mpoly->loopstart;
+ int i;
+
+ for (i=0; i<mpoly->totloop; i++, ml++) {
+ if ((me->dvert+ml->v)->flag) {
+ alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*ml->v, mval, pressure);
+ if(alpha != 0.0f) {
+ do_weight_paint_vertex(wp, ob, ml->v,
+ alpha, paintweight, flip, wpd->vgroup_mirror,
wpd->vgroup_validmap);
}
- (me->dvert+mface->v4)->flag= 0;
+ (me->dvert+ml->v)->flag= 0;
}
}
}
@@ -1707,7 +1743,7 @@ static int set_vpaint(bContext *C, wmOperator *op) /* toggle */
return OPERATOR_PASS_THROUGH;
}
- if(me && me->mcol==NULL) make_vertexcol(ob);
+ if(me && me->mloopcol==NULL) make_vertexcol(ob);
/* toggle: end vpaint */
if(ob->mode & OB_MODE_VERTEX_PAINT) {
@@ -1775,14 +1811,60 @@ For future:
*/
+typedef struct polyfacemap_e {
+ struct polyfacemap_e *next, *prev;
+ int facenr;
+} polyfacemap_e;
+
typedef struct VPaintData {
ViewContext vc;
unsigned int paintcol;
int *indexar;
float *vertexcosnos;
float vpimat[3][3];
+
+ /*mpoly -> mface mapping*/
+ MemArena *arena;
+ ListBase *polyfacemap;
} VPaintData;
+static void vpaint_build_poly_facemap(struct VPaintData *vd, Mesh *me,
+ Object *ob, Scene *scene)
+{
+ MFace *mf;
+ polyfacemap_e *e;
+ int *origIndex;
+ int i;
+
+ vd->arena = BLI_memarena_new(1<<13, "vpaint tmp");
+ BLI_memarena_use_calloc(vd->arena);
+
+ vd->polyfacemap = BLI_memarena_alloc(vd->arena, sizeof(ListBase)*me->totpoly);
+
+ /*we can't assume mfaces have a correct origindex layer that indices to mpolys.
+ so instead we have to regenerate the tesselation faces altogether.*/
+ me->totface = mesh_recalcTesselation(&me->fdata, &me->ldata, &me->pdata,
+ me->mvert, me->totface, me->totloop, me->totpoly, 1, 0);
+ mesh_update_customdata_pointers(me);
+ makeDerivedMesh(scene, ob, NULL, CD_MASK_BAREMESH);
+
+ origIndex = CustomData_get_layer(&me->fdata, CD_ORIGINDEX);
+ mf = me->mface;
+
+ if (!origIndex)
+ return;
+
+ for (i=0; i<me->totface; i++, mf++, origIndex++) {
+ if (*origIndex == ORIGINDEX_NONE)
+ continue;
+
+ e = BLI_memarena_alloc(vd->arena, sizeof(polyfacemap_e));
+ e->facenr = i;
+
+ BLI_addtail(&vd->polyfacemap[*origIndex], e);
+ }
+}
+
static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *UNUSED(event))
{
ToolSettings *ts= CTX_data_tool_settings(C);
@@ -1790,15 +1872,19 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent
VPaint *vp= ts->vpaint;
struct VPaintData *vpd;
Object *ob= CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
Mesh *me;
float mat[4][4], imat[4][4];
/* context checks could be a poll() */
me= get_mesh(ob);
- if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH;
+ if(me==NULL || me->totpoly==0)
+ return OPERATOR_PASS_THROUGH;
- if(me->mcol==NULL) make_vertexcol(ob);
- if(me->mcol==NULL) return OPERATOR_CANCELLED;
+ if(me->mloopcol==NULL)
+ make_vertexcol(ob);
+ if(me->mloopcol==NULL)
+ return OPERATOR_CANCELLED;
/* make mode data storage */
vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData");
@@ -1808,9 +1894,10 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent
vpd->vertexcosnos= mesh_get_mapped_verts_nors(vpd->vc.scene, ob);
vpd->indexar= get_indexarray(me);
vpd->paintcol= vpaint_get_current_col(vp);
+ vpaint_build_poly_facemap(vpd, me, ob, scene);
/* for filtering */
- copy_vpaint_prev(vp, (unsigned int *)me->mcol, me->totface);
+ copy_vpaint_prev(vp, (unsigned int *)me->mloopcol, me->totloop);
/* some old cruft to sort out later */
mul_m4_m4m4(mat, ob->obmat, vpd->vc.rv3d->viewmat);
@@ -1820,6 +1907,7 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent
return 1;
}
+#if 0
static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, int index, float mval[2], float pressure, int UNUSED(flip))
{
ViewContext *vc = &vpd->vc;
@@ -1853,6 +1941,7 @@ static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, int index
vpaint_blend(vp, mcol+i, mcolorig+i, vpd->paintcol, (int)(alpha*255.0));
}
}
+#endif
static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
@@ -1862,6 +1951,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
Brush *brush = paint_brush(&vp->paint);
ViewContext *vc= &vpd->vc;
Object *ob= vc->obact;
+ polyfacemap_e *e;
Mesh *me= ob->data;
float mat[4][4];
int *indexar= vpd->indexar;
@@ -1883,7 +1973,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* which faces are involved */
if(vp->flag & VP_AREA) {
- totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size(brush));
+ totindex= sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size(brush));
}
else {
indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
@@ -1893,19 +1983,114 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
swap_m4m4(vc->rv3d->persmat, mat);
- for(index=0; index<totindex; index++) {
- if(indexar[index] && indexar[index]<=me->totface)
- vpaint_paint_face(vp, vpd, ob, indexar[index]-1, mval, pressure, flip);
+ if(vp->flag & VP_COLINDEX) {
+ for(index=0; index<totindex; index++) {
+ if(indexar[index] && indexar[index]<=me->totpoly) {
+ MPoly *mpoly= ((MPoly *)me->mpoly) + (indexar[index]-1);
+
+ if(mpoly->mat_nr!=ob->actcol-1) {
+ indexar[index]= 0;
+ }
+ }
+ }
}
+
+ if((me->editflag & ME_EDIT_PAINT_MASK) && me->mpoly) {
+ for(index=0; index<totindex; index++) {
+ if(indexar[index] && indexar[index]<=me->totpoly) {
+ MPoly *mpoly= ((MPoly *)me->mpoly) + (indexar[index]-1);
+ if((mpoly->flag & ME_FACE_SEL)==0)
+ indexar[index]= 0;
+ }
+ }
+ }
+
swap_m4m4(vc->rv3d->persmat, mat);
/* was disabled because it is slow, but necessary for blur */
if(brush->vertexpaint_tool == VP_BLUR)
do_shared_vertexcol(me);
- ED_region_tag_redraw(vc->ar);
+ for(index=0; index<totindex; index++) {
+
+ if(indexar[index] && indexar[index]<=me->totpoly) {
+ MPoly *mpoly= ((MPoly *)me->mpoly) + (indexar[index]-1);
+ MFace *mf;
+ MCol *mc;
+ MLoop *ml;
+ MLoopCol *mlc;
+ unsigned int *lcol = ((unsigned int*)me->mloopcol) + mpoly->loopstart;
+ unsigned int *lcolorig = ((unsigned int*)vp->vpaint_prev) + mpoly->loopstart;
+ float alpha;
+ int i, j;
+
+ if(brush->vertexpaint_tool==VP_BLUR) {
+ unsigned int blend[5] = {0};
+ char *col;
+
+ for (j=0; j<mpoly->totloop; j += 2) {
+ col = (char*)(lcol + j);
+ blend[0] += col[0];
+ blend[1] += col[1];
+ blend[2] += col[2];
+ blend[3] += col[3];
+ }
+
+ blend[0] /= mpoly->totloop;
+ blend[1] /= mpoly->totloop;
+ blend[2] /= mpoly->totloop;
+ blend[3] /= mpoly->totloop;
+ col = (char*)(blend + 4);
+ col[0] = blend[0];
+ col[1] = blend[1];
+ col[2] = blend[2];
+ col[3] = blend[3];
+
+ vpd->paintcol = *((unsigned int*)col);
+ }
+
+ ml = me->mloop + mpoly->loopstart;
+ for (i=0; i<mpoly->totloop; i++, ml++) {
+ alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat,
+ vpd->vertexcosnos+6*ml->v, mval, pressure);
+ if(alpha > 0.0f) vpaint_blend(vp, lcol+i, lcolorig+i, vpd->paintcol, (int)(alpha*255.0f));
+ }
+
+ #ifdef CPYCOL
+ #undef CPYCOL
+ #endif
+ #define CPYCOL(c, l) (c)->a = (l)->a, (c)->r = (l)->r, (c)->g = (l)->g, (c)->b = (l)->b
+
+ /*update vertex colors for tesselations incrementally,
+ rather then regenerating the tesselation altogether.*/
+ for (e=vpd->polyfacemap[(indexar[index]-1)].first; e; e=e->next) {
+ mf = me->mface + e->facenr;
+ mc = me->mcol + e->facenr*4;
+
+ ml = me->mloop + mpoly->loopstart;
+ mlc = me->mloopcol + mpoly->loopstart;
+ for (j=0; j<mpoly->totloop; j++, ml++, mlc++) {
+ if (ml->v == mf->v1)
+ CPYCOL(mc, mlc);
+ else if (ml->v == mf->v2)
+ CPYCOL(mc+1, mlc);
+ else if (ml->v == mf->v3)
+ CPYCOL(mc+2, mlc);
+ else if (mf->v4 && ml->v == mf->v4)
+ CPYCOL(mc+3, mlc);
+
+ }
+ }
+ #undef CPYCOL
+ }
+ }
+
+ swap_m4m4(vc->rv3d->persmat, mat);
+ do_shared_vertexcol(me);
+
+ ED_region_tag_redraw(vc->ar);
DAG_id_tag_update(ob->data, 0);
}
@@ -1920,7 +2105,8 @@ static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
/* frees prev buffer */
copy_vpaint_prev(ts->vpaint, NULL, 0);
-
+ BLI_memarena_free(vpd->arena);
+
MEM_freeN(vpd);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 7505fdb0ecf..a94cb9dd971 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -129,7 +129,7 @@ struct MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob)
Mesh *me= (Mesh*)ob->data;
ModifierData *md;
- if(!CustomData_get_layer(&me->fdata, CD_MDISPS)) {
+ if(!CustomData_get_layer(&me->ldata, CD_MDISPS)) {
/* multires can't work without displacement layer */
return NULL;
}
@@ -221,6 +221,8 @@ typedef struct StrokeCache {
float mouse[2];
float bstrength;
float tex_mouse[2];
+
+ rctf prect;
/* The rest is temporary storage that isn't saved as a property */
@@ -265,10 +267,20 @@ typedef struct StrokeCache {
static int sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
Object *ob, rcti *rect)
{
+ StrokeCache *cache = ob->sculpt->cache;
PBVH *pbvh= ob->sculpt->pbvh;
float bb_min[3], bb_max[3], pmat[4][4];
int i, j, k;
+/* if (G.rt == 1) {
+ rect->xmin = cache->prect.xmin;
+ rect->xmax = cache->prect.xmax;
+ rect->ymin = cache->prect.ymin;
+ rect->ymax = cache->prect.ymax;
+
+ return rect->xmin < rect->xmax && rect->ymin < rect->ymax;;
+ }
+*/
view3d_get_object_project_mat(rv3d, ob, pmat);
if(!pbvh)
@@ -307,6 +319,7 @@ void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar,
PBVH *pbvh= ob->sculpt->pbvh;
BoundBox bb;
bglMats mats;
+ StrokeCache *cache = ob->sculpt->cache;
rcti rect;
memset(&bb, 0, sizeof(BoundBox));
@@ -335,6 +348,13 @@ void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar,
/* clear redraw flag from nodes */
if(pbvh)
BLI_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL);
+
+ /*clear prect*/
+ cache->prect.xmin = FLT_MAX;
+ cache->prect.xmax = -FLT_MAX;
+ cache->prect.ymin = FLT_MAX;
+ cache->prect.ymax = -FLT_MAX;
+
}
/************************ Brush Testing *******************/
@@ -2170,10 +2190,11 @@ static void do_fill_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t
static void do_scrape_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
+ rctf mr;
+ float xrad, yrad;
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
-
float an[3];
float fc[3];
float offset = get_offset(sd, ss);
@@ -2651,7 +2672,7 @@ void sculpt_update_mesh_elements(Scene *scene, Object *ob, int need_fmap)
if(mmd) {
ss->multires = mmd;
ss->totvert = dm->getNumVerts(dm);
- ss->totface = dm->getNumFaces(dm);
+ ss->totface = dm->getNumTessFaces(dm);
ss->mvert= NULL;
ss->mface= NULL;
ss->face_normals= NULL;
@@ -2861,6 +2882,11 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio
int mode;
ss->cache = cache;
+
+ cache->prect.xmin = FLT_MAX;
+ cache->prect.xmax = -FLT_MAX;
+ cache->prect.ymin = FLT_MAX;
+ cache->prect.ymax = -FLT_MAX;
/* Set scaling adjustment */
ss->cache->scale[0] = 1.0f / ob->size[0];
@@ -3351,15 +3377,16 @@ static void sculpt_flush_update(bContext *C)
}
else {
rcti r;
+ int off = 0;
BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
//rcti tmp;
- r.xmin += ar->winrct.xmin + 1;
- r.xmax += ar->winrct.xmin - 1;
- r.ymin += ar->winrct.ymin + 1;
- r.ymax += ar->winrct.ymin - 1;
+ r.xmin += ar->winrct.xmin + 1 + off;
+ r.xmax += ar->winrct.xmin - 1 - off;
+ r.ymin += ar->winrct.ymin + 1 + off;
+ r.ymax += ar->winrct.ymin - 1 - off;
//tmp = r;
diff --git a/source/blender/editors/space_api/CMakeLists.txt b/source/blender/editors/space_api/CMakeLists.txt
index 22319dbb26e..3977a47066c 100644
--- a/source/blender/editors/space_api/CMakeLists.txt
+++ b/source/blender/editors/space_api/CMakeLists.txt
@@ -24,6 +24,9 @@ set(INC
../../blenkernel
../../blenloader
../../blenlib
+ ../../bmesh
+ ../include
+ ../../../../intern/guardedalloc
../../makesdna
../../makesrna
../../windowmanager
diff --git a/source/blender/editors/space_api/SConscript b/source/blender/editors/space_api/SConscript
index d6a763a78ff..6bf901cf8ad 100644
--- a/source/blender/editors/space_api/SConscript
+++ b/source/blender/editors/space_api/SConscript
@@ -4,7 +4,7 @@ Import ('env')
sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../blenloader ../../makesdna'
-incs += ' ../../windowmanager ../../python ../../makesrna'
+incs += ' ../../windowmanager ../../python ../../makesrna ../../bmesh'
incs += ' #/intern/guardedalloc #/extern/glew/include'
defs = ''
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index bd19ff5e1b1..db857d4be9f 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -35,6 +35,9 @@
#include "BKE_context.h"
#include "BKE_screen.h"
+#include "BKE_tessmesh.h"
+
+#include "bmesh.h"
#include "UI_interface.h"
#include "UI_view2d.h"
diff --git a/source/blender/editors/space_buttons/SConscript b/source/blender/editors/space_buttons/SConscript
index a4270f1f59a..38a65cadfab 100644
--- a/source/blender/editors/space_buttons/SConscript
+++ b/source/blender/editors/space_buttons/SConscript
@@ -5,7 +5,11 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
+<<<<<<< .working
+incs += ' ../../makesrna ../../render/extern/include ../../bmesh'
+=======
incs += ' ../../makesrna ../../render/extern/include ../../blenloader'
+>>>>>>> .merge-right.r35190
defs = []
diff --git a/source/blender/editors/space_file/Makefile b/source/blender/editors/space_file/Makefile
new file mode 100644
index 00000000000..4597ffa3f6b
--- /dev/null
+++ b/source/blender/editors/space_file/Makefile
@@ -0,0 +1,76 @@
+#
+# $Id$
+#
+# ***** 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) 2007 Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL LICENSE BLOCK *****
+#
+# Makes module object directory and bounces make to subdirectories.
+
+LIBNAME = ed_file
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I$(NAN_GLEW)/include
+CPPFLAGS += -I$(OPENGL_HEADERS)
+
+# not very neat....
+CPPFLAGS += -I../../windowmanager
+CPPFLAGS += -I../../blenloader
+CPPFLAGS += -I../../blenkernel
+CPPFLAGS += -I../../blenlib
+CPPFLAGS += -I../../makesdna
+CPPFLAGS += -I../../makesrna
+CPPFLAGS += -I../../imbuf
+CPPFLAGS += -I../../render/extern/include
+CPPFLAGS += -I../../python
+CPPFLAGS += -I../../blenfont
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+
+# own include
+
+CPPFLAGS += -I../include
+
+ifeq ($(WITH_OPENJPEG),true)
+ CPPFLAGS += -DWITH_OPENJPEG
+endif
+
+ifeq ($(WITH_OPENEXR), true)
+ CPPFLAGS += -DWITH_OPENEXR
+endif
+
+ifeq ($(WITH_TIFF), true)
+ CPPFLAGS += -DWITH_TIFF
+endif
+
+ifeq ($(WITH_CINEON), true)
+ CPPFLAGS += -DWITH_CINEON
+endif
+
+ifeq ($(WITH_HDR), true)
+ CPPFLAGS += -DWITH_HDR
+endif
diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt
index f6825808267..8568278d0bb 100644
--- a/source/blender/editors/space_image/CMakeLists.txt
+++ b/source/blender/editors/space_image/CMakeLists.txt
@@ -26,6 +26,7 @@ set(INC
../../blenloader
../../blenlib
../../imbuf
+ ../../bmesh
../../makesdna
../../makesrna
../../windowmanager
diff --git a/source/blender/editors/space_image/Makefile b/source/blender/editors/space_image/Makefile
new file mode 100644
index 00000000000..51a29115813
--- /dev/null
+++ b/source/blender/editors/space_image/Makefile
@@ -0,0 +1,77 @@
+#
+# $Id$
+#
+# ***** 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) 2007 Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL LICENSE BLOCK *****
+#
+# Makes module object directory and bounces make to subdirectories.
+
+LIBNAME = ed_image
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I$(NAN_GLEW)/include
+CPPFLAGS += -I$(OPENGL_HEADERS)
+
+# not very neat....
+CPPFLAGS += -I../../windowmanager
+CPPFLAGS += -I../../blenkernel
+CPPFLAGS += -I../../blenlib
+CPPFLAGS += -I../../makesdna
+CPPFLAGS += -I../../makesrna
+CPPFLAGS += -I../../imbuf
+CPPFLAGS += -I../../python
+CPPFLAGS += -I../../render/extern/include
+CPPFLAGS += -I../../bmesh
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+
+# own include
+
+CPPFLAGS += -I../include
+
+ifeq ($(WITH_OPENEXR), true)
+ CPPFLAGS += -DWITH_OPENEXR
+endif
+
+ifeq ($(WITH_TIFF), true)
+ CPPFLAGS += -DWITH_TIFF
+endif
+
+ifeq ($(WITH_LCMS), true)
+ CPPFLAGS += -DWITH_LCMS
+ CPPFLAGS += -I$(BF_LCMS_INC)
+endif
+
+ifeq ($(WITH_CINEON), true)
+ CPPFLAGS += -DWITH_CINEON
+endif
+
+ifeq ($(WITH_HDR), true)
+ CPPFLAGS += -DWITH_HDR
+endif
+
diff --git a/source/blender/editors/space_image/SConscript b/source/blender/editors/space_image/SConscript
index e84afcdaab1..7d966025006 100644
--- a/source/blender/editors/space_image/SConscript
+++ b/source/blender/editors/space_image/SConscript
@@ -5,7 +5,11 @@ sources = env.Glob('*.c')
incs = '../include ../../blenfont ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
+<<<<<<< .working
+incs += ' ../../render/extern/include ../../makesrna ../../bmesh'
+=======
incs += ' ../../render/extern/include ../../makesrna ../../blenloader'
+>>>>>>> .merge-right.r35190
defs = []
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index ea991f420a0..dfaeccd7993 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -49,6 +49,7 @@
#include "BKE_mesh.h"
#include "BKE_node.h"
#include "BKE_screen.h"
+#include "BKE_tessmesh.h"
#include "RE_pipeline.h"
@@ -202,39 +203,32 @@ static void image_editvertex_buts(const bContext *C, uiBlock *block)
SpaceImage *sima= CTX_wm_space_image(C);
Image *ima= sima->image;
Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em;
+ BMFace *efa;
+ MTexPoly *tf;
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter iter, liter;
static float ocent[2];
float cent[2]= {0.0, 0.0};
int imx= 256, imy= 256;
int nactive= 0, step, digits;
- EditMesh *em;
- EditFace *efa;
- MTFace *tf;
image_transform_but_attr(sima, &imx, &imy, &step, &digits);
- em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
- for (efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if (uvedit_face_visible(scene, ima, efa, tf)) {
+ em= ((Mesh *)obedit->data)->edit_btmesh;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if (!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ BM_ITER(l, &iter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- if (uvedit_uv_selected(scene, efa, tf, 0)) {
- cent[0]+= tf->uv[0][0];
- cent[1]+= tf->uv[0][1];
- nactive++;
- }
- if (uvedit_uv_selected(scene, efa, tf, 1)) {
- cent[0]+= tf->uv[1][0];
- cent[1]+= tf->uv[1][1];
- nactive++;
- }
- if (uvedit_uv_selected(scene, efa, tf, 2)) {
- cent[0]+= tf->uv[2][0];
- cent[1]+= tf->uv[2][1];
- nactive++;
- }
- if (efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
- cent[0]+= tf->uv[3][0];
- cent[1]+= tf->uv[3][1];
+ if (uvedit_uv_selected(em, scene, l)) {
+ cent[0] += luv->uv[0];
+ cent[1] += luv->uv[1];
+
nactive++;
}
}
@@ -277,32 +271,23 @@ static void image_editvertex_buts(const bContext *C, uiBlock *block)
delta[1]= ocent[1]/imy - cent[1];
}
- for (efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if (uvedit_face_visible(scene, ima, efa, tf)) {
- if (uvedit_uv_selected(scene, efa, tf, 0)) {
- tf->uv[0][0]+= delta[0];
- tf->uv[0][1]+= delta[1];
- }
- if (uvedit_uv_selected(scene, efa, tf, 1)) {
- tf->uv[1][0]+= delta[0];
- tf->uv[1][1]+= delta[1];
- }
- if (uvedit_uv_selected(scene, efa, tf, 2)) {
- tf->uv[2][0]+= delta[0];
- tf->uv[2][1]+= delta[1];
- }
- if (efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
- tf->uv[3][0]+= delta[0];
- tf->uv[3][1]+= delta[1];
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if (!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ BM_ITER(l, &iter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if (uvedit_uv_selected(em, scene, l)) {
+ luv->uv[0] += delta[0];
+ luv->uv[1] += delta[1];
}
}
}
-
+
WM_event_add_notifier(C, NC_IMAGE, sima->image);
}
-
- BKE_mesh_end_editmesh(obedit->data, em);
}
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 4abddf18c20..e19a001f005 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -187,13 +187,13 @@ static void draw_image_grid(ARegion *ar, float zoomx, float zoomy)
if(gridsize<=0.0f) return;
if(gridsize<1.0f) {
- while(gridsize<1.0f) {
+ while(gridsize<1.0f && gridsize<1000000.0f ) {
gridsize*= 4.0;
gridstep*= 4.0;
}
}
else {
- while(gridsize>=4.0f) {
+ while(gridsize>=4.0f && gridsize<1000000.0f) {
gridsize/= 4.0;
gridstep/= 4.0;
}
diff --git a/source/blender/editors/space_image/image_header.c b/source/blender/editors/space_image/image_header.c
index 176e12025f7..be481053693 100644
--- a/source/blender/editors/space_image/image_header.c
+++ b/source/blender/editors/space_image/image_header.c
@@ -38,6 +38,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_mesh.h"
#include "ED_image.h"
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 25dd79ecc8e..19fe795bb58 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -40,6 +40,7 @@
#include "DNA_node_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_scene_types.h"
+#include "DNA_meshdata_types.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
@@ -51,6 +52,7 @@
#include "BKE_packedFile.h"
#include "BKE_report.h"
#include "BKE_screen.h"
+#include "BKE_tessmesh.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -61,6 +63,8 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "bmesh.h"
+
#include "ED_image.h"
#include "ED_screen.h"
#include "ED_space_api.h"
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index cc81d7ac975..ed59a35229a 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -46,6 +46,7 @@
#include "BKE_image.h"
#include "BKE_mesh.h"
#include "BKE_screen.h"
+#include "BKE_tessmesh.h"
#include "IMB_imbuf_types.h"
@@ -271,12 +272,11 @@ int ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit)
return 0;
if(obedit && obedit->type == OB_MESH) {
- EditMesh *em = BKE_mesh_get_editmesh(obedit->data);
+ BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
int ret;
- ret = EM_texFaceCheck(em);
+ ret = EDBM_texFaceCheck(em);
- BKE_mesh_end_editmesh(obedit->data, em);
return ret;
}
@@ -290,12 +290,11 @@ int ED_space_image_show_uvshadow(SpaceImage *sima, Object *obedit)
if(ED_space_image_show_paint(sima))
if(obedit && obedit->type == OB_MESH) {
- EditMesh *em = BKE_mesh_get_editmesh(obedit->data);
+ BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
int ret;
- ret = EM_texFaceCheck(em);
+ ret = EDBM_texFaceCheck(em);
- BKE_mesh_end_editmesh(obedit->data, em);
return ret;
}
@@ -585,13 +584,13 @@ static void image_refresh(const bContext *C, ScrArea *UNUSED(sa))
if(ima && (ima->source==IMA_SRC_VIEWER || sima->pin));
else if(obedit && obedit->type == OB_MESH) {
Mesh *me= (Mesh*)obedit->data;
- EditMesh *em= BKE_mesh_get_editmesh(me);
- MTFace *tf;
+ BMEditMesh *em= me->edit_btmesh;
+ MTexPoly *tf;
- if(em && EM_texFaceCheck(em)) {
+ if(em && EDBM_texFaceCheck(em)) {
sima->image= NULL;
- tf = EM_get_active_mtface(em, NULL, NULL, 1); /* partially selected face is ok */
+ tf = EDBM_get_active_mtexpoly(em, NULL, 1); /* partially selected face is ok */
if(tf && (tf->mode & TF_TEX)) {
/* don't need to check for pin here, see above */
@@ -601,8 +600,6 @@ static void image_refresh(const bContext *C, ScrArea *UNUSED(sa))
else sima->curtile= tf->tile;
}
}
-
- BKE_mesh_end_editmesh(obedit->data, em);
}
}
@@ -1006,4 +1003,3 @@ void ED_spacetype_image(void)
BKE_spacetype_register(st);
}
-
diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt
index c7e0b23acab..9ebd86f5c2b 100644
--- a/source/blender/editors/space_info/CMakeLists.txt
+++ b/source/blender/editors/space_info/CMakeLists.txt
@@ -26,6 +26,7 @@ set(INC
../../blenloader
../../blenlib
../../imbuf
+ ../../bmesh
../../makesdna
../../makesrna
../../windowmanager
diff --git a/source/blender/editors/space_info/Makefile b/source/blender/editors/space_info/Makefile
new file mode 100644
index 00000000000..0a9d3e3396d
--- /dev/null
+++ b/source/blender/editors/space_info/Makefile
@@ -0,0 +1,56 @@
+#
+# $Id$
+#
+# ***** 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) 2007 Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL LICENSE BLOCK *****
+#
+# Makes module object directory and bounces make to subdirectories.
+
+LIBNAME = ed_info
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I$(NAN_GLEW)/include
+CPPFLAGS += -I$(OPENGL_HEADERS)
+
+# not very neat....
+CPPFLAGS += -I../../windowmanager
+CPPFLAGS += -I../../blenloader
+CPPFLAGS += -I../../blenkernel
+CPPFLAGS += -I../../blenlib
+CPPFLAGS += -I../../makesdna
+CPPFLAGS += -I../../makesrna
+CPPFLAGS += -I../../imbuf
+CPPFLAGS += -I../../python
+CPPFLAGS += -I../../bmesh
+CPPFLAGS += -I../../blenfont
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+
+# own include
+
+CPPFLAGS += -I../include
diff --git a/source/blender/editors/space_info/SConscript b/source/blender/editors/space_info/SConscript
index 697ee4319b8..18de1a13d9d 100644
--- a/source/blender/editors/space_info/SConscript
+++ b/source/blender/editors/space_info/SConscript
@@ -4,7 +4,11 @@ Import ('env')
sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../makesrna ../../imbuf ../../blenfont'
+<<<<<<< .working
+incs += ' ../../bmesh ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
+=======
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include ../../blenloader'
+>>>>>>> .merge-right.r35190
defs = []
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index b3c8c6c891e..b9e4730ec41 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -42,6 +42,7 @@
#include "BKE_key.h"
#include "BKE_mesh.h"
#include "BKE_particle.h"
+#include "BKE_tessmesh.h"
#include "ED_info.h"
#include "ED_armature.h"
@@ -135,26 +136,16 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
static void stats_object_edit(Object *obedit, SceneStats *stats)
{
if(obedit->type==OB_MESH) {
- /* Mesh Edit */
- EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
+ BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
+
+ stats->totvert = em->bm->totvert;
+ stats->totvertsel = em->bm->totvertsel;
- for(eve= em->verts.first; eve; eve=eve->next) {
- stats->totvert++;
- if(eve->f & SELECT) stats->totvertsel++;
- }
- for(eed= em->edges.first; eed; eed=eed->next) {
- stats->totedge++;
- if(eed->f & SELECT) stats->totedgesel++;
- }
- for(efa= em->faces.first; efa; efa=efa->next) {
- stats->totface++;
- if(efa->f & SELECT) stats->totfacesel++;
- }
+ stats->totedge = em->bm->totedge;
+ stats->totedgesel = em->bm->totedgesel;
- EM_validate_selections(em);
+ stats->totface = em->bm->totface;
+ stats->totfacesel = em->bm->totfacesel;
}
else if(obedit->type==OB_ARMATURE){
/* Armature Edit */
diff --git a/source/blender/editors/space_logic/logic_buttons.c b/source/blender/editors/space_logic/logic_buttons.c
index 310cbf645d1..1450bc3b3b5 100644
--- a/source/blender/editors/space_logic/logic_buttons.c
+++ b/source/blender/editors/space_logic/logic_buttons.c
@@ -26,6 +26,8 @@
#include <string.h>
#include <stdio.h>
+#include "DNA_meshdata_types.h"
+
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/editors/space_node/SConscript b/source/blender/editors/space_node/SConscript
index 634d4b777d9..6a5556e3e51 100644
--- a/source/blender/editors/space_node/SConscript
+++ b/source/blender/editors/space_node/SConscript
@@ -14,7 +14,7 @@ if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
if env['CC'] == 'gcc':
#cf.append('-Werror')
pass
-
+
if env['OURPLATFORM'] == 'linux2':
cflags='-pthread'
incs += ' ../../../extern/binreloc/include'
diff --git a/source/blender/editors/space_outliner/outliner.c b/source/blender/editors/space_outliner/outliner.c
index edfe63e9dd4..91a2754545b 100644
--- a/source/blender/editors/space_outliner/outliner.c
+++ b/source/blender/editors/space_outliner/outliner.c
@@ -5742,7 +5742,7 @@ void draw_outliner(const bContext *C)
outliner_back(ar);
block= uiBeginBlock(C, ar, "outliner buttons", UI_EMBOSS);
outliner_draw_tree((bContext *)C, block, scene, ar, soops);
-
+
if(ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
/* draw rna buttons */
outliner_draw_rnacols(ar, sizex_rna);
@@ -5760,6 +5760,9 @@ void draw_outliner(const bContext *C)
/* draw edit buttons if nessecery */
outliner_buttons(C, block, ar, soops, &soops->tree);
+ /* draw edit buttons if nessecery */
+ outliner_buttons(C, block, ar, soops, &soops->tree);
+
uiEndBlock(C, block);
uiDrawBlock(C, block);
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index fc9dd8c9bcc..3e611ab406e 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
../../blenkernel
../../blenloader
../../blenlib
+ ../../bmesh
../../gpu
../../imbuf
../../makesdna
diff --git a/source/blender/editors/space_view3d/SConscript b/source/blender/editors/space_view3d/SConscript
index 3df59d485d5..9c1c03ff373 100644
--- a/source/blender/editors/space_view3d/SConscript
+++ b/source/blender/editors/space_view3d/SConscript
@@ -7,7 +7,7 @@ defs = [ 'GLEW_STATIC' ]
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../render/extern/include ../../blenloader'
-incs += ' ../../gpu ../../makesrna ../../blenfont'
+incs += ' ../../gpu ../../makesrna ../../blenfont ../../bmesh'
incs += ' #/intern/smoke/extern'
incs += ' #source/kernel/gen_system'
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
index 1f0ee30c9e9..93a08af6903 100644
--- a/source/blender/editors/space_view3d/drawarmature.c
+++ b/source/blender/editors/space_view3d/drawarmature.c
@@ -1314,36 +1314,36 @@ static void pchan_draw_IK_root_lines(bPoseChannel *pchan, short only_temp)
switch (con->type) {
case CONSTRAINT_TYPE_KINEMATIC:
{
- bKinematicConstraint *data = (bKinematicConstraint*)con->data;
- int segcount= 0;
-
- /* if only_temp, only draw if it is a temporary ik-chain */
- if ((only_temp) && !(data->flag & CONSTRAINT_IK_TEMP))
- continue;
-
- setlinestyle(3);
- glBegin(GL_LINES);
-
- /* exclude tip from chain? */
- if ((data->flag & CONSTRAINT_IK_TIP)==0)
- parchan= pchan->parent;
- else
- parchan= pchan;
-
- glVertex3fv(parchan->pose_tail);
-
- /* Find the chain's root */
- while (parchan->parent) {
- segcount++;
- if(segcount==data->rootbone || segcount>255) break; // 255 is weak
- parchan= parchan->parent;
- }
- if (parchan)
- glVertex3fv(parchan->pose_head);
-
- glEnd();
- setlinestyle(0);
+ bKinematicConstraint *data = (bKinematicConstraint*)con->data;
+ int segcount= 0;
+
+ /* if only_temp, only draw if it is a temporary ik-chain */
+ if ((only_temp) && !(data->flag & CONSTRAINT_IK_TEMP))
+ continue;
+
+ setlinestyle(3);
+ glBegin(GL_LINES);
+
+ /* exclude tip from chain? */
+ if ((data->flag & CONSTRAINT_IK_TIP)==0)
+ parchan= pchan->parent;
+ else
+ parchan= pchan;
+
+ glVertex3fv(parchan->pose_tail);
+
+ /* Find the chain's root */
+ while (parchan->parent) {
+ segcount++;
+ if(segcount==data->rootbone || segcount>255) break; // 255 is weak
+ parchan= parchan->parent;
}
+ if (parchan)
+ glVertex3fv(parchan->pose_head);
+
+ glEnd();
+ setlinestyle(0);
+ }
break;
case CONSTRAINT_TYPE_SPLINEIK:
{
@@ -1362,7 +1362,7 @@ static void pchan_draw_IK_root_lines(bPoseChannel *pchan, short only_temp)
// FIXME: revise the breaking conditions
if(segcount==data->chainlen || segcount>255) break; // 255 is weak
parchan= parchan->parent;
- }
+ }
if (parchan) // XXX revise the breaking conditions to only stop at the tail?
glVertex3fv(parchan->pose_head);
@@ -1821,9 +1821,9 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
glLoadName(index & 0xFFFF);
pchan_draw_IK_root_lines(pchan, !(do_dashed & 2));
- }
- }
}
+ }
+ }
}
glPushMatrix();
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index 19726f02665..030f368aaa2 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -42,6 +42,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_windowmanager_types.h"
#include "DNA_object_types.h"
#include "BKE_DerivedMesh.h"
@@ -50,6 +51,7 @@
#include "BKE_material.h"
#include "BKE_paint.h"
#include "BKE_property.h"
+#include "BKE_tessmesh.h"
#include "BIF_gl.h"
@@ -403,7 +405,7 @@ static void draw_textured_end(void)
glPopMatrix();
}
-static int draw_tface__set_draw_legacy(MTFace *tface, MCol *mcol, int matnr)
+static int draw_tface__set_draw_legacy(MTFace *tface, int has_vcol, int matnr)
{
if (tface && (tface->mode&TF_INVISIBLE)) return 0;
@@ -413,7 +415,7 @@ static int draw_tface__set_draw_legacy(MTFace *tface, MCol *mcol, int matnr)
} else if (tface && tface->mode&TF_OBCOL) {
glColor3ubv(Gtexdraw.obcol);
return 2; /* Don't set color */
- } else if (!mcol) {
+ } else if (!has_vcol) {
if (tface) glColor3f(1.0, 1.0, 1.0);
else {
Material *ma= give_current_material(Gtexdraw.ob, matnr+1);
@@ -448,15 +450,15 @@ static int draw_tface__set_draw(MTFace *tface, MCol *mcol, int matnr)
static void add_tface_color_layer(DerivedMesh *dm)
{
MTFace *tface = DM_get_face_data_layer(dm, CD_MTFACE);
- MFace *mface = DM_get_face_data_layer(dm, CD_MFACE);
+ MFace *mface = dm->getTessFaceArray(dm);
MCol *finalCol;
int i,j;
- MCol *mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL);
+ MCol *mcol = dm->getTessFaceDataArray(dm, CD_WEIGHT_MCOL);
if(!mcol)
- mcol = dm->getFaceDataArray(dm, CD_MCOL);
+ mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
- finalCol = MEM_mallocN(sizeof(MCol)*4*dm->getNumFaces(dm),"add_tface_color_layer");
- for(i=0;i<dm->getNumFaces(dm);i++) {
+ finalCol = MEM_mallocN(sizeof(MCol)*4*dm->getNumTessFaces(dm),"add_tface_color_layer");
+ for(i=0;i<dm->getNumTessFaces(dm);i++) {
if (tface && (tface->mode&TF_INVISIBLE)) {
if( mcol )
memcpy(&finalCol[i*4],&mcol[i*4],sizeof(MCol)*4);
@@ -522,30 +524,53 @@ static void add_tface_color_layer(DerivedMesh *dm)
static int draw_tface_mapped__set_draw(void *userData, int index)
{
Mesh *me = (Mesh*)userData;
- MTFace *tface = (me->mtface)? &me->mtface[index]: NULL;
- MFace *mface = &me->mface[index];
- MCol *mcol = (me->mcol)? &me->mcol[index]: NULL;
- const int matnr = mface->mat_nr;
- if (mface->flag & ME_HIDE) return 0;
- return draw_tface__set_draw(tface, mcol, matnr);
+ MTexPoly *tpoly = (me->mtpoly)? &me->mtpoly[index]: NULL;
+ MPoly *mpoly = (me->mpoly)? &me->mpoly[index]: NULL;
+ MTFace mtf;
+ int matnr = me->mpoly[index].mat_nr;
+
+ if (mpoly && mpoly->flag&ME_HIDE) return 0;
+
+ memset(&mtf, 0, sizeof(mtf));
+ if (tpoly) {
+ mtf.flag = tpoly->flag;
+ mtf.tpage = tpoly->tpage;
+ mtf.transp = tpoly->transp;
+ mtf.mode = tpoly->mode;
+ mtf.tile = tpoly->tile;
+ mtf.unwrap = tpoly->unwrap;
+ }
+
+ return draw_tface__set_draw(&mtf, CustomData_has_layer(&me->ldata, CD_MLOOPCOL), matnr);
}
static int draw_em_tf_mapped__set_draw(void *userData, int index)
{
- EditMesh *em = userData;
- EditFace *efa= EM_get_face_for_index(index);
- MTFace *tface;
- MCol *mcol;
- int matnr;
+ BMEditMesh *em = userData;
+ BMFace *efa= EDBM_get_face_for_index(em, index);
+ MTexPoly *tpoly;
+ MTFace mtf;
+ int matnr, has_vcol;
- if (efa->h)
+ if (efa==NULL || BM_TestHFlag(efa, BM_HIDDEN))
return 0;
- tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
+ tpoly = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ has_vcol = CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL);
matnr = efa->mat_nr;
- return draw_tface__set_draw_legacy(tface, mcol, matnr);
+ memset(&mtf, 0, sizeof(mtf));
+
+ if (tpoly) {
+ mtf.flag = tpoly->flag;
+ mtf.tpage = tpoly->tpage;
+ mtf.transp = tpoly->transp;
+ mtf.mode = tpoly->mode;
+ mtf.tile = tpoly->tile;
+ mtf.unwrap = tpoly->unwrap;
+ }
+
+ return draw_tface__set_draw_legacy(&mtf, has_vcol, matnr);
}
static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r)
@@ -661,7 +686,7 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *o
glColor4f(1.0f,1.0f,1.0f,1.0f);
if(ob->mode & OB_MODE_EDIT) {
- dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, me->edit_mesh);
+ dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, me->edit_btmesh);
} else if(faceselect) {
if(ob->mode & OB_MODE_WEIGHT_PAINT)
dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me, 1, GPU_enable_material);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 031607e3084..a87cbd0530d 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -69,6 +69,8 @@
#include "BKE_pointcache.h"
#include "BKE_unit.h"
+#include "BKE_tessmesh.h"
+
#include "smoke_API.h"
#include "BIF_gl.h"
@@ -217,7 +219,7 @@ static int check_material_alpha(Base *base, Mesh *me, int glsl)
if(G.f & G_PICKSEL)
return 0;
- if(me->edit_mesh)
+ if(me->edit_btmesh)
return 0;
return (glsl || (base->object->dtx & OB_DRAWTRANSP));
@@ -1520,16 +1522,21 @@ static void drawlattice(Scene *scene, View3D *v3d, Object *ob)
* use the object matrix in the useual way */
static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
{
- struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData;
- EditVert *eve = EM_get_vert_for_index(index);
+ struct { void (*func)(void *userData, BMVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData;
+ BMVert *eve = EDBM_get_vert_for_index(data->vc.em, index);
- if (eve->h==0) {
+ if (!BM_TestHFlag(eve, BM_HIDDEN)) {
short s[2]= {IS_CLIPPED, 0};
+ float co2[3];
+
+ VECCOPY(co2, co);
+
+ mul_m4_v3(data->vc.obedit->obmat, co2);
if (data->clipVerts) {
view3d_project_short_clip(data->vc.ar, co, s, 1);
} else {
- view3d_project_short_noclip(data->vc.ar, co, s);
+ project_short_noclip(data->vc.ar, co2, s);
}
if (s[0]!=IS_CLIPPED)
@@ -1537,39 +1544,46 @@ static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co
}
}
-void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, EditVert *eve, int x, int y, int index), void *userData, int clipVerts)
+void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BMVert *eve, int x, int y, int index), void *userData, int clipVerts)
{
- struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } data;
- DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
+ struct { void (*func)(void *userData, BMVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } data;
+ DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
data.vc= *vc;
data.func = func;
data.userData = userData;
data.clipVerts = clipVerts;
+ EDBM_init_index_arrays(vc->em, 1, 0, 0);
if(clipVerts)
ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
- EM_init_index_arrays(vc->em, 1, 0, 0);
dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data);
- EM_free_index_arrays();
+ EDBM_free_index_arrays(vc->em);
dm->release(dm);
}
static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0co, float *v1co)
{
- struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData;
- EditEdge *eed = EM_get_edge_for_index(index);
+ struct { void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData;
+ BMEdge *eed = EDBM_get_edge_for_index(data->vc.em, index);
short s[2][2];
+ float v1_co[3], v2_co[3];
+
+ VECCOPY(v1_co, v0co);
+ VECCOPY(v2_co, v1co);
- if (eed->h==0) {
+ mul_m4_v3(data->vc.obedit->obmat, v1_co);
+ mul_m4_v3(data->vc.obedit->obmat, v2_co);
+
+ if (!BM_TestHFlag(eed, BM_HIDDEN)) {
if (data->clipVerts==1) {
view3d_project_short_clip(data->vc.ar, v0co, s[0], 1);
view3d_project_short_clip(data->vc.ar, v1co, s[1], 1);
} else {
- view3d_project_short_noclip(data->vc.ar, v0co, s[0]);
- view3d_project_short_noclip(data->vc.ar, v1co, s[1]);
+ project_short_noclip(data->vc.ar, v1_co, s[0]);
+ project_short_noclip(data->vc.ar, v2_co, s[1]);
if (data->clipVerts==2) {
if (!(s[0][0]>=0 && s[0][1]>= 0 && s[0][0]<data->vc.ar->winx && s[0][1]<data->vc.ar->winy))
@@ -1582,54 +1596,57 @@ static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0
}
}
-void mesh_foreachScreenEdge(ViewContext *vc, void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts)
+void mesh_foreachScreenEdge(ViewContext *vc, void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts)
{
- struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } data;
- DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
+ struct { void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } data;
+ DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
data.vc= *vc;
data.func = func;
data.userData = userData;
data.clipVerts = clipVerts;
+ EDBM_init_index_arrays(vc->em, 0, 1, 0);
if(clipVerts)
ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
- EM_init_index_arrays(vc->em, 0, 1, 0);
dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data);
- EM_free_index_arrays();
+ EDBM_free_index_arrays(vc->em);
dm->release(dm);
}
static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *cent, float *UNUSED(no))
{
- struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } *data = userData;
- EditFace *efa = EM_get_face_for_index(index);
+ struct { void (*func)(void *userData, BMFace *efa, int x, int y, int index); void *userData; ViewContext vc; float pmat[4][4], vmat[4][4]; } *data = userData;
+ float cent2[3];
+ BMFace *efa = EDBM_get_face_for_index(data->vc.em, index);
short s[2];
- if (efa && efa->h==0 && efa->fgonf!=EM_FGON) {
- view3d_project_short_clip(data->vc.ar, cent, s, 1);
+ VECCOPY(cent2, cent);
+ if (efa && !BM_TestHFlag(efa, BM_HIDDEN)) {
+ mul_m4_v3(data->vc.obedit->obmat, cent2);
+ project_short(data->vc.ar, cent2, s);
data->func(data->userData, efa, s[0], s[1], index);
}
}
-void mesh_foreachScreenFace(ViewContext *vc, void (*func)(void *userData, EditFace *efa, int x, int y, int index), void *userData)
+void mesh_foreachScreenFace(ViewContext *vc, void (*func)(void *userData, BMFace *efa, int x, int y, int index), void *userData)
{
- struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } data;
- DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
+ struct { void (*func)(void *userData, BMFace *efa, int x, int y, int index); void *userData; ViewContext vc; float pmat[4][4], vmat[4][4]; } data;
+ DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
data.vc= *vc;
data.func = func;
data.userData = userData;
+ EDBM_init_index_arrays(vc->em, 0, 0, 1);
//if(clipVerts)
ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
- EM_init_index_arrays(vc->em, 0, 0, 1);
dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data);
- EM_free_index_arrays();
+ EDBM_free_index_arrays(vc->em);
dm->release(dm);
}
@@ -1696,46 +1713,54 @@ void nurbs_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, Nurb
static void draw_dm_face_normals__mapFunc(void *userData, int index, float *cent, float *no)
{
- ToolSettings *ts= ((Scene *)userData)->toolsettings;
- EditFace *efa = EM_get_face_for_index(index);
+ Scene *scene= ((void **)userData)[0];
+ BMEditMesh *em = ((void **)userData)[1];
+ BMFace *efa = EDBM_get_face_for_index(em, index);
+ ToolSettings *ts= scene->toolsettings;
- if (efa->h==0 && efa->fgonf!=EM_FGON) {
+ if (!BM_TestHFlag(efa, BM_HIDDEN)) {
glVertex3fv(cent);
glVertex3f( cent[0] + no[0]*ts->normalsize,
cent[1] + no[1]*ts->normalsize,
cent[2] + no[2]*ts->normalsize);
}
}
-static void draw_dm_face_normals(Scene *scene, DerivedMesh *dm)
+static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
{
+ void *ptrs[2] = {scene, em};
+
glBegin(GL_LINES);
- dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, scene);
+ dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, ptrs);
glEnd();
}
static void draw_dm_face_centers__mapFunc(void *userData, int index, float *cent, float *UNUSED(no))
{
- EditFace *efa = EM_get_face_for_index(index);
- int sel = *((int*) userData);
+ BMFace *efa = EDBM_get_face_for_index(((void **)userData)[0], index);
+ BMEditMesh *em = ((void **)userData)[0];
+ int sel = *(((int **)userData)[1]);
- if (efa->h==0 && efa->fgonf!=EM_FGON && (efa->f&SELECT)==sel) {
+ if (!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT)==sel) {
bglVertex3fv(cent);
}
}
-static void draw_dm_face_centers(DerivedMesh *dm, int sel)
+static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, int sel)
{
+ void *ptrs[2] = {em, &sel};
+
bglBegin(GL_POINTS);
- dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &sel);
+ dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, ptrs);
bglEnd();
}
static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
{
- Scene *scene= (Scene *)userData;
+ Scene *scene= ((void **)userData)[0];
ToolSettings *ts= scene->toolsettings;
- EditVert *eve = EM_get_vert_for_index(index);
+ BMEditMesh *em = ((void **)userData)[1];
+ BMVert *eve = EDBM_get_vert_for_index(em, index);
- if (eve->h==0) {
+ if (!BM_TestHFlag(eve, BM_HIDDEN)) {
glVertex3fv(co);
if (no_f) {
@@ -1749,20 +1774,78 @@ static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co,
}
}
}
-static void draw_dm_vert_normals(Scene *scene, DerivedMesh *dm)
+static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
{
+ void *ptrs[2] = {scene, em};
+
glBegin(GL_LINES);
- dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, scene);
+ dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, ptrs);
+ glEnd();
+}
+
+/* check if all verts of the face are pinned */
+static int check_pinned_face(BMesh *bm, BMFace *efa)
+{
+ BMIter vfiter;
+ BMVert *v;
+ int vcount = 0;
+
+ BM_ITER(v, &vfiter, bm, BM_VERTS_OF_FACE, efa) {
+ if(BM_TestHFlag(v, BM_PINNED)) vcount ++;
+ }
+
+ if( vcount == efa->len) return 1;
+ return 0;
+}
+
+static void draw_dm_vert_pins__mapFunc(void *userData, int index, float *co)
+{
+ struct {BMEditMesh *em; Mesh *me;} *data = userData;
+ BMVert *eve = EDBM_get_vert_for_index(data->em, index);
+ BMFace *fv;
+ BMIter fviter;
+ float vsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
+ int small=0;
+
+ if (!BM_TestHFlag(eve, BM_HIDDEN)) {
+ if (BM_TestHFlag(eve, BM_PINNED)) {
+ BM_ITER(fv, &fviter, data->em->bm, BM_FACES_OF_VERT, eve) {
+ small += check_pinned_face(data->em->bm, fv);
+ }
+ if(small == 0) {
+ bglEnd();
+ glPointSize(vsize*1.5);
+ glBegin(GL_POINTS);
+ glVertex3fv(co);
+ }
+ else {
+ bglEnd();
+ glPointSize(vsize*0.5);
+ glBegin(GL_POINTS);
+ glVertex3fv(co);
+ }
+ }
+ }
+}
+
+static void draw_dm_vert_pins(BMEditMesh *em, DerivedMesh *dm, Mesh *me)
+{
+ struct { BMEditMesh *em; Mesh *me;} data;
+
+ data.em = em;
+ data.me = me;
+
+ dm->foreachMappedVert(dm, draw_dm_vert_pins__mapFunc, &data);
glEnd();
}
/* Draw verts with color set based on selection */
static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
{
- struct { int sel; EditVert *eve_act; } * data = userData;
- EditVert *eve = EM_get_vert_for_index(index);
+ struct { BMEditMesh *em; int sel; BMVert *eve_act; } *data = userData;
+ BMVert *eve = EDBM_get_vert_for_index(data->em, index);
- if (eve->h==0 && (eve->f&SELECT)==data->sel) {
+ if (!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)==data->sel) {
/* draw active larger - need to stop/start point drawing for this :/ */
if (eve==data->eve_act) {
float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
@@ -1784,11 +1867,16 @@ static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *
}
}
-static void draw_dm_verts(DerivedMesh *dm, int sel, EditVert *eve_act)
+static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, int sel, BMVert *eve_act)
{
- struct { int sel; EditVert *eve_act; } data;
+ struct { BMEditMesh *em; int sel; BMVert *eve_act; } data;
data.sel = sel;
data.eve_act = eve_act;
+ data.em = em;
+
+ bglBegin(GL_POINTS);
+ dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
+ bglEnd();
bglBegin(GL_POINTS);
dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
@@ -1798,16 +1886,18 @@ static void draw_dm_verts(DerivedMesh *dm, int sel, EditVert *eve_act)
/* Draw edges with color set based on selection */
static int draw_dm_edges_sel__setDrawOptions(void *userData, int index)
{
- EditEdge *eed = EM_get_edge_for_index(index);
+ BMEdge *eed;
//unsigned char **cols = userData, *col;
- struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } * data = userData;
+ struct { BMEditMesh *em; unsigned char *baseCol, *selCol, *actCol; BMEdge *eed_act; } * data = userData;
unsigned char *col;
- if (eed->h==0) {
+ eed = EDBM_get_edge_for_index(data->em, index);
+
+ if (!BM_TestHFlag(eed, BM_HIDDEN)) {
if (eed==data->eed_act) {
glColor4ubv(data->actCol);
} else {
- if (eed->f&SELECT) {
+ if (BM_TestHFlag(eed, BM_SELECT)) {
col = data->selCol;
} else {
col = data->baseCol;
@@ -1822,38 +1912,40 @@ static int draw_dm_edges_sel__setDrawOptions(void *userData, int index)
return 0;
}
}
-static void draw_dm_edges_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditEdge *eed_act)
+static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
+ unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act)
{
- struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } data;
+ struct { BMEditMesh *em; unsigned char *baseCol, *selCol, *actCol; BMEdge *eed_act; } data;
data.baseCol = baseCol;
data.selCol = selCol;
data.actCol = actCol;
+ data.em = em;
data.eed_act = eed_act;
dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
}
/* Draw edges */
-static int draw_dm_edges__setDrawOptions(void *UNUSED(userData), int index)
+static int draw_dm_edges__setDrawOptions(void *userData, int index)
{
- return EM_get_edge_for_index(index)->h==0;
+ return !BM_TestHFlag(EDBM_get_edge_for_index(userData, index), BM_HIDDEN);
}
-static void draw_dm_edges(DerivedMesh *dm)
+static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm)
{
- dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, NULL);
+ dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em);
}
/* Draw edges with color interpolated based on selection */
-static int draw_dm_edges_sel_interp__setDrawOptions(void *UNUSED(userData), int index)
+static int draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
{
- return EM_get_edge_for_index(index)->h==0;
+ return !BM_TestHFlag(EDBM_get_edge_for_index(((void**)userData)[0], index), BM_HIDDEN);
}
static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
{
- EditEdge *eed = EM_get_edge_for_index(index);
+ BMEdge *eed = EDBM_get_edge_for_index(((void**)userData)[0], index);
unsigned char **cols = userData;
- unsigned char *col0 = cols[(eed->v1->f&SELECT)?1:0];
- unsigned char *col1 = cols[(eed->v2->f&SELECT)?1:0];
+ unsigned char *col0 = cols[(BM_TestHFlag(eed->v1, BM_SELECT))?2:1];
+ unsigned char *col1 = cols[(BM_TestHFlag(eed->v2, BM_SELECT))?2:1];
glColor4ub( col0[0] + (col1[0]-col0[0])*t,
col0[1] + (col1[1]-col0[1])*t,
@@ -1861,36 +1953,87 @@ static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int i
col0[3] + (col1[3]-col0[3])*t);
}
-static void draw_dm_edges_sel_interp(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
+static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
{
- unsigned char *cols[2];
- cols[0]= baseCol;
- cols[1]= selCol;
+ unsigned char *cols[3] = {em, baseCol, selCol};
+
dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
}
/* Draw only seam edges */
-static int draw_dm_edges_seams__setDrawOptions(void *UNUSED(userData), int index)
+static int draw_dm_edges_seams__setDrawOptions(void *userData, int index)
+{
+ BMEdge *eed = EDBM_get_edge_for_index(userData, index);
+
+ return !BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SEAM);
+}
+
+static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
+{
+ dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em);
+}
+
+/* Draw only pinned edges */
+static int draw_dm_edges_pins__setDrawOptions(void *userData, int index)
{
- EditEdge *eed = EM_get_edge_for_index(index);
+ struct {BMEditMesh *em; Mesh *me;} *data = userData;
+
+ BMEdge *eed = EDBM_get_edge_for_index(data->em, index);
+ BMIter feiter;
+ BMFace *fe;
- return (eed->h==0 && eed->seam);
+ int fcount, fpcount = 0;
+ int pin = 0;
+
+ /* If pinned faces are drawn then only draw pinned edges at the borders.
+ This looks way better and the user still has all the info he needs. */
+ if(data->me->drawflag & ME_DRAW_PINS) {
+ if( BM_TestHFlag(eed->v1, BM_PINNED) && BM_TestHFlag(eed->v2, BM_PINNED) ) {
+ pin = 1;
+
+ fcount = 0;
+ BM_ITER(fe, &feiter, data->em->bm, BM_FACES_OF_EDGE, eed) {
+ fcount ++;
+ fpcount += check_pinned_face(data->em->bm, fe);
+ }
+ }
+ }
+ else {
+ pin = BM_TestHFlag(eed->v1, BM_PINNED) && BM_TestHFlag(eed->v2, BM_PINNED);
+ }
+
+ if( !BM_TestHFlag(eed, BM_HIDDEN)) {
+ /* Edges with at least one adherent pinned face are considered borders.
+ If there are more than two adherent faces overall of which at least two are pinned it's also consideres a border. */
+ if( fpcount == 2 && fcount <= 2) {
+ return 0; }
+ else {
+ return pin; }
+ }
+
+ return 0;
}
-static void draw_dm_edges_seams(DerivedMesh *dm)
+
+static void draw_dm_edges_pins(BMEditMesh *em, DerivedMesh *dm, Mesh *me)
{
- dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, NULL);
+ struct { BMEditMesh *em; Mesh *me;} data;
+
+ data.em = em;
+ data.me = me;
+
+ dm->drawMappedEdges(dm, draw_dm_edges_pins__setDrawOptions, &data);
}
/* Draw only sharp edges */
-static int draw_dm_edges_sharp__setDrawOptions(void *UNUSED(userData), int index)
+static int draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
{
- EditEdge *eed = EM_get_edge_for_index(index);
+ BMEdge *eed = EDBM_get_edge_for_index(userData, index);
- return (eed->h==0 && eed->sharp);
+ return !BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SHARP);
}
-static void draw_dm_edges_sharp(DerivedMesh *dm)
+static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
{
- dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, NULL);
+ dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em);
}
@@ -1898,18 +2041,38 @@ static void draw_dm_edges_sharp(DerivedMesh *dm)
* return 2 for the active face so it renders with stipple enabled */
static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *UNUSED(drawSmooth_r))
{
- struct { unsigned char *cols[3]; EditFace *efa_act; } * data = userData;
- EditFace *efa = EM_get_face_for_index(index);
+ struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} *data = userData;
+ BMFace *efa = EDBM_get_face_for_index(data->em, index);
unsigned char *col;
+ BMIter vfiter;
+ BMVert *v;
+ int vcount, pin=0;
+ int opac = UI_GetThemeValue(TH_PIN_OPAC);
+
+ if (!efa)
+ return 0;
- if (efa->h==0) {
+ if (!BM_TestHFlag(efa, BM_HIDDEN)) {
+
+ /* Check if all verts of a face are pinned. If so, then display it in a darker shade. */
+ if(data->me->drawflag & ME_DRAW_PINS)
+ pin = check_pinned_face(data->em->bm, efa);
+
if (efa == data->efa_act) {
- glColor4ubv(data->cols[2]);
+ if(pin==0) { glColor4ubv(data->cols[2]); }
+ else {
+ col = data->cols[2];
+ glColor4ub(col[0]-col[0]*0.9, col[1]-col[1]*0.9, col[2]-col[2]*0.9, opac*2.55);
+ }
+
return 2; /* stipple */
} else {
- col = data->cols[(efa->f&SELECT)?1:0];
+ col = data->cols[BM_TestHFlag(efa, BM_SELECT)?1:0];
if (col[3]==0) return 0;
- glColor4ubv(col);
+
+ if(pin==0) { glColor4ubv(col); }
+ else { glColor4ub(col[0]-col[0]*0.9, col[1]-col[1]*0.9, col[2]-col[2]*0.9, opac*2.55); }
+
return 1;
}
}
@@ -1917,68 +2080,87 @@ static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *UNU
}
/* also draws the active face */
-static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditFace *efa_act)
+static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
+ unsigned char *selCol, unsigned char *actCol, BMFace *efa_act, Mesh *me)
{
- struct { unsigned char *cols[3]; EditFace *efa_act; } data;
+ struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} data;
+
data.cols[0] = baseCol;
+ data.em = em;
data.cols[1] = selCol;
data.cols[2] = actCol;
data.efa_act = efa_act;
+ data.me = me;
dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0, GPU_enable_material);
}
-static int draw_dm_creases__setDrawOptions(void *UNUSED(userData), int index)
+static int draw_dm_creases__setDrawOptions(void *userData, int index)
{
- EditEdge *eed = EM_get_edge_for_index(index);
-
- if (eed->h==0 && eed->crease!=0.0) {
- UI_ThemeColorBlend(TH_WIRE, TH_EDGE_CREASE, eed->crease);
+ BMEditMesh *em = userData;
+ BMEdge *eed = EDBM_get_edge_for_index(userData, index);
+ float *crease = bm_get_cd_float(&em->bm->edata, eed->head.data, CD_CREASE);
+
+ if (!crease)
+ return 0;
+
+ if (!BM_TestHFlag(eed, BM_HIDDEN) && *crease!=0.0) {
+ UI_ThemeColorBlend(TH_WIRE, TH_EDGE_CREASE, *crease);
return 1;
} else {
return 0;
}
}
-static void draw_dm_creases(DerivedMesh *dm)
+static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm)
{
glLineWidth(3.0);
- dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, NULL);
+ dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, em);
glLineWidth(1.0);
}
-static int draw_dm_bweights__setDrawOptions(void *UNUSED(userData), int index)
+static int draw_dm_bweights__setDrawOptions(void *userData, int index)
{
- EditEdge *eed = EM_get_edge_for_index(index);
+ BMEditMesh *em = userData;
+ BMEdge *eed = EDBM_get_edge_for_index(userData, index);
+ float *bweight = bm_get_cd_float(&em->bm->edata, eed->head.data, CD_BWEIGHT);
- if (eed->h==0 && eed->bweight!=0.0) {
- UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->bweight);
+ if (!bweight)
+ return 0;
+
+ if (!BM_TestHFlag(eed, BM_HIDDEN) && *bweight!=0.0) {
+ UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, *bweight);
return 1;
} else {
return 0;
}
}
-static void draw_dm_bweights__mapFunc(void *UNUSED(userData), int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
+static void draw_dm_bweights__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
{
- EditVert *eve = EM_get_vert_for_index(index);
-
- if (eve->h==0 && eve->bweight!=0.0) {
- UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, eve->bweight);
+ BMEditMesh *em = userData;
+ BMVert *eve = EDBM_get_vert_for_index(userData, index);
+ float *bweight = bm_get_cd_float(&em->bm->vdata, eve->head.data, CD_BWEIGHT);
+
+ if (!bweight)
+ return;
+
+ if (!BM_TestHFlag(eve, BM_HIDDEN) && *bweight!=0.0) {
+ UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, *bweight);
bglVertex3fv(co);
}
}
-static void draw_dm_bweights(Scene *scene, DerivedMesh *dm)
+static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
{
ToolSettings *ts= scene->toolsettings;
if (ts->selectmode & SCE_SELECT_VERTEX) {
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
bglBegin(GL_POINTS);
- dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, NULL);
+ dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, em);
bglEnd();
}
else {
glLineWidth(3.0);
- dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, NULL);
+ dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, em);
glLineWidth(1.0);
}
}
@@ -1992,7 +2174,8 @@ static void draw_dm_bweights(Scene *scene, DerivedMesh *dm)
/* EditMesh drawing routines*/
-static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, DerivedMesh *cageDM, EditVert *eve_act)
+static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
+ BMEditMesh *em, DerivedMesh *cageDM, BMVert *eve_act)
{
ToolSettings *ts= scene->toolsettings;
int sel;
@@ -2029,13 +2212,13 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, Deriv
if(ts->selectmode & SCE_SELECT_VERTEX) {
glPointSize(size);
glColor4ubv(col);
- draw_dm_verts(cageDM, sel, eve_act);
+ draw_dm_verts(em, cageDM, sel, eve_act);
}
if(check_ob_drawface_dot(scene, v3d, obedit->dt)) {
glPointSize(fsize);
glColor4ubv(fcol);
- draw_dm_face_centers(cageDM, sel);
+ draw_dm_face_centers(em, cageDM, sel);
}
if (pass==0) {
@@ -2049,7 +2232,9 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, Deriv
glPointSize(1.0);
}
-static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh *cageDM, short sel_only, EditEdge *eed_act)
+static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
+ Mesh *me, DerivedMesh *cageDM, short sel_only,
+ BMEdge *eed_act)
{
ToolSettings *ts= scene->toolsettings;
int pass;
@@ -2082,21 +2267,21 @@ static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh
}
if(ts->selectmode == SCE_SELECT_FACE) {
- draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act);
+ draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
}
else if( (me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE) ) {
if(cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) {
glShadeModel(GL_SMOOTH);
- draw_dm_edges_sel_interp(cageDM, wireCol, selCol);
+ draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
glShadeModel(GL_FLAT);
} else {
- draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act);
+ draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
}
}
else {
if (!sel_only) {
glColor4ubv(wireCol);
- draw_dm_edges(cageDM);
+ draw_dm_edges(em, cageDM);
}
}
@@ -2107,8 +2292,10 @@ static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh
}
}
-static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em, UnitSettings *unit)
+static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d,
+ Object *ob, BMEditMesh *em, UnitSettings *unit)
{
+#if 0
Mesh *me= ob->data;
EditEdge *eed;
EditFace *efa;
@@ -2258,13 +2445,14 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E
glEnable(GL_DEPTH_TEST);
bglPolygonOffset(rv3d->dist, 0.0f);
}
+#endif
}
-static int draw_em_fancy__setFaceOpts(void *UNUSED(userData), int index, int *UNUSED(drawSmooth_r))
+static int draw_em_fancy__setFaceOpts(void *userData, int index, int *UNUSED(drawSmooth_r))
{
- EditFace *efa = EM_get_face_for_index(index);
+ BMFace *efa = EDBM_get_face_for_index(userData, index);
- if (efa->h==0) {
+ if (efa && !BM_TestHFlag(efa, BM_HIDDEN)) {
GPU_enable_material(efa->mat_nr+1, NULL);
return 1;
}
@@ -2272,33 +2460,35 @@ static int draw_em_fancy__setFaceOpts(void *UNUSED(userData), int index, int *UN
return 0;
}
-static int draw_em_fancy__setGLSLFaceOpts(void *UNUSED(userData), int index)
+static int draw_em_fancy__setGLSLFaceOpts(void *userData, int index)
{
- EditFace *efa = EM_get_face_for_index(index);
+ BMFace *efa = EDBM_get_face_for_index(userData, index);
- return (efa->h==0);
+ return !BM_TestHFlag(efa, BM_HIDDEN);
}
-static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt)
+static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob,
+ BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt)
+
{
Mesh *me = ob->data;
- EditFace *efa_act = EM_get_actFace(em, 0); /* annoying but active faces is stored differently */
- EditEdge *eed_act = NULL;
- EditVert *eve_act = NULL;
+ BMFace *efa_act = EDBM_get_actFace(em, 0); /* annoying but active faces is stored differently */
+ BMEdge *eed_act = NULL;
+ BMVert *eve_act = NULL;
- if (em->selected.last) {
- EditSelection *ese = em->selected.last;
+ if (em->bm->selected.last) {
+ BMEditSelection *ese = em->bm->selected.last;
/* face is handeled above */
/*if (ese->type == EDITFACE ) {
efa_act = (EditFace *)ese->data;
} else */ if ( ese->type == EDITEDGE ) {
- eed_act = (EditEdge *)ese->data;
+ eed_act = (BMEdge *)ese->data;
} else if ( ese->type == EDITVERT ) {
- eve_act = (EditVert *)ese->data;
+ eve_act = (BMVert *)ese->data;
}
}
- EM_init_index_arrays(em, 1, 1, 1);
+ EDBM_init_index_arrays(em, 1, 1, 1);
if(dt>OB_WIRE) {
if(CHECK_OB_DRAWTEXTURE(v3d, dt)) {
@@ -2306,7 +2496,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
finalDM->drawMappedFacesGLSL(finalDM, GPU_enable_material,
- draw_em_fancy__setGLSLFaceOpts, NULL);
+ draw_em_fancy__setGLSLFaceOpts, em);
GPU_disable_material();
glFrontFace(GL_CCW);
@@ -2321,8 +2511,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
glEnable(GL_LIGHTING);
glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
-
- finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, 0, 0, GPU_enable_material);
+ finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, me->edit_btmesh, 0, GPU_enable_material);
glFrontFace(GL_CCW);
glDisable(GL_LIGHTING);
@@ -2356,7 +2545,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
if CHECK_OB_DRAWTEXTURE(v3d, dt)
col1[3] = 0;
- draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act, me);
glDisable(GL_BLEND);
glDepthMask(1); // restore write in zbuffer
@@ -2371,7 +2560,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
glEnable(GL_BLEND);
glDepthMask(0); // disable write in zbuffer, needed for nice transp
- draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act, me);
glDisable(GL_BLEND);
glDepthMask(1); // restore write in zbuffer
@@ -2383,14 +2572,14 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
/* we are drawing textures and 'ME_DRAWEDGES' is disabled, dont draw any edges */
/* only draw selected edges otherwise there is no way of telling if a face is selected */
- draw_em_fancy_edges(scene, v3d, me, cageDM, 1, eed_act);
+ draw_em_fancy_edges(em, scene, v3d, me, cageDM, 1, eed_act);
} else {
if(me->drawflag & ME_DRAWSEAMS) {
UI_ThemeColor(TH_EDGE_SEAM);
glLineWidth(2);
- draw_dm_edges_seams(cageDM);
+ draw_dm_edges_seams(em, cageDM);
glColor3ub(0,0,0);
glLineWidth(1);
@@ -2400,33 +2589,47 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
UI_ThemeColor(TH_EDGE_SHARP);
glLineWidth(2);
- draw_dm_edges_sharp(cageDM);
+ draw_dm_edges_sharp(em, cageDM);
glColor3ub(0,0,0);
glLineWidth(1);
}
- if(me->drawflag & ME_DRAWCREASES) {
- draw_dm_creases(cageDM);
+ if(me->drawflag & ME_DRAWCREASES && CustomData_has_layer(&em->bm->edata, CD_CREASE)) {
+ draw_dm_creases(em, cageDM);
}
if(me->drawflag & ME_DRAWBWEIGHTS) {
- draw_dm_bweights(scene, cageDM);
+ draw_dm_bweights(em, scene, cageDM);
+ }
+
+ if(me->drawflag & ME_DRAW_PINS) {
+ UI_ThemeColor(TH_PIN);
+ glLineWidth(2);
+
+ draw_dm_edges_pins(em, cageDM, me);
+
+ glColor3ub(0,0,0);
+ glLineWidth(1);
}
- draw_em_fancy_edges(scene, v3d, me, cageDM, 0, eed_act);
+ draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act);
}
if(em) {
// XXX retopo_matrix_update(v3d);
- draw_em_fancy_verts(scene, v3d, ob, cageDM, eve_act);
+ draw_em_fancy_verts(scene, v3d, ob, em, cageDM, eve_act);
if(me->drawflag & ME_DRAWNORMALS) {
UI_ThemeColor(TH_NORMAL);
- draw_dm_face_normals(scene, cageDM);
+ draw_dm_face_normals(em, scene, cageDM);
}
if(me->drawflag & ME_DRAW_VNORMALS) {
UI_ThemeColor(TH_VNORMAL);
- draw_dm_vert_normals(scene, cageDM);
+ draw_dm_vert_normals(em, scene, cageDM);
+ }
+ if(me->drawflag & ME_DRAW_PINS) {
+ UI_ThemeColor(TH_PIN);
+ draw_dm_vert_pins(em, cageDM, me);
}
if(me->drawflag & (ME_DRAWEXTRA_EDGELEN|ME_DRAWEXTRA_FACEAREA|ME_DRAWEXTRA_FACEANG) && !((v3d->flag2 & V3D_RENDER_OVERRIDE)))
@@ -2439,7 +2642,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
GPU_disable_material();
}
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
}
/* Mesh drawing routines */
@@ -2468,7 +2671,7 @@ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
}
}
-static int wpaint__setSolidDrawOptions(void *UNUSED(userData), int UNUSED(index), int *drawSmooth_r)
+static int wpaint__setSolidDrawOptions(void *userData, int UNUSED(index), int *drawSmooth_r)
{
*drawSmooth_r = 1;
return 1;
@@ -2495,7 +2698,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
/* totvert = dm->getNumVerts(dm); */ /*UNUSED*/
totedge = dm->getNumEdges(dm);
- totface = dm->getNumFaces(dm);
+ totface = dm->getNumTessFaces(dm);
/* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
if(dt!=OB_SHADED)
@@ -2752,7 +2955,7 @@ static int draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
Object *ob= base->object;
Object *obedit= scene->obedit;
Mesh *me= ob->data;
- EditMesh *em= me->edit_mesh;
+ BMEditMesh *em= me->edit_btmesh;
int do_alpha_pass= 0, drawlinked= 0, retval= 0, glsl, check_alpha;
if(obedit && ob!=obedit && ob->data==obedit->data) {
@@ -2765,9 +2968,9 @@ static int draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
DerivedMesh *finalDM, *cageDM;
if (obedit!=ob)
- finalDM = cageDM = editmesh_get_derived_base(ob, em);
+ finalDM = cageDM = editbmesh_get_derived_base(ob, em);
else
- cageDM = editmesh_get_derived_cage_and_final(scene, ob, em, &finalDM,
+ cageDM = editbmesh_get_derived_cage_and_final(scene, ob, em, &finalDM,
scene->customdata_mask);
if(dt>OB_WIRE) {
@@ -6358,44 +6561,49 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
static void bbs_mesh_verts__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
{
- int offset = (intptr_t) userData;
- EditVert *eve = EM_get_vert_for_index(index);
+ void **ptrs = userData;
+ int offset = (intptr_t) ptrs[0];
+ BMVert *eve = EDBM_get_vert_for_index(ptrs[1], index);
- if (eve->h==0) {
+ if (!BM_TestHFlag(eve, BM_HIDDEN)) {
WM_set_framebuffer_index_color(offset+index);
bglVertex3fv(co);
}
}
-static void bbs_mesh_verts(DerivedMesh *dm, int offset)
+static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *dm, int offset)
{
+ void *ptrs[2] = {(void*)(intptr_t) offset, em};
+
glPointSize( UI_GetThemeValuef(TH_VERTEX_SIZE) );
bglBegin(GL_POINTS);
- dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, (void*)(intptr_t) offset);
+ dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, ptrs);
bglEnd();
glPointSize(1.0);
}
static int bbs_mesh_wire__setDrawOptions(void *userData, int index)
{
- int offset = (intptr_t) userData;
- EditEdge *eed = EM_get_edge_for_index(index);
+ void **ptrs = userData;
+ int offset = (intptr_t) ptrs[0];
+ BMEdge *eed = EDBM_get_edge_for_index(ptrs[1], index);
- if (eed->h==0) {
+ if (!BM_TestHFlag(eed, BM_HIDDEN)) {
WM_set_framebuffer_index_color(offset+index);
return 1;
} else {
return 0;
}
}
-static void bbs_mesh_wire(DerivedMesh *dm, int offset)
+static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset)
{
- dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, (void*)(intptr_t) offset);
+ void *ptrs[2] = {(void*)(intptr_t) offset, em};
+ dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, ptrs);
}
static int bbs_mesh_solid__setSolidDrawOptions(void *userData, int index, int *UNUSED(drawSmooth_r))
{
- if (EM_get_face_for_index(index)->h==0) {
- if (userData) {
+ if (!BM_TestHFlag(EDBM_get_face_for_index(((void**)userData)[0], index), BM_HIDDEN)) {
+ if (((void**)userData)[1]) {
WM_set_framebuffer_index_color(index+1);
}
return 1;
@@ -6404,11 +6612,11 @@ static int bbs_mesh_solid__setSolidDrawOptions(void *userData, int index, int *U
}
}
-static void bbs_mesh_solid__drawCenter(void *UNUSED(userData), int index, float *cent, float *UNUSED(no))
+static void bbs_mesh_solid__drawCenter(void *userData, int index, float *cent, float *UNUSED(no))
{
- EditFace *efa = EM_get_face_for_index(index);
+ BMFace *efa = EDBM_get_face_for_index(((void**)userData)[0], index);
- if (efa->h==0 && efa->fgonf!=EM_FGON) {
+ if (!BM_TestHFlag(efa, BM_HIDDEN)) {
WM_set_framebuffer_index_color(index+1);
bglVertex3fv(cent);
@@ -6416,27 +6624,30 @@ static void bbs_mesh_solid__drawCenter(void *UNUSED(userData), int index, float
}
/* two options, facecolors or black */
-static void bbs_mesh_solid_EM(Scene *scene, View3D *v3d, Object *ob, DerivedMesh *dm, int facecol)
+static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d,
+ Object *ob, DerivedMesh *dm, int facecol)
{
+ void *ptrs[2] = {em, NULL}; //second one being null means to draw black
cpack(0);
if (facecol) {
- dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*)(intptr_t) 1, 0, GPU_enable_material);
+ ptrs[1] = (void*)(intptr_t) 1;
+ dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, ptrs, 0, GPU_enable_material);
if(check_ob_drawface_dot(scene, v3d, ob->dt)) {
glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE));
bglBegin(GL_POINTS);
- dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, NULL);
+ dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, ptrs);
bglEnd();
}
} else {
- dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*) 0, 0, GPU_enable_material);
+ dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, ptrs, 0, GPU_enable_material);
}
}
-static int bbs_mesh_solid__setDrawOpts(void *UNUSED(userData), int index, int *UNUSED(drawSmooth_r))
+static int bbs_mesh_solid__setDrawOpts(void *userData, int index, int *UNUSED(drawSmooth_r))
{
WM_set_framebuffer_index_color(index+1);
return 1;
@@ -6481,36 +6692,36 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
{
if(ob->mode & OB_MODE_EDIT) {
Mesh *me= ob->data;
- EditMesh *em= me->edit_mesh;
+ BMEditMesh *em= me->edit_btmesh;
- DerivedMesh *dm = editmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH);
+ DerivedMesh *dm = editbmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH);
- EM_init_index_arrays(em, 1, 1, 1);
+ EDBM_init_index_arrays(em, 1, 1, 1);
- bbs_mesh_solid_EM(scene, v3d, ob, dm, ts->selectmode & SCE_SELECT_FACE);
+ bbs_mesh_solid_EM(em, scene, v3d, ob, dm, ts->selectmode & SCE_SELECT_FACE);
if(ts->selectmode & SCE_SELECT_FACE)
- em_solidoffs = 1+em->totface;
+ bm_solidoffs = 1+em->bm->totface;
else
- em_solidoffs= 1;
+ bm_solidoffs= 1;
bglPolygonOffset(rv3d->dist, 1.0);
// we draw edges always, for loop (select) tools
- bbs_mesh_wire(dm, em_solidoffs);
- em_wireoffs= em_solidoffs + em->totedge;
+ bbs_mesh_wire(em, dm, bm_solidoffs);
+ bm_wireoffs= bm_solidoffs + em->bm->totedge;
// we draw verts if vert select mode or if in transform (for snap).
if(ts->selectmode & SCE_SELECT_VERTEX || G.moving & G_TRANSFORM_EDIT) {
- bbs_mesh_verts(dm, em_wireoffs);
- em_vertoffs= em_wireoffs + em->totvert;
+ bbs_mesh_verts(em, dm, bm_wireoffs);
+ bm_vertoffs= bm_wireoffs + em->bm->totvert;
}
- else em_vertoffs= em_wireoffs;
+ else bm_vertoffs= bm_wireoffs;
bglPolygonOffset(rv3d->dist, 0.0);
dm->release(dm);
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
}
else bbs_mesh_solid(scene, ob);
}
@@ -6536,7 +6747,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
int glsl;
if(ob->mode & OB_MODE_EDIT)
- edm= editmesh_get_derived_base(ob, me->edit_mesh);
+ edm= editbmesh_get_derived_base(ob, me->edit_btmesh);
else
dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 96ef339a9b9..dd3b5f42b89 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -434,6 +434,7 @@ 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;
}
+
return view3d_ima_drop_poll(C, drag, event);
}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 0e4e1ad7266..7c80db76e9e 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -55,6 +55,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_screen.h"
+#include "BKE_tessmesh.h"
#include "BKE_deform.h"
#include "WM_api.h"
@@ -143,31 +144,32 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
if(ob->type==OB_MESH) {
Mesh *me= ob->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
- EditVert *eve, *evedef=NULL;
- EditEdge *eed;
+ BMEditMesh *em = me->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMVert *eve, *evedef=NULL;
+ BMEdge *eed;
+ BMIter iter;
- eve= em->verts.first;
- while(eve) {
- if(eve->f & SELECT) {
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(BM_TestHFlag(eve, BM_SELECT)) {
evedef= eve;
tot++;
add_v3_v3(median, eve->co);
}
- eve= eve->next;
}
- eed= em->edges.first;
- while(eed) {
- if((eed->f & SELECT)) {
+
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_TestHFlag(eed, BM_SELECT)) {
+ float *f = bm_get_cd_float(&bm->edata, eed->head.data, CD_CREASE);
+
totedge++;
- median[3]+= eed->crease;
+ median[3]+= f ? *f : 0.0f;
}
- eed= eed->next;
}
/* check for defgroups */
if(evedef)
- dvert= CustomData_em_get(&em->vdata, evedef->data, CD_MDEFORMVERT);
+ dvert= CustomData_bmesh_get(&em->bm->vdata, evedef->head.data, CD_MDEFORMVERT);
if(tot==1 && dvert && dvert->totweight) {
bDeformGroup *dg;
int i, max=1, init=1;
@@ -191,8 +193,6 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
tfp->defweightp= &dvert->dw[0].weight;
}
}
-
- BKE_mesh_end_editmesh(me, em);
}
else if(ob->type==OB_CURVE || ob->type==OB_SURF) {
Curve *cu= ob->data;
@@ -375,31 +375,34 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
if(ob->type==OB_MESH) {
Mesh *me= ob->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
+ BMEditMesh *em = me->edit_btmesh;
+ BMVert *eve;
+ BMIter iter;
- /* allow for some rounding error becasue of matrix transform */
if(len_v3(median) > 0.000001) {
- EditVert *eve;
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if(BM_TestHFlag(eve, BM_SELECT)) {
add_v3_v3(eve->co, median);
}
}
-
- recalc_editnormals(em);
+
+ EDBM_RecalcNormals(em);
}
-
+
if(median[3] != 0.0f) {
- EditEdge *eed;
+ BMEdge *eed;
const float fixed_crease= (ve_median[3] <= 0.0f ? 0.0 : (ve_median[3] >= 1.0f ? 1.0 : FLT_MAX));
if(fixed_crease != FLT_MAX) {
/* simple case */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- eed->crease= fixed_crease;
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_TestHFlag(eed, BM_SELECT)) {
+ float *crease = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE);
+ if (!crease) break;
+
+ *crease= fixed_crease;
}
}
}
@@ -416,10 +419,14 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
/* scale down */
const float sca= median_new / median_orig;
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- eed->crease *= sca;
- CLAMP(eed->crease, 0.0, 1.0);
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_TestHFlag(eed, BM_SELECT)) {
+ float *crease = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE);
+
+ if (!crease) break;
+
+ *crease *= sca;
+ CLAMP(*crease, 0.0, 1.0);
}
}
}
@@ -427,17 +434,20 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
/* scale up */
const float sca= (1.0f - median_new) / (1.0f - median_orig);
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- eed->crease = 1.0f - ((1.0f - eed->crease) * sca);
- CLAMP(eed->crease, 0.0, 1.0);
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_TestHFlag(eed, BM_SELECT)) {
+ float *crease = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE);
+ if (!crease) break;
+
+ *crease = 1.0f - ((1.0f - *crease) * sca);
+ CLAMP(*crease, 0.0, 1.0);
}
}
}
}
}
-
- BKE_mesh_end_editmesh(me, em);
+
+ EDBM_RecalcNormals(em);
}
else if(ob->type==OB_CURVE || ob->type==OB_SURF) {
Curve *cu= ob->data;
@@ -514,37 +524,35 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
#define B_VGRP_PNL_EDIT_SINGLE 8 /* or greater */
#define B_VGRP_PNL_COPY_SINGLE 16384 /* or greater */
-static void act_vert_def(Object *ob, EditVert **eve, MDeformVert **dvert)
+static void act_vert_def(Object *ob, BMVert **eve, MDeformVert **dvert)
{
if(ob && ob->mode & OB_MODE_EDIT && ob->type==OB_MESH && ob->defbase.first) {
Mesh *me= ob->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
- EditSelection *ese = ((EditSelection*)em->selected.last);
+ BMEditMesh *em = me->edit_btmesh;
+ BMEditSelection *ese = ((BMEditSelection*)em->bm->selected.last);
- if(ese && ese->type == EDITVERT) {
- *eve= (EditVert*)ese->data;
- *dvert= CustomData_em_get(&em->vdata, (*eve)->data, CD_MDEFORMVERT);
+ if(ese && ese->type == BM_VERT) {
+ *eve= (BMVert*)ese->data;
+ *dvert= CustomData_bmesh_get(&em->bm->vdata, (*eve)->head.data, CD_MDEFORMVERT);
return;
}
-
- BKE_mesh_end_editmesh(me, em);
}
*eve= NULL;
*dvert= NULL;
}
-static void editvert_mirror_update(Object *ob, EditVert *eve, int def_nr, int index)
+static void editvert_mirror_update(Object *ob, BMVert *eve, int def_nr, int index)
{
Mesh *me= ob->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
- EditVert *eve_mirr;
+ BMEditMesh *em = me->edit_btmesh;
+ BMVert *eve_mirr;
- eve_mirr= editmesh_get_x_mirror_vert(ob, em, eve, eve->co, index);
+ eve_mirr= editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, index);
if(eve_mirr && eve_mirr != eve) {
- MDeformVert *dvert_src= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
- MDeformVert *dvert_dst= CustomData_em_get(&em->vdata, eve_mirr->data, CD_MDEFORMVERT);
+ MDeformVert *dvert_src= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
+ MDeformVert *dvert_dst= CustomData_bmesh_get(&em->bm->vdata, eve_mirr->head.data, CD_MDEFORMVERT);
if(dvert_dst) {
if(def_nr == -1) {
/* all vgroups, add groups where neded */
@@ -566,7 +574,7 @@ static void editvert_mirror_update(Object *ob, EditVert *eve, int def_nr, int in
static void vgroup_adjust_active(Object *ob, int def_nr)
{
- EditVert *eve_act;
+ BMVert *eve_act;
MDeformVert *dvert_act;
act_vert_def(ob, &eve_act, &dvert_act);
@@ -579,7 +587,7 @@ static void vgroup_adjust_active(Object *ob, int def_nr)
static void vgroup_copy_active_to_sel(Object *ob)
{
- EditVert *eve_act;
+ BMVert *eve_act;
MDeformVert *dvert_act;
act_vert_def(ob, &eve_act, &dvert_act);
@@ -589,14 +597,15 @@ static void vgroup_copy_active_to_sel(Object *ob)
}
else {
Mesh *me= ob->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
- EditVert *eve;
+ BMEditMesh *em = me->edit_btmesh;
+ BMIter iter;
+ BMVert *eve;
MDeformVert *dvert;
int index= 0;
- for(eve= em->verts.first; eve; eve= eve->next, index++) {
- if(eve->f & SELECT && eve != eve_act) {
- dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if(BM_TestHFlag(eve, BM_SELECT) && eve != eve_act) {
+ dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
if(dvert) {
defvert_copy(dvert, dvert_act);
@@ -605,13 +614,15 @@ static void vgroup_copy_active_to_sel(Object *ob)
}
}
+
+ index++;
}
}
}
static void vgroup_copy_active_to_sel_single(Object *ob, int def_nr)
{
- EditVert *eve_act;
+ BMVert *eve_act;
MDeformVert *dvert_act;
act_vert_def(ob, &eve_act, &dvert_act);
@@ -621,8 +632,9 @@ static void vgroup_copy_active_to_sel_single(Object *ob, int def_nr)
}
else {
Mesh *me= ob->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
- EditVert *eve;
+ BMEditMesh *em = me->edit_btmesh;
+ BMIter iter;
+ BMVert *eve;
MDeformVert *dvert;
MDeformWeight *dw;
float act_weight = -1.0f;
@@ -638,10 +650,11 @@ static void vgroup_copy_active_to_sel_single(Object *ob, int def_nr)
if(act_weight < -0.5f)
return;
-
- for(eve= em->verts.first; eve; eve= eve->next, index++) {
- if(eve->f & SELECT && eve != eve_act) {
- dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+
+ eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for (index=0; eve; eve=BMIter_Step(&iter), index++) {
+ if(BM_TestHFlag(eve, BM_SELECT) && eve != eve_act) {
+ dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
if(dvert) {
for(i=0, dw=dvert->dw; i < dvert->totweight; i++, dw++) {
if(def_nr == dw->def_nr) {
@@ -665,7 +678,7 @@ static void vgroup_copy_active_to_sel_single(Object *ob, int def_nr)
static void vgroup_normalize_active(Object *ob)
{
- EditVert *eve_act;
+ BMVert *eve_act;
MDeformVert *dvert_act;
act_vert_def(ob, &eve_act, &dvert_act);
@@ -713,7 +726,7 @@ static int view3d_panel_vgroup_poll(const bContext *C, PanelType *UNUSED(pt))
{
Scene *scene= CTX_data_scene(C);
Object *ob= OBACT;
- EditVert *eve_act;
+ BMVert *eve_act;
MDeformVert *dvert_act;
act_vert_def(ob, &eve_act, &dvert_act);
@@ -728,7 +741,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
Scene *scene= CTX_data_scene(C);
Object *ob= OBACT;
- EditVert *eve;
+ BMVert *eve;
MDeformVert *dvert;
act_vert_def(ob, &eve, &dvert);
@@ -990,10 +1003,10 @@ static void v3d_editmetaball_buts(uiLayout *layout, Object *ob)
// row= uiLayoutRow(layout, 0);
RNA_pointer_create(&mball->id, &RNA_MetaElement, mball->lastelem, &ptr);
-
+
col= uiLayoutColumn(layout, 0);
uiItemR(col, &ptr, "co", 0, "Location", ICON_NULL);
-
+
uiItemR(col, &ptr, "radius", 0, "Radius", ICON_NULL);
uiItemR(col, &ptr, "stiffness", 0, "Stiffness", ICON_NULL);
@@ -1055,7 +1068,7 @@ static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
break;
-
+
case B_OBJECTPANELMEDIAN:
if(ob) {
v3d_editvertex_buts(NULL, v3d, ob, 1.0);
@@ -1252,7 +1265,7 @@ static void view3d_panel_object(const bContext *C, Panel *pa)
else {
v3d_transform_butsR(col, &obptr);
- }
+ }
}
#if 0
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 0a3ecd735f0..86957ecb86c 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -50,6 +50,7 @@
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_tessmesh.h"
#include "BIF_gl.h"
@@ -1932,18 +1933,18 @@ static void axis_set_view(bContext *C, float q1, float q2, float q3, float q4, s
if(align_active==FALSE) {
/* normal operation */
- if(rv3d->viewlock) {
- /* only pass on if */
+ if(rv3d->viewlock) {
+ /* only pass on if */
if(rv3d->view==RV3D_VIEW_FRONT && view==RV3D_VIEW_BACK);
else if(rv3d->view==RV3D_VIEW_BACK && view==RV3D_VIEW_FRONT);
else if(rv3d->view==RV3D_VIEW_RIGHT && view==RV3D_VIEW_LEFT);
else if(rv3d->view==RV3D_VIEW_LEFT && view==RV3D_VIEW_RIGHT);
else if(rv3d->view==RV3D_VIEW_BOTTOM && view==RV3D_VIEW_TOP);
else if(rv3d->view==RV3D_VIEW_TOP && view==RV3D_VIEW_BOTTOM);
- else return;
- }
+ else return;
+ }
- rv3d->view= view;
+ rv3d->view= view;
}
if(rv3d->viewlock) {
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 82605439b33..05735d810d3 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -50,6 +50,7 @@
#include "BKE_modifier.h"
#include "BKE_paint.h"
#include "BKE_screen.h"
+#include "BKE_tessmesh.h"
#include "ED_mesh.h"
#include "ED_util.h"
@@ -313,12 +314,12 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
ScrArea *sa= CTX_wm_area(C);
View3D *v3d= sa->spacedata.first;
Object *obedit = CTX_data_edit_object(C);
- EditMesh *em= NULL;
+ BMEditMesh *em= NULL;
int ctrl= win->eventstate->ctrl, shift= win->eventstate->shift;
PointerRNA props_ptr;
if(obedit && obedit->type==OB_MESH) {
- em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ em= ((Mesh *)obedit->data)->edit_btmesh;
}
/* watch it: if sa->win does not exist, check that when calling direct drawing routines */
@@ -339,7 +340,7 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
if(shift==0 || em->selectmode==0)
em->selectmode= SCE_SELECT_VERTEX;
ts->selectmode= em->selectmode;
- EM_selectmode_set(em);
+ EDBM_selectmode_set(em);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
ED_undo_push(C, "Selectmode Set: Vertex");
}
@@ -348,12 +349,12 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
if(em) {
if(shift==0 || em->selectmode==0){
if( (em->selectmode ^ SCE_SELECT_EDGE) == SCE_SELECT_VERTEX){
- if(ctrl) EM_convertsel(em, SCE_SELECT_VERTEX,SCE_SELECT_EDGE);
+ if(ctrl) EDBM_convertsel(em, SCE_SELECT_VERTEX,SCE_SELECT_EDGE);
}
em->selectmode = SCE_SELECT_EDGE;
}
ts->selectmode= em->selectmode;
- EM_selectmode_set(em);
+ EDBM_selectmode_set(em);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
ED_undo_push(C, "Selectmode Set: Edge");
}
@@ -361,14 +362,13 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
case B_SEL_FACE:
if(em) {
if( shift==0 || em->selectmode==0){
- if( ((em->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_VERTEX) || ((em->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_EDGE)){
- if(ctrl)
- EM_convertsel(em, (em->selectmode ^ SCE_SELECT_FACE),SCE_SELECT_FACE);
+ if( ((ts->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_VERTEX) || ((ts->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_EDGE)){
+ if(ctrl) EDBM_convertsel(em, (ts->selectmode ^ SCE_SELECT_FACE),SCE_SELECT_FACE);
}
em->selectmode = SCE_SELECT_FACE;
}
ts->selectmode= em->selectmode;
- EM_selectmode_set(em);
+ EDBM_selectmode_set(em);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
ED_undo_push(C, "Selectmode Set: Face");
}
@@ -401,9 +401,6 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
default:
break;
}
-
- if(obedit && obedit->type==OB_MESH)
- BKE_mesh_end_editmesh(obedit->data, em);
}
/* Returns the icon associated with an object mode */
@@ -444,11 +441,17 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
uiBlockSetEmboss(block, UI_EMBOSS);
/* mode */
- if(ob)
+ if(ob) {
+ /*sanity point checkpoint, put here to avoid seeding
+ this same code in 10 different other places.*/
+ if (!ob->mode)
+ ob->mode = OB_MODE_OBJECT;
+
v3d->modeselect = ob->mode;
- else
+ } else {
v3d->modeselect = OB_MODE_OBJECT;
-
+ }
+
uiBlockBeginAlign(block);
uiDefIconTextButS(block, MENU, B_MODESELECT, object_mode_icon(v3d->modeselect), view3d_modeselect_pup(scene) ,
0,0,126,20, &(v3d->modeselect), 0, 0, 0, 0, "Mode");
@@ -517,14 +520,14 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
/* selection modus, dont use python for this since it cant do the toggle buttons with shift+click as well as clicking to set one. */
if(obedit && (obedit->type == OB_MESH)) {
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ ts->selectmode = em->selectmode;
+
row= uiLayoutRow(layout, 1);
block= uiLayoutGetBlock(row);
- uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL, 0,0,XIC,YIC, &em->selectmode, 1.0, 0.0, 0, 0, "Vertex select mode");
- uiDefIconButBitS(block, TOG, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL, 0,0,XIC,YIC, &em->selectmode, 1.0, 0.0, 0, 0, "Edge select mode");
- uiDefIconButBitS(block, TOG, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL, 0,0,XIC,YIC, &em->selectmode, 1.0, 0.0, 0, 0, "Face select mode");
-
- BKE_mesh_end_editmesh(obedit->data, em);
+ uiDefIconButBitI(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL, 0,0,XIC,YIC, &em->selectmode, 1.0, 0.0, 0, 0, "Vertex select mode");
+ uiDefIconButBitI(block, TOG, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL, 0,0,XIC,YIC, &em->selectmode, 1.0, 0.0, 0, 0, "Edge select mode");
+ uiDefIconButBitI(block, TOG, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL, 0,0,XIC,YIC, &em->selectmode, 1.0, 0.0, 0, 0, "Face select mode");
}
}
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index a2a8f9afdb8..8cd07916b7b 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -184,6 +184,9 @@ void VIEW3D_OT_snap_cursor_to_grid(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_center(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_active(struct wmOperatorType *ot);
+#ifdef EVENT_RECORDER
+void VIEW3D_OT_evtrec(struct wmOperatorType *ot);
+#endif
/* space_view3d.c */
ARegion *view3d_has_buttons_region(ScrArea *sa);
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 8906fb6fb8e..dc1d2e26de0 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -54,6 +54,9 @@
void view3d_operatortypes(void)
{
+#ifdef EVENT_RECORDER
+ WM_operatortype_append(VIEW3D_OT_evtrec);
+#endif
WM_operatortype_append(VIEW3D_OT_rotate);
WM_operatortype_append(VIEW3D_OT_move);
WM_operatortype_append(VIEW3D_OT_zoom);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 4aa64733875..c557952a454 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: view3d_select.c 35106 2011-02-23 10:52:22Z jesterking $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
@@ -52,7 +52,7 @@
#include "BKE_context.h"
#include "BKE_paint.h"
#include "BKE_armature.h"
-
+#include "BKE_tessmesh.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -137,57 +137,63 @@ void view3d_get_transformation(ARegion *ar, RegionView3D *rv3d, Object *ob, bglM
/* local prototypes */
-static void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
+void EDBM_backbuf_checkAndSelectVerts(BMEditMesh *em, int select)
{
- EditVert *eve;
- int index= em_wireoffs;
+ BMVert *eve;
+ BMIter iter;
+ int index= bm_wireoffs;
- for(eve= em->verts.first; eve; eve= eve->next, index++) {
- if(eve->h==0) {
- if(EM_check_backbuf(index)) {
- eve->f = select?(eve->f|1):(eve->f&~1);
+ eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for ( ; eve; eve=BMIter_Step(&iter), index++) {
+ if(!BM_TestHFlag(eve, BM_HIDDEN)) {
+ if(EDBM_check_backbuf(index)) {
+ BM_Select_Vert(em->bm, eve, select);
}
}
}
}
-static void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
+void EDBM_backbuf_checkAndSelectEdges(BMEditMesh *em, int select)
{
- EditEdge *eed;
- int index= em_solidoffs;
+ BMEdge *eed;
+ BMIter iter;
+ int index= bm_solidoffs;
- for(eed= em->edges.first; eed; eed= eed->next, index++) {
- if(eed->h==0) {
- if(EM_check_backbuf(index)) {
- EM_select_edge(eed, select);
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter), index++) {
+ if(!BM_TestHFlag(eed, BM_HIDDEN)) {
+ if(EDBM_check_backbuf(index)) {
+ BM_Select_Edge(em->bm, eed, select);
}
}
}
}
-static void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
+void EDBM_backbuf_checkAndSelectFaces(BMEditMesh *em, int select)
{
- EditFace *efa;
+ BMFace *efa;
+ BMIter iter;
int index= 1;
- for(efa= em->faces.first; efa; efa= efa->next, index++) {
- if(efa->h==0) {
- if(EM_check_backbuf(index)) {
- EM_select_face_fgon(em, efa, select);
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter), index++) {
+ if(!BM_TestHFlag(efa, BM_HIDDEN)) {
+ if(EDBM_check_backbuf(index)) {
+ BM_Select_Face(em->bm, efa, select);
}
}
}
}
-static void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
+void EDBM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
{
- MFace *mface = me->mface;
+ MPoly *mpoly = me->mpoly;
int a;
- if (mface) {
- for(a=1; a<=me->totface; a++, mface++) {
- if(EM_check_backbuf(a)) {
- mface->flag = select?(mface->flag|ME_FACE_SEL):(mface->flag&~ME_FACE_SEL);
+ if (mpoly) {
+ for(a=1; a<=me->totpoly; a++, mpoly++) {
+ if(EDBM_check_backbuf(a)) {
+ mpoly->flag = select?(mpoly->flag|ME_FACE_SEL):(mpoly->flag&~ME_FACE_SEL);
}
}
}
@@ -427,39 +433,39 @@ static void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
}
}
-static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int UNUSED(index))
+static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, int x, int y, int UNUSED(index))
{
struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
- eve->f = data->select?(eve->f|1):(eve->f&~1);
+ BM_Select(data->vc.em->bm, eve, data->select);
}
}
-static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
+static void do_lasso_select_mesh__doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index)
{
struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
- if (EM_check_backbuf(em_solidoffs+index)) {
+ if (EDBM_check_backbuf(bm_solidoffs+index)) {
if (data->pass==0) {
if ( edge_fully_inside_rect(data->rect, x0, y0, x1, y1) &&
lasso_inside(data->mcords, data->moves, x0, y0) &&
lasso_inside(data->mcords, data->moves, x1, y1)) {
- EM_select_edge(eed, data->select);
+ BM_Select(data->vc.em->bm, eed, data->select);
data->done = 1;
}
} else {
if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
- EM_select_edge(eed, data->select);
+ BM_Select(data->vc.em->bm, eed, data->select);
}
}
}
}
-static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int UNUSED(index))
+static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, int x, int y, int UNUSED(index))
{
struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
- EM_select_face_fgon(data->vc.em, efa, data->select);
+ BM_Select(data->vc.em->bm, efa, data->select);
}
}
@@ -473,7 +479,7 @@ static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves
lasso_select_boundbox(&rect, mcords, moves);
/* set editmesh */
- vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
+ vc->em= ((Mesh *)vc->obedit->data)->edit_btmesh;
data.vc= *vc;
data.rect = &rect;
@@ -484,7 +490,7 @@ static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves
data.pass = 0;
if (extend == 0 && select)
- EM_deselect_all(vc->em);
+ EDBM_clear_flag_all(vc->em, BM_SELECT);
/* workaround: init mats first, EM_mask_init_backbuf_border can change
view matrix to pixel space, breaking edge select with backbuf. fixes bug [#20936] */
@@ -493,11 +499,11 @@ static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves
/* ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d) */
glLoadMatrixf(vc->rv3d->viewmat);
- bbsel= EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ bbsel= EDBM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
if(ts->selectmode & SCE_SELECT_VERTEX) {
if (bbsel) {
- EM_backbuf_checkAndSelectVerts(vc->em, select);
+ EDBM_backbuf_checkAndSelectVerts(vc->em, select);
} else {
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, 1);
@@ -518,15 +524,15 @@ static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves
if(ts->selectmode & SCE_SELECT_FACE) {
if (bbsel) {
- EM_backbuf_checkAndSelectFaces(vc->em, select);
+ EDBM_backbuf_checkAndSelectFaces(vc->em, select);
} else {
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data);
}
}
- EM_free_backbuf();
- EM_selectmode_flush(vc->em);
+ EDBM_free_backbuf();
+ EDBM_selectmode_flush(vc->em);
}
#if 0
@@ -745,14 +751,14 @@ static void do_lasso_select_paintface(ViewContext *vc, short mcords[][2], short
if(extend==0 && select)
paintface_deselect_all_visible(ob, SEL_DESELECT, FALSE); /* flush selection at the end */
- em_vertoffs= me->totface+1; /* max index array */
+ bm_vertoffs= me->totpoly+1; /* max index array */
lasso_select_boundbox(&rect, mcords, moves);
- EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ EDBM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
- EM_backbuf_checkAndSelectTFaces(me, select);
+ EDBM_backbuf_checkAndSelectTFaces(me, select);
- EM_free_backbuf();
+ EDBM_free_backbuf();
paintface_flush_flags(ob);
}
@@ -1443,37 +1449,37 @@ static int do_lattice_box_select(ViewContext *vc, rcti *rect, int select, int ex
return OPERATOR_FINISHED;
}
-static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int UNUSED(index))
+static void do_mesh_box_select__doSelectVert(void *userData, BMVert *eve, int x, int y, int UNUSED(index))
{
struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
if (BLI_in_rcti(data->rect, x, y)) {
- eve->f = data->select?(eve->f|1):(eve->f&~1);
+ BM_Select(data->vc.em->bm, eve, data->select);
}
}
-static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
+static void do_mesh_box_select__doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index)
{
struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
- if(EM_check_backbuf(em_solidoffs+index)) {
+ if(EDBM_check_backbuf(bm_solidoffs+index)) {
if (data->pass==0) {
if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
- EM_select_edge(eed, data->select);
+ BM_Select(data->vc.em->bm, eed, data->select);
data->done = 1;
}
} else {
if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
- EM_select_edge(eed, data->select);
+ BM_Select(data->vc.em->bm, eed, data->select);
}
}
}
}
-static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int UNUSED(index))
+static void do_mesh_box_select__doSelectFace(void *userData, BMFace *efa, int x, int y, int UNUSED(index))
{
struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
if (BLI_in_rcti(data->rect, x, y)) {
- EM_select_face_fgon(data->vc.em, efa, data->select);
+ BM_Select(data->vc.em->bm, efa, data->select);
}
}
static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int extend)
@@ -1489,7 +1495,7 @@ static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int exten
data.done = 0;
if (extend == 0 && select)
- EM_deselect_all(vc->em);
+ EDBM_clear_flag_all(vc->em, BM_SELECT);
/* workaround: init mats first, EM_mask_init_backbuf_border can change
view matrix to pixel space, breaking edge select with backbuf. fixes bug #20936 */
@@ -1499,11 +1505,11 @@ static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int exten
/* ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d) */
glLoadMatrixf(vc->rv3d->viewmat);
- bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ bbsel= EDBM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
if(ts->selectmode & SCE_SELECT_VERTEX) {
if (bbsel) {
- EM_backbuf_checkAndSelectVerts(vc->em, select);
+ EDBM_backbuf_checkAndSelectVerts(vc->em, select);
} else {
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
@@ -1523,16 +1529,16 @@ static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int exten
if(ts->selectmode & SCE_SELECT_FACE) {
if(bbsel) {
- EM_backbuf_checkAndSelectFaces(vc->em, select);
+ EDBM_backbuf_checkAndSelectFaces(vc->em, select);
} else {
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
}
}
- EM_free_backbuf();
+ EDBM_free_backbuf();
- EM_selectmode_flush(vc->em);
+ EDBM_selectmode_flush(vc->em);
return OPERATOR_FINISHED;
}
@@ -1766,7 +1772,7 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op)
if(vc.obedit) {
switch(vc.obedit->type) {
case OB_MESH:
- vc.em= ((Mesh *)vc.obedit->data)->edit_mesh;
+ vc.em= ((Mesh *)vc.obedit->data)->edit_btmesh;
ret= do_mesh_box_select(&vc, &rect, select, extend);
// if (EM_texFaceCheck())
if(ret & OPERATOR_FINISHED) {
@@ -1906,32 +1912,32 @@ void VIEW3D_OT_select(wmOperatorType *ot)
/* -------------------- circle select --------------------------------------------- */
-static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int UNUSED(index))
+static void mesh_circle_doSelectVert(void *userData, BMVert *eve, int x, int y, int UNUSED(index))
{
struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
int mx = x - data->mval[0], my = y - data->mval[1];
float r = sqrt(mx*mx + my*my);
if (r<=data->radius) {
- eve->f = data->select?(eve->f|1):(eve->f&~1);
+ BM_Select(data->vc->em->bm, eve, data->select);
}
}
-static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int UNUSED(index))
+static void mesh_circle_doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int UNUSED(index))
{
struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
- EM_select_edge(eed, data->select);
+ BM_Select(data->vc->em->bm, eed, data->select);
}
}
-static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int UNUSED(index))
+static void mesh_circle_doSelectFace(void *userData, BMFace *efa, int x, int y, int UNUSED(index))
{
struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
int mx = x - data->mval[0], my = y - data->mval[1];
float r = sqrt(mx*mx + my*my);
if (r<=data->radius) {
- EM_select_face_fgon(data->vc->em, efa, data->select);
+ BM_Select(data->vc->em->bm, efa, data->select);
}
}
@@ -1941,10 +1947,10 @@ static void mesh_circle_select(ViewContext *vc, int select, short *mval, float r
int bbsel;
struct {ViewContext *vc; short select, mval[2]; float radius; } data;
- bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
+ bbsel= EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
- vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
+ vc->em= ((Mesh *)vc->obedit->data)->edit_btmesh;
data.vc = vc;
data.select = select;
@@ -1954,7 +1960,7 @@ static void mesh_circle_select(ViewContext *vc, int select, short *mval, float r
if(ts->selectmode & SCE_SELECT_VERTEX) {
if(bbsel) {
- EM_backbuf_checkAndSelectVerts(vc->em, select==LEFTMOUSE);
+ EDBM_backbuf_checkAndSelectVerts(vc->em, select==LEFTMOUSE);
} else {
mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1);
}
@@ -1962,7 +1968,7 @@ static void mesh_circle_select(ViewContext *vc, int select, short *mval, float r
if(ts->selectmode & SCE_SELECT_EDGE) {
if (bbsel) {
- EM_backbuf_checkAndSelectEdges(vc->em, select==LEFTMOUSE);
+ EDBM_backbuf_checkAndSelectEdges(vc->em, select==LEFTMOUSE);
} else {
mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0);
}
@@ -1970,14 +1976,14 @@ static void mesh_circle_select(ViewContext *vc, int select, short *mval, float r
if(ts->selectmode & SCE_SELECT_FACE) {
if(bbsel) {
- EM_backbuf_checkAndSelectFaces(vc->em, select==LEFTMOUSE);
+ EDBM_backbuf_checkAndSelectFaces(vc->em, select==LEFTMOUSE);
} else {
mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data);
}
}
- EM_free_backbuf();
- EM_selectmode_flush(vc->em);
+ EDBM_free_backbuf();
+ EDBM_selectmode_flush(vc->em);
}
static void paint_facesel_circle_select(ViewContext *vc, int select, short *mval, float rad)
@@ -1987,11 +1993,11 @@ static void paint_facesel_circle_select(ViewContext *vc, int select, short *mval
int bbsel;
if (me) {
- em_vertoffs= me->totface+1; /* max index array */
+ bm_vertoffs= me->totface+1; /* max index array */
- bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
- EM_backbuf_checkAndSelectTFaces(me, select==LEFTMOUSE);
- EM_free_backbuf();
+ bbsel= EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
+ EDBM_backbuf_checkAndSelectTFaces(me, select==LEFTMOUSE);
+ EDBM_free_backbuf();
}
}
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index 4c007bb1aac..04b097ba097 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: view3d_snap.c 35106 2011-02-23 10:52:22Z jesterking $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
@@ -52,6 +52,7 @@
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_object.h"
+#include "BKE_tessmesh.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -92,7 +93,7 @@ static void special_transvert_update(Object *obedit)
if(obedit->type==OB_MESH) {
Mesh *me= obedit->data;
- recalc_editnormals(me->edit_mesh); // does face centers too
+ BM_Compute_Normals(me->edit_btmesh->bm); // does face centers too
}
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
Curve *cu= obedit->data;
@@ -194,7 +195,7 @@ static void make_trans_verts(Object *obedit, float *min, float *max, int mode)
BPoint *bp;
TransVert *tv=NULL;
MetaElem *ml;
- EditVert *eve;
+ BMVert *eve;
EditBone *ebo;
float total, center[3], centroid[3];
int a;
@@ -206,50 +207,80 @@ static void make_trans_verts(Object *obedit, float *min, float *max, int mode)
if(obedit->type==OB_MESH) {
Mesh *me= obedit->data;
- EditMesh *em= me->edit_mesh;
+ BMEditMesh *em= me->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMIter iter;
+ int proptrans= 0;
// transform now requires awareness for select mode, so we tag the f1 flags in verts
tottrans= 0;
- if(em->selectmode & SCE_SELECT_VERTEX) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->h==0 && (eve->f & SELECT)) {
- eve->f1= SELECT;
+ if(em->bm->selectmode & SCE_SELECT_VERTEX) {
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)) {
+ BMINDEX_SET(eve, 1);
tottrans++;
}
- else eve->f1= 0;
+ else BMINDEX_SET(eve, 0);
}
}
- else if(em->selectmode & SCE_SELECT_EDGE) {
- EditEdge *eed;
- for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0 && (eed->f & SELECT)) eed->v1->f1= eed->v2->f1= SELECT;
+ else if(em->bm->selectmode & SCE_SELECT_EDGE) {
+ BMEdge *eed;
+
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
+ BMINDEX_SET(eve, 0);
+
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if(!BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SELECT))
+ BMINDEX_SET(eed->v1, 1), BMINDEX_SET(eed->v2, 1);
}
- for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
+
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
+ if(BMINDEX_GET(eve)) tottrans++;
}
else {
- EditFace *efa;
- for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0 && (efa->f & SELECT)) {
- efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
- if(efa->v4) efa->v4->f1= SELECT;
+ BMFace *efa;
+
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
+ BMINDEX_SET(eve, 0);
+
+ BM_ITER(efa, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if(!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT)) {
+ BMIter liter;
+ BMLoop *l;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) {
+ BMINDEX_SET(l->v, 1);
+ }
+ }
+ }
+
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
+ if(BMINDEX_GET(eve)) tottrans++;
+ }
+
+ /* proportional edit exception... */
+ if((mode & 1) && tottrans) {
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(BMINDEX_GET(eve)) tottrans++;
+ if(!BM_TestHFlag(eve, BM_HIDDEN)) {
+ BMINDEX_SET(eve, BMINDEX_GET(eve)|2);
+ proptrans++;
}
}
- for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
+ if(proptrans>tottrans) tottrans= proptrans;
}
/* and now make transverts */
if(tottrans) {
tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts");
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f1) {
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(BMINDEX_GET(eve)) {
VECCOPY(tv->oldloc, eve->co);
tv->loc= eve->co;
if(eve->no[0]!=0.0 || eve->no[1]!=0.0 ||eve->no[2]!=0.0)
tv->nor= eve->no; // note this is a hackish signal (ton)
- tv->flag= eve->f1 & SELECT;
+ tv->flag= BMINDEX_GET(eve) & SELECT;
tv++;
}
}
@@ -866,10 +897,10 @@ static int snap_curs_to_active(bContext *C, wmOperator *UNUSED(op))
if (obedit->type == OB_MESH) {
/* check active */
Mesh *me= obedit->data;
- EditSelection ese;
+ BMEditSelection ese;
- if (EM_get_actSelection(me->edit_mesh, &ese)) {
- EM_editselection_center(curs, &ese);
+ if (EDBM_get_actSelection(me->edit_btmesh, &ese)) {
+ EDBM_editselection_center(me->edit_btmesh, curs, &ese);
}
mul_m4_v3(obedit->obmat, curs);
diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c
index bfe324df51e..3292c5d396c 100644
--- a/source/blender/editors/space_view3d/view3d_toolbar.c
+++ b/source/blender/editors/space_view3d/view3d_toolbar.c
@@ -272,3 +272,27 @@ void VIEW3D_OT_toolshelf(wmOperatorType *ot)
/* flags */
ot->flag= 0;
}
+
+
+#ifdef EVENT_RECORDER
+static int view3d_evtrec(bContext *C, wmOperator *op)
+{
+
+ CTX_rec_events_set(C, !CTX_rec_events(C));
+
+ return OPERATOR_FINISHED;
+}
+
+void VIEW3D_OT_evtrec(wmOperatorType *ot)
+{
+ ot->name= "Toggle Event Recorder";
+ ot->description= "Toggles event recorder";
+ ot->idname= "VIEW3D_OT_evtrec";
+
+ ot->exec= view3d_evtrec;
+ ot->poll= ED_operator_view3d_active;
+
+ /* flags */
+ ot->flag= 0;
+}
+#endif
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 36485b9e20e..794088de20c 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -710,11 +710,12 @@ void view3d_unproject(bglMats *mats, float out[3], const short x, const short y,
out[2] = uz;
}
-/* use above call to get projecting mat */
+/* use view3d_get_object_project_mat to get projecting mat */
void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4])
{
float vec4[4];
+ VECCOPY(vec4, vec);
adr[0]= IS_CLIPPED;
copy_v3_v3(vec4, vec);
vec4[3]= 1.0;
@@ -729,6 +730,26 @@ void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4])
}
}
+/* use view3d_get_object_project_mat to get projecting mat */
+void view3d_project_float_v3(ARegion *ar, float *vec, float *adr, float mat[4][4])
+{
+ float vec4[4];
+
+ VECCOPY(vec4, vec);
+ adr[0]= IS_CLIPPED;
+ vec4[3]= 1.0;
+
+ mul_m4_v4(mat, vec4);
+
+ if( vec4[3]>FLT_EPSILON ) {
+ adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];
+ adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
+ adr[2] = vec4[2]/vec4[3];
+ } else {
+ adr[0] = adr[1] = adr[2] = 0.0f;
+ }
+}
+
int boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb)
{
/* return 1: draw */
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 6758b94f53f..f31d7ba6449 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenkernel
../../blenloader
../../blenlib
+ ../../bmesh
../../makesdna
../../makesrna
../../windowmanager
diff --git a/source/blender/editors/transform/SConscript b/source/blender/editors/transform/SConscript
index edc2156a07b..9b59466bbc0 100644
--- a/source/blender/editors/transform/SConscript
+++ b/source/blender/editors/transform/SConscript
@@ -6,6 +6,10 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../render/extern/include'
+<<<<<<< .working
+incs += ' ../../gpu ../../makesrna ../../bmesh'
+=======
incs += ' ../../gpu ../../makesrna ../../blenloader'
+>>>>>>> .merge-right.r35190
env.BlenderLib ( 'bf_editors_transform', sources, Split(incs), [], libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 62cead972b9..f4ef67234e0 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -93,6 +93,7 @@
#include "BLI_editVert.h"
#include "BLI_ghash.h"
#include "BLI_linklist.h"
+#include "BLI_smallhash.h"
#include "UI_resources.h"
@@ -3468,7 +3469,8 @@ static void applyTranslation(TransInfo *t, float vec[3]) {
protectedTransBits(td->protectflag, tvec);
- add_v3_v3v3(td->loc, td->iloc, tvec);
+ if (td->loc)
+ add_v3_v3v3(td->loc, td->iloc, tvec);
constraintTransLim(t, td);
}
@@ -4273,11 +4275,340 @@ int BoneEnvelope(TransInfo *t, short UNUSED(mval[2]))
}
/* ******************** Edge Slide *************** */
+#if 0
+static int createSlideVerts(TransInfo *t) {
+#else
+static BMEdge *get_other_edge(BMesh *bm, BMVert *v, BMEdge *e)
+{
+ BMIter iter;
+ BMEdge *e2;
+
+ BM_ITER(e2, &iter, bm, BM_EDGES_OF_VERT, v) {
+ if (BM_TestHFlag(e2, BM_SELECT) && e2 != e)
+ return e2;
+ }
+
+ return NULL;
+}
+
+static BMLoop *get_next_loop(BMesh *UNUSED(bm), BMVert *v, BMLoop *l,
+ BMEdge *olde, BMEdge *nexte, float vec[3])
+{
+ BMLoop *firstl;
+ float a[3] = {0.0f, 0.0f, 0.0f}, n[3] = {0.0f, 0.0f, 0.0f};
+ int i=0;
+
+ firstl = l;
+ do {
+ l = BM_OtherFaceLoop(l->e, l->f, v);
+ if (l->radial_next == l)
+ return NULL;
+
+ if (l->e == nexte) {
+ if (i) {
+ mul_v3_fl(a, 1.0f / (float)i);
+ } else {
+ float f1[3], f2[3], f3[3];
+
+ sub_v3_v3v3(f1, BM_OtherEdgeVert(olde, v)->co, v->co);
+ sub_v3_v3v3(f2, BM_OtherEdgeVert(nexte, v)->co, v->co);
+
+ cross_v3_v3v3(f3, f1, l->f->no);
+ cross_v3_v3v3(a, f2, l->f->no);
+ mul_v3_fl(a, -1.0f);
+
+ add_v3_v3(a, f3);
+ mul_v3_fl(a, 0.5f);
+ }
+
+ VECCOPY(vec, a);
+ return l;
+ } else {
+ sub_v3_v3v3(n, BM_OtherEdgeVert(l->e, v)->co, v->co);
+ add_v3_v3v3(a, a, n);
+ i += 1;
+ }
+
+ if (BM_OtherFaceLoop(l->e, l->f, v)->e == nexte) {
+ if (i)
+ mul_v3_fl(a, 1.0f / (float)i);
+
+ VECCOPY(vec, a);
+ return BM_OtherFaceLoop(l->e, l->f, v);
+ }
+
+ l = l->radial_next;
+ } while (l != firstl);
+
+ if (i)
+ mul_v3_fl(a, 1.0f / (float)i);
+
+ VECCOPY(vec, a);
+
+ return NULL;
+}
static int createSlideVerts(TransInfo *t)
{
Mesh *me = t->obedit->data;
- EditMesh *em = me->edit_mesh;
+ BMEditMesh *em = me->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMIter iter, iter2;
+ BMEdge *e, *e1, *ee, *le;
+ BMVert *v, *v2, *first;
+ BMLoop *l, *l1, *l2;
+ TransDataSlideVert *tempsv;
+ BMBVHTree *btree = BMBVH_NewBVH(em);
+ SmallHash table;
+ SlideData *sld = MEM_callocN(sizeof(*sld), "sld");
+ RegionView3D *v3d = t->ar->regiondata;
+ ARegion *ar = t->ar;
+ float projectMat[4][4];
+ float start[3] = {0.0f, 0.0f, 0.0f}, dir[3], end[3] = {0.0f, 0.0f, 0.0f};
+ float vec[3], vec2[3], lastvec[3], size, dis=0.0, z;
+ int numsel, i, j;
+
+ if (!v3d) {
+ /*ok, let's try to survive this*/
+ unit_m4(projectMat);
+ } else {
+ view3d_get_object_project_mat(v3d, t->obedit, projectMat);
+ }
+
+ BLI_smallhash_init(&table);
+
+ /*ensure valid selection*/
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(v, BM_SELECT)) {
+ numsel = 0;
+ BM_ITER(e, &iter2, em->bm, BM_EDGES_OF_VERT, v) {
+ if (BM_TestHFlag(e, BM_SELECT)) {
+ /*BMESH_TODO: this is probably very evil,
+ set v->e to a selected edge*/
+ v->e = e;
+
+ numsel++;
+ }
+ }
+
+ if (numsel > 2) {
+ return 0; //invalid edge selection
+ }
+ }
+ }
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(e, BM_SELECT)) {
+ if (BM_Edge_FaceCount(e) > 2 || BM_Edge_FaceCount(e) == 0)
+ return 0; //can't handle more then 2 faces around an edge
+ }
+ }
+
+ j = 0;
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(v, BM_SELECT)) {
+ BMINDEX_SET(v, 1);
+ BLI_smallhash_insert(&table, (intptr_t)v, SET_INT_IN_POINTER(j));
+ j += 1;
+ } else BMINDEX_SET(v, 0);
+ }
+
+ if (!j)
+ return 0;
+
+ tempsv = MEM_callocN(sizeof(TransDataSlideVert)*j, "tempsv");
+
+ j = 0;
+ while (1) {
+ v = NULL;
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMINDEX_GET(v))
+ break;
+
+ }
+
+ if (!v)
+ break;
+
+ if (!v->e)
+ continue;
+
+ first = v;
+
+ /*walk along the edge loop*/
+ e = v->e;
+
+ /*first, rewind*/
+ numsel = 0;
+ do {
+ e = get_other_edge(bm, v, e);
+ if (!e) {
+ e = v->e;
+ break;
+ }
+
+ numsel += 1;
+
+ if (!BMINDEX_GET(BM_OtherEdgeVert(e, v)))
+ break;
+
+ v = BM_OtherEdgeVert(e, v);
+ } while (e != first->e);
+
+ BMINDEX_SET(v, 0);
+
+ l1 = l2 = l = NULL;
+ l1 = e->l;
+ l2 = e->l->radial_next;
+
+ l = BM_OtherFaceLoop(l1->e, l1->f, v);
+ sub_v3_v3v3(vec, BM_OtherEdgeVert(l->e, v)->co, v->co);
+
+ if (l2 != l1) {
+ l = BM_OtherFaceLoop(l2->e, l2->f, v);
+ sub_v3_v3v3(vec2, BM_OtherEdgeVert(l->e, v)->co, v->co);
+ } else {
+ l2 = NULL;
+ }
+
+ /*iterate over the loop*/
+ first = v;
+ j = 0;
+ do {
+ TransDataSlideVert *sv = tempsv + j;
+
+ sv->v = v;
+ sv->origvert = *v;
+ VECCOPY(sv->upvec, vec);
+ if (l2)
+ VECCOPY(sv->downvec, vec2);
+
+ l = BM_OtherFaceLoop(l1->e, l1->f, v);
+ sv->up = BM_OtherEdgeVert(l->e, v);
+
+ if (l2) {
+ l = BM_OtherFaceLoop(l2->e, l2->f, v);
+ sv->down = BM_OtherEdgeVert(l->e, v);
+ }
+
+ v2=v, v = BM_OtherEdgeVert(e, v);
+
+ e1 = e;
+ e = get_other_edge(bm, v, e);
+ if (!e) {
+ //v2=v, v = BM_OtherEdgeVert(l1->e, v);
+
+ sv = tempsv + j + 1;
+ sv->v = v;
+ sv->origvert = *v;
+
+ l = BM_OtherFaceLoop(l1->e, l1->f, v);
+ sv->up = BM_OtherEdgeVert(l->e, v);
+ sub_v3_v3v3(sv->upvec, BM_OtherEdgeVert(l->e, v)->co, v->co);
+
+ if (l2) {
+ l = BM_OtherFaceLoop(l2->e, l2->f, v);
+ sv->down = BM_OtherEdgeVert(l->e, v);
+ sub_v3_v3v3(sv->downvec, BM_OtherEdgeVert(l->e, v)->co, v->co);
+ }
+
+ BMINDEX_SET(v, 0);
+ BMINDEX_SET(v2, 0);
+
+ j += 2;
+ break;
+ }
+
+ l1 = get_next_loop(bm, v, l1, e1, e, vec);
+ l2 = l2 ? get_next_loop(bm, v, l2, e1, e, vec2) : NULL;
+
+ j += 1;
+
+ BMINDEX_SET(v, 0);
+ BMINDEX_SET(v2, 0);
+ } while (e != first->e && l1);
+ }
+
+ //EDBM_clear_flag_all(em, BM_SELECT);
+
+ sld->sv = tempsv;
+ sld->totsv = j;
+
+ /*find mouse vector*/
+ dis = z = -1.0f;
+ size = 50.0;
+ zero_v3(lastvec); zero_v3(dir);
+ ee = le = NULL;
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(e, BM_SELECT)) {
+ BMIter iter2;
+ BMEdge *e2;
+ float vec1[3], dis2, mval[2] = {t->mval[0], t->mval[1]}, d;
+
+ /*search cross edges for visible edge to the mouse cursor,
+ then use the shared vertex to calculate screen vector*/
+ dis2 = -1.0f;
+ for (i=0; i<2; i++) {
+ v = i?e->v1:e->v2;
+ BM_ITER(e2, &iter2, em->bm, BM_EDGES_OF_VERT, v) {
+ if (BM_TestHFlag(e2, BM_SELECT))
+ continue;
+
+ if (!BMBVH_EdgeVisible(btree, e2, v3d, t->obedit))
+ continue;
+
+
+ j = GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (intptr_t)v));
+
+ if (tempsv[j].down) {
+ view3d_project_float_v3(ar, tempsv[j].down->co, vec1, projectMat);
+ } else {
+ add_v3_v3v3(vec1, v->co, tempsv[j].downvec);
+ view3d_project_float_v3(ar, vec1, vec1, projectMat);
+ }
+
+ if (tempsv[j].up) {
+ view3d_project_float_v3(ar, tempsv[j].up->co, vec2, projectMat);
+ } else {
+ add_v3_v3v3(vec1, v->co, tempsv[j].upvec);
+ view3d_project_float_v3(ar, vec2, vec2, projectMat);
+ }
+
+ d = dist_to_line_segment_v2(mval, vec1, vec2);
+ if (dis2 == -1.0f || d < dis2) {
+ dis2 = d;
+ ee = e2;
+ size = len_v3v3(vec1, vec2);
+ sub_v3_v3v3(dir, vec1, vec2);
+ }
+ }
+ }
+ }
+ }
+
+ /*zero out start*/
+ zero_v3(start);
+
+ /*dir holds a vector along edge loop*/
+ copy_v3_v3(end, dir);
+ mul_v3_fl(end, 0.5);
+
+ sld->start[0] = t->mval[0] + start[0];
+ sld->start[1] = t->mval[1] + start[1];
+
+ sld->end[0] = t->mval[0] + end[0];
+ sld->end[1] = t->mval[1] + end[1];
+
+ t->customData = sld;
+
+ BLI_smallhash_release(&table);
+ BMBVH_FreeBVH(btree);
+
+ return 1;
+#endif
+#if 0
+ Mesh *me = t->obedit->data;
+ BMEditMesh *em = me->edit_btmesh;
EditFace *efa;
EditEdge *eed,*first=NULL,*last=NULL, *temp = NULL;
EditVert *ev, *nearest = NULL;
@@ -4766,10 +5097,12 @@ static int createSlideVerts(TransInfo *t)
t->customData = sld;
return 1;
+#endif
}
void freeSlideVerts(TransInfo *t)
{
+#if 0
TransDataSlideUv *suv;
SlideData *sld = t->customData;
Mesh *me = t->obedit->data;
@@ -4813,6 +5146,7 @@ void freeSlideVerts(TransInfo *t)
MEM_freeN(sld);
t->customData = NULL;
+#endif
}
void initEdgeSlide(TransInfo *t)
@@ -4851,6 +5185,26 @@ void initEdgeSlide(TransInfo *t)
int doEdgeSlide(TransInfo *t, float perc)
{
+ SlideData *sld = t->customData;
+ TransDataSlideVert *svlist = sld->sv, *sv;
+ float vec[3];
+ int i;
+
+ sv = svlist;
+ for (i=0; i<sld->totsv; i++, sv++) {
+ if (perc > 0.0f) {
+ VECCOPY(vec, sv->upvec);
+ mul_v3_fl(vec, perc);
+ add_v3_v3v3(sv->v->co, sv->origvert.co, vec);
+ } else {
+ VECCOPY(vec, sv->downvec);
+ mul_v3_fl(vec, -perc);
+ add_v3_v3v3(sv->v->co, sv->origvert.co, vec);
+ }
+ }
+
+ return 1;
+#if 0
Mesh *me= t->obedit->data;
EditMesh *em = me->edit_mesh;
SlideData *sld = t->customData;
@@ -4957,6 +5311,7 @@ int doEdgeSlide(TransInfo *t, float perc)
}
return 1;
+#endif
}
int EdgeSlide(TransInfo *t, short UNUSED(mval[2]))
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 71480ce5e7d..c01aa89d717 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -36,6 +36,7 @@
#include "DNA_listBase.h"
#include "BLI_editVert.h"
+#include "BKE_tessmesh.h"
/* ************************** Types ***************************** */
@@ -202,16 +203,26 @@ typedef struct TransDataSlideUv {
} TransDataSlideUv;
typedef struct TransDataSlideVert {
- struct EditEdge *up, *down;
- struct EditVert origvert;
+ struct BMVert vup, vdown;
+ struct BMVert origvert;
+
+ struct BMVert *up, *down;
+ struct BMVert *v;
+
+ float upvec[3], downvec[3];
} TransDataSlideVert;
typedef struct SlideData {
+ TransDataSlideVert *sv;
+ int totsv;
+
+ /*
TransDataSlideUv *slideuv, *suv_last;
int totuv, uvlay_tot;
struct GHash *vhash, **uvhash;
struct EditVert *nearest;
struct LinkNode *edgelist, *vertlist;
+ */
short start[2], end[2];
} SlideData;
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index a3247b72115..4427e472412 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -229,7 +229,7 @@ static void axisProjection(TransInfo *t, float axis[3], float in[3], float out[3
mul_v3_fl(out, 1000000000);
} else {
mul_v3_fl(out, -1000000000);
- }
+ }
} else {
add_v3_v3v3(v2, t->con.center, axis);
add_v3_v3v3(v4, v, norm);
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index d1bf030e17c..e55e6ba33e9 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -69,6 +69,7 @@
#include "BKE_sequencer.h"
#include "BKE_pointcache.h"
#include "BKE_bmesh.h"
+#include "BKE_tessmesh.h"
#include "BKE_scene.h"
#include "BKE_report.h"
@@ -92,6 +93,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_editVert.h"
+#include "BLI_array.h"
#include "BLI_utildefines.h"
#include "RNA_access.h"
@@ -99,6 +101,7 @@
extern ListBase editelems;
#include "transform.h"
+#include "bmesh.h"
#include "BLO_sys_types.h" // for intptr_t support
@@ -284,18 +287,20 @@ static void createTransTexspace(TransInfo *t)
/* ********************* edge (for crease) ***** */
static void createTransEdge(TransInfo *t) {
- EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh;
+ BMEditMesh *em = ((Mesh *)t->obedit->data)->edit_btmesh;
TransData *td = NULL;
- EditEdge *eed;
+ BMEdge *eed;
+ BMIter iter;
float mtx[3][3], smtx[3][3];
int count=0, countsel=0;
int propmode = t->flag & T_PROP_EDIT;
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0) {
- if (eed->f & SELECT) countsel++;
- if (propmode) count++;
- }
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(eed, BM_HIDDEN))
+ continue;
+
+ if (BM_TestHFlag(eed, BM_SELECT)) countsel++;
+ if (propmode) count++;
}
if (countsel == 0)
@@ -313,14 +318,17 @@ static void createTransEdge(TransInfo *t) {
copy_m3_m4(mtx, t->obedit->obmat);
invert_m3_m3(smtx, mtx);
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0 && (eed->f & SELECT || propmode)) {
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if(!BM_TestHFlag(eed, BM_HIDDEN) && (BM_TestHFlag(eed, BM_SELECT) || propmode)) {
+ float *bweight = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_BWEIGHT);
+ float *crease = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE);
+
/* need to set center for center calculations */
add_v3_v3v3(td->center, eed->v1->co, eed->v2->co);
mul_v3_fl(td->center, 0.5f);
td->loc= NULL;
- if (eed->f & SELECT)
+ if (BM_TestHFlag(eed, BM_SELECT))
td->flag= TD_SELECTED;
else
td->flag= 0;
@@ -331,12 +339,12 @@ static void createTransEdge(TransInfo *t) {
td->ext = NULL;
if (t->mode == TFM_BWEIGHT) {
- td->val = &(eed->bweight);
- td->ival = eed->bweight;
+ td->val = bweight;
+ td->ival = bweight ? *bweight : 1.0f;
}
else {
- td->val = &(eed->crease);
- td->ival = eed->crease;
+ td->val = crease;
+ td->ival = crease ? *crease : 0.0f;
}
td++;
@@ -1895,22 +1903,54 @@ static void editmesh_set_connectivity_distance(EditMesh *em, float mtx[][3])
}
/* loop-in-a-loop I know, but we need it! (ton) */
-static void get_face_center(float *cent, EditMesh *em, EditVert *eve)
+ static void get_face_center(float *centout, BMesh *bm, BMVert *eve)
+
{
- EditFace *efa;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter;
+ float cent[3] = {0.0, 0.0, 0.0};
- for(efa= em->faces.first; efa; efa= efa->next)
- if(efa->f & SELECT)
- if(efa->v1==eve || efa->v2==eve || efa->v3==eve || efa->v4==eve)
- break;
- if(efa) {
- VECCOPY(cent, efa->cent);
+ efa = BMIter_New(&iter, bm, BM_FACES_OF_VERT, eve);
+ if (efa) {
+ l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, efa);
+ for ( ; l; l=BMIter_Step(&iter)) {
+ VECADD(cent, cent, l->v->co);
+ }
+
+ mul_v3_fl(cent, 1.0f / (float)efa->len);
}
+
+ if (cent[0] == 0.0f && cent[1] == 0.0f && cent[2] == 0.0f) cent[2] = 1.0f;
+ copy_v3_v3(centout, cent);
}
+#define VertsToTransData(t, td, em, eve, bweight) \
+ td->flag = 0;\
+ td->loc = eve->co;\
+ VECCOPY(td->center, td->loc);\
+ if(t->around==V3D_LOCAL && (em->selectmode & SCE_SELECT_FACE))\
+ get_face_center(td->center, em, eve);\
+ VECCOPY(td->iloc, td->loc);\
+ VECCOPY(td->axismtx[2], eve->no);\
+ td->axismtx[0][0] =\
+ td->axismtx[0][1] =\
+ td->axismtx[0][2] =\
+ td->axismtx[1][0] =\
+ td->axismtx[1][1] =\
+ td->axismtx[1][2] = 0.0f;\
+ td->ext = NULL;\
+ td->val = NULL;\
+ td->extra = NULL;\
+ if (t->mode == TFM_BWEIGHT) {\
+ td->val = bweight;\
+ td->ival = bweight ? *(bweight) : 1.0f;\
+ }
+
+#if 0
//way to overwrite what data is edited with transform
//static void VertsToTransData(TransData *td, EditVert *eve, BakeKey *key)
-static void VertsToTransData(TransInfo *t, TransData *td, EditMesh *em, EditVert *eve)
+inline void VertsToTransData(TransInfo *t, TransData *td, BMesh *em, BMVert *eve)
{
td->flag = 0;
//if(key)
@@ -1940,9 +1980,152 @@ static void VertsToTransData(TransInfo *t, TransData *td, EditMesh *em, EditVert
td->ival = eve->bweight;
}
}
+#endif
+
+/* *********************** CrazySpace correction. Now without doing subsurf optimal ****************** */
+
+static void make_vertexcos__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
+{
+ float *vec = userData;
+
+ vec+= 3*index;
+ VECCOPY(vec, co);
+}
+
+static int modifiers_disable_subsurf_temporary(Object *ob)
+{
+ ModifierData *md;
+ int disabled = 0;
+
+ for(md=ob->modifiers.first; md; md=md->next)
+ if(md->type==eModifierType_Subsurf)
+ if(md->mode & eModifierMode_OnCage) {
+ md->mode ^= eModifierMode_DisableTemporary;
+ disabled= 1;
+ }
+
+ return disabled;
+}
+
+/* disable subsurf temporal, get mapped cos, and enable it */
+static float *get_crazy_mapped_editverts(TransInfo *t)
+{
+ Mesh *me= t->obedit->data;
+ DerivedMesh *dm;
+ float *vertexcos;
+
+ /* disable subsurf temporal, get mapped cos, and enable it */
+ if(modifiers_disable_subsurf_temporary(t->obedit)) {
+ /* need to make new derivemesh */
+ makeDerivedMesh(t->scene, t->obedit, me->edit_btmesh, CD_MASK_BAREMESH);
+ }
+
+ /* now get the cage */
+ dm= editbmesh_get_derived_cage(t->scene, t->obedit, me->edit_btmesh, CD_MASK_BAREMESH);
+
+ vertexcos= MEM_mallocN(3*sizeof(float)*me->edit_btmesh->bm->totvert, "vertexcos map");
+ dm->foreachMappedVert(dm, make_vertexcos__mapFunc, vertexcos);
+
+ dm->release(dm);
+
+ /* set back the flag, no new cage needs to be built, transform does it */
+ modifiers_disable_subsurf_temporary(t->obedit);
+
+ return vertexcos;
+}
+
+#define TAN_MAKE_VEC(a, b, c) a[0]= b[0] + 0.2f*(b[0]-c[0]); a[1]= b[1] + 0.2f*(b[1]-c[1]); a[2]= b[2] + 0.2f*(b[2]-c[2])
+static void set_crazy_vertex_quat(float *quat, float *v1, float *v2, float *v3, float *def1, float *def2, float *def3)
+{
+ float vecu[3], vecv[3];
+ float q1[4], q2[4];
+
+ TAN_MAKE_VEC(vecu, v1, v2);
+ TAN_MAKE_VEC(vecv, v1, v3);
+ tri_to_quat( q1,v1, vecu, vecv);
+
+ TAN_MAKE_VEC(vecu, def1, def2);
+ TAN_MAKE_VEC(vecv, def1, def3);
+ tri_to_quat( q2,def1, vecu, vecv);
+
+ sub_qt_qtqt(quat, q2, q1);
+}
+#undef TAN_MAKE_VEC
+static void set_crazyspace_quats(BMEditMesh *em, float *origcos, float *mappedcos, float *quats)
+{
#if 0
+ BMVert *eve, *prev;
+ BMFace *efa;
+ float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4;
+ intptr_t index= 0;
+
+ /* two abused locations in vertices */
+ for(eve= em->verts.first; eve; eve= eve->next, index++) {
+ eve->tmp.p = NULL;
+ eve->prev= (BMVert *)index;
+ }
+
+ /* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */
+ for(efa= em->faces.first; efa; efa= efa->next) {
+
+ /* retrieve mapped coordinates */
+ v1= mappedcos + 3*(intptr_t)(efa->v1->prev);
+ v2= mappedcos + 3*(intptr_t)(efa->v2->prev);
+ v3= mappedcos + 3*(intptr_t)(efa->v3->prev);
+
+ co1= (origcos)? origcos + 3*(intptr_t)(efa->v1->prev): efa->v1->co;
+ co2= (origcos)? origcos + 3*(intptr_t)(efa->v2->prev): efa->v2->co;
+ co3= (origcos)? origcos + 3*(intptr_t)(efa->v3->prev): efa->v3->co;
+
+ if(efa->v2->tmp.p==NULL && efa->v2->f1) {
+ set_crazy_vertex_quat(quats, co2, co3, co1, v2, v3, v1);
+ efa->v2->tmp.p= (void*)quats;
+ quats+= 4;
+ }
+
+ if(efa->v4) {
+ v4= mappedcos + 3*(intptr_t)(efa->v4->prev);
+ co4= (origcos)? origcos + 3*(intptr_t)(efa->v4->prev): efa->v4->co;
+
+ if(efa->v1->tmp.p==NULL && efa->v1->f1) {
+ set_crazy_vertex_quat(quats, co1, co2, co4, v1, v2, v4);
+ efa->v1->tmp.p= (void*)quats;
+ quats+= 4;
+ }
+ if(efa->v3->tmp.p==NULL && efa->v3->f1) {
+ set_crazy_vertex_quat(quats, co3, co4, co2, v3, v4, v2);
+ efa->v3->tmp.p= (void*)quats;
+ quats+= 4;
+ }
+ if(efa->v4->tmp.p==NULL && efa->v4->f1) {
+ set_crazy_vertex_quat(quats, co4, co1, co3, v4, v1, v3);
+ efa->v4->tmp.p= (void*)quats;
+ quats+= 4;
+ }
+ }
+ else {
+ if(efa->v1->tmp.p==NULL && efa->v1->f1) {
+ set_crazy_vertex_quat(quats, co1, co2, co3, v1, v2, v3);
+ efa->v1->tmp.p= (void*)quats;
+ quats+= 4;
+ }
+ if(efa->v3->tmp.p==NULL && efa->v3->f1) {
+ set_crazy_vertex_quat(quats, co3, co1, co2, v3, v1, v2);
+ efa->v3->tmp.p= (void*)quats;
+ quats+= 4;
+ }
+ }
+ }
+
+ /* restore abused prev pointer */
+ for(prev= NULL, eve= em->verts.first; eve; prev= eve, eve= eve->next)
+ eve->prev= prev;
+#endif
+}
+
static void createTransBMeshVerts(TransInfo *t, BME_Mesh *bm, BME_TransData_Head *td) {
+#if 0
BME_Vert *v;
BME_TransData *vtd;
TransData *tob;
@@ -1965,25 +2148,32 @@ static void createTransBMeshVerts(TransInfo *t, BME_Mesh *bm, BME_TransData_Head
/* since td is a memarena, it can hold more transdata than actual elements
* (i.e. we can't depend on td->len to determine the number of actual elements) */
t->total = i;
-}
#endif
+ t->total = 0;
+}
static void createTransEditVerts(bContext *C, TransInfo *t)
{
ToolSettings *ts = CTX_data_tool_settings(C);
TransData *tob = NULL;
- EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh;
- EditVert *eve;
- EditVert *eve_act = NULL;
+ BMEditMesh *em = ((Mesh *)t->obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMVert *eve;
+ BMVert **nears = NULL;
+ BMIter iter;
+ BMVert *eve_act = NULL;
float *mappedcos = NULL, *quats= NULL;
float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
- int count=0, countsel=0, a, totleft;
+ float *vectors=NULL;
+ int count=0, countsel=0, a, totleft, *selstate = NULL;
+ BLI_array_declare(selstate);
int propmode = t->flag & T_PROP_EDIT;
int mirror = 0;
short selectmode = ts->selectmode;
if (t->flag & T_MIRROR)
{
+ EDBM_CacheMirrorVerts(em);
mirror = 1;
}
@@ -1994,36 +2184,56 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
// transform now requires awareness for select mode, so we tag the f1 flags in verts
if(selectmode & SCE_SELECT_VERTEX) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->h==0 && (eve->f & SELECT))
- eve->f1= SELECT;
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT))
+ BMINDEX_SET(eve, SELECT);
else
- eve->f1= 0;
+ BMINDEX_SET(eve, 0);
}
}
else if(selectmode & SCE_SELECT_EDGE) {
- EditEdge *eed;
- for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0 && (eed->f & SELECT))
- eed->v1->f1= eed->v2->f1= SELECT;
+ BMEdge *eed;
+
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for( ; eve; eve=BMIter_Step(&iter)) BMINDEX_SET(eve, 0);
+
+ eed = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);
+ for( ; eed; eed=BMIter_Step(&iter)) {
+ if(!BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SELECT))
+ BMINDEX_SET(eed->v1, SELECT), BMINDEX_SET(eed->v2, SELECT);
}
}
else {
- EditFace *efa;
- for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0 && (efa->f & SELECT)) {
- efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
- if(efa->v4) efa->v4->f1= SELECT;
+ BMFace *efa;
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for( ; eve; eve=BMIter_Step(&iter)) BMINDEX_SET(eve, 0);
+
+ efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
+ for( ; efa; efa=BMIter_Step(&iter)) {
+ if(!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT)) {
+ BMIter liter;
+ BMLoop *l;
+
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BMIter_Step(&liter)) {
+ BMINDEX_SET(l->v, SELECT);
+ }
}
}
}
- /* now we can count */
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->h==0) {
- if(eve->f1) countsel++;
+ /* now we can count. we store selection state in selstate, since
+ get_crazy_mapped_editverts messes up the index state of the
+ verts*/
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for(a=0; eve; eve=BMIter_Step(&iter), a++) {
+ BLI_array_growone(selstate);
+
+ if(!BM_TestHFlag(eve, BM_HIDDEN)) {
+ if(BMINDEX_GET(eve)) {
+ selstate[a] = 1;
+ countsel++;
+ }
if(propmode) count++;
}
}
@@ -2032,15 +2242,21 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
if (countsel==0) return;
/* check active */
- if (em->selected.last) {
- EditSelection *ese = em->selected.last;
+ if (em->bm->selected.last) {
+ BMEditSelection *ese = em->bm->selected.last;
if ( ese->type == EDITVERT ) {
- eve_act = (EditVert *)ese->data;
+ eve_act = (BMVert *)ese->data;
}
}
- if(propmode) t->total = count;
+ if(propmode) {
+ t->total = count;
+
+ /* allocating scratch arrays */
+ vectors = (float *)MEM_mallocN(t->total * 3 * sizeof(float), "scratch vectors");
+ nears = (BMVert**)MEM_mallocN(t->total * sizeof(BMVert*), "scratch nears");
+ }
else t->total = countsel;
tob= t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Mesh EditMode)");
@@ -2048,7 +2264,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
copy_m3_m4(mtx, t->obedit->obmat);
invert_m3_m3(smtx, mtx);
- if(propmode) editmesh_set_connectivity_distance(em, mtx);
+ //BMESH_TODO if(propmode) editmesh_set_connectivity_distance(em, t->total, vectors, nears);
/* detect CrazySpace [tm] */
if(propmode==0) {
@@ -2056,7 +2272,8 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
if(modifiers_isCorrectableDeformed(t->obedit)) {
/* check if we can use deform matrices for modifier from the
start up to stack, they are more accurate than quats */
- totleft= editmesh_get_first_deform_matrices(t->scene, t->obedit, em, &defmats, &defcos);
+
+ totleft= editbmesh_get_first_deform_matrices(t->scene, t->obedit, em, &defmats, &defcos);
/* if we still have more modifiers, also do crazyspace
correction with quats, relative to the coordinates after
@@ -2077,8 +2294,9 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
/* find out which half we do */
if(mirror) {
- for (eve=em->verts.first; eve; eve=eve->next) {
- if(eve->h==0 && eve->f1 && eve->co[0]!=0.0f) {
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for(a=0; eve; eve=BMIter_Step(&iter), a++) {
+ if(!BM_TestHFlag(eve, BM_HIDDEN) && selstate[a] && eve->co[0]!=0.0f) {
if(eve->co[0]<0.0f)
{
t->mirror = -1;
@@ -2089,33 +2307,43 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
}
}
- for (a=0, eve=em->verts.first; eve; eve=eve->next, a++) {
- if(eve->h==0) {
- if(propmode || eve->f1) {
- VertsToTransData(t, tob, em, eve);
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for(a=0; eve; eve=BMIter_Step(&iter), a++) {
+ if(!BM_TestHFlag(eve, BM_HIDDEN)) {
+ if(propmode || selstate[a]) {
+ float *bweight = CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_BWEIGHT);
+
+ VertsToTransData(t, tob, bm, eve, bweight);
+
+ /* pinned */
+ if(BM_TestHFlag(eve,BM_PINNED)) tob->flag |= TD_SKIP;
/* selected */
- if(eve->f1) tob->flag |= TD_SELECTED;
+ if(selstate[a]) tob->flag |= TD_SELECTED;
/* active */
if(eve == eve_act) tob->flag |= TD_ACTIVE;
if(propmode) {
+ /*BMESH_TODO
+ this has to do with edge connectivity
+ PEP mode, I think. -joeedh
if (eve->f2) {
tob->dist= eve->tmp.fp;
}
- else {
+ else {*/
tob->flag |= TD_NOTCONNECTED;
tob->dist = MAXFLOAT;
- }
+ //}
}
/* CrazySpace */
- if(defmats || (quats && eve->tmp.p)) {
+ if(defmats) { // || (quats && eve->tmp.p)) {
float mat[3][3], imat[3][3], qmat[3][3];
/* use both or either quat and defmat correction */
- if(quats && eve->tmp.f) {
+ //BMESH_TODO, need to restore this quats thing
+ /*if(quats && eve->tmp.f) {
quat_to_mat3( qmat,eve->tmp.p);
if(defmats)
@@ -2124,7 +2352,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
else
mul_m3_m3m3(mat, mtx, qmat);
}
- else
+ else*/
mul_m3_m3m3(mat, mtx, defmats[a]);
invert_m3_m3(imat, mat);
@@ -2138,9 +2366,11 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
}
/* Mirror? */
+
+ //BMESH_TODO
if( (mirror>0 && tob->iloc[0]>0.0f) || (mirror<0 && tob->iloc[0]<0.0f)) {
- EditVert *vmir= editmesh_get_x_mirror_vert(t->obedit, em, eve, tob->iloc, a); /* initializes octree on first call */
- if(vmir != eve) {
+ BMVert *vmir= EDBM_GetMirrorVert(em, eve); //t->obedit, em, eve, tob->iloc, a);
+ if(vmir && vmir != eve) {
tob->extra = vmir;
}
}
@@ -2161,11 +2391,20 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
}
}
+
/* crazy space free */
if(quats)
MEM_freeN(quats);
if(defmats)
MEM_freeN(defmats);
+
+ BLI_array_free(selstate);
+
+ if (t->flag & T_MIRROR)
+ {
+ EDBM_EndMirrorCache(em);
+ mirror = 1;
+ }
}
/* *** NODE EDITOR *** */
@@ -2321,30 +2560,33 @@ static void createTransUVs(bContext *C, TransInfo *t)
Scene *scene = t->scene;
TransData *td = NULL;
TransData2D *td2d = NULL;
- MTFace *tf;
+ MTexPoly *tf;
+ MLoopUV *luv;
+ BMEditMesh *em = ((Mesh *)t->obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
int count=0, countsel=0;
int propmode = t->flag & T_PROP_EDIT;
- EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh;
- EditFace *efa;
-
if(!ED_space_image_show_uvedit(sima, t->obedit)) return;
/* count */
- for (efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- efa->tmp.p = tf;
+ if(!uvedit_face_visible(scene, ima, efa, tf)) {
+ BMINDEX_SET(efa, 0);
+ continue;
+ }
+
+ BMINDEX_SET(efa, 1);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (uvedit_uv_selected(em, scene, l))
+ countsel++;
- if (uvedit_uv_selected(scene, efa, tf, 0)) countsel++;
- if (uvedit_uv_selected(scene, efa, tf, 1)) countsel++;
- if (uvedit_uv_selected(scene, efa, tf, 2)) countsel++;
- if (efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) countsel++;
if(propmode)
- count += (efa->v4)? 4: 3;
- } else {
- efa->tmp.p = NULL;
+ count += efa->len;
}
}
@@ -2363,20 +2605,17 @@ static void createTransUVs(bContext *C, TransInfo *t)
td= t->data;
td2d= t->data2d;
- for (efa= em->faces.first; efa; efa= efa->next) {
- if ((tf=(MTFace *)efa->tmp.p)) {
- if (propmode) {
- UVsToTransData(sima, td++, td2d++, tf->uv[0], uvedit_uv_selected(scene, efa, tf, 0));
- UVsToTransData(sima, td++, td2d++, tf->uv[1], uvedit_uv_selected(scene, efa, tf, 1));
- UVsToTransData(sima, td++, td2d++, tf->uv[2], uvedit_uv_selected(scene, efa, tf, 2));
- if(efa->v4)
- UVsToTransData(sima, td++, td2d++, tf->uv[3], uvedit_uv_selected(scene, efa, tf, 3));
- } else {
- if(uvedit_uv_selected(scene, efa, tf, 0)) UVsToTransData(sima, td++, td2d++, tf->uv[0], 1);
- if(uvedit_uv_selected(scene, efa, tf, 1)) UVsToTransData(sima, td++, td2d++, tf->uv[1], 1);
- if(uvedit_uv_selected(scene, efa, tf, 2)) UVsToTransData(sima, td++, td2d++, tf->uv[2], 1);
- if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) UVsToTransData(sima, td++, td2d++, tf->uv[3], 1);
- }
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMINDEX_GET(efa))
+ continue;
+
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (!propmode && !uvedit_uv_selected(em, scene, l))
+ continue;
+
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ UVsToTransData(sima, td++, td2d++, luv->uv, uvedit_uv_selected(em, scene, l));
}
}
@@ -4676,7 +4915,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
if (t->spacetype==SPACE_VIEW3D) {
if (t->obedit) {
if (cancelled==0) {
- EM_automerge(t->scene, t->obedit, 1);
+ EDBM_automerge(t->scene, t->obedit, 1);
}
}
}
@@ -4883,9 +5122,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
else if (t->obedit) {
if (t->obedit->type == OB_MESH)
{
- EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh;
+ BMEditMesh *em = ((Mesh *)t->obedit->data)->edit_btmesh;
/* table needs to be created for each edit command, since vertices can move etc */
- mesh_octree_table(t->obedit, em, NULL, 'e');
+ // BMESH_TODO mesh_octree_table(t->obedit, em, NULL, 'e');
}
}
else if ((t->flag & T_POSE) && (t->poseobj)) {
@@ -4942,8 +5181,8 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
for (i = 0; i < t->total; i++) {
TransData *td = t->data + i;
- ListBase pidlist;
- PTCacheID *pid;
+ ListBase pidlist;
+ PTCacheID *pid;
ob = td->ob;
if (td->flag & TD_NOACTION)
@@ -4960,9 +5199,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
BLI_freelistN(&pidlist);
- /* pointcache refresh */
+ /* pointcache refresh */
if (BKE_ptcache_object_reset(t->scene, ob, PTCACHE_RESET_OUTDATED))
- ob->recalc |= OB_RECALC_DATA;
+ ob->recalc |= OB_RECALC_DATA;
/* Needed for proper updating of "quick cached" dynamics. */
/* Creates troubles for moving animated objects without */
@@ -5013,7 +5252,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
#endif
}
-static void createTransObject(bContext *C, TransInfo *t)
+static void createTransObject(struct bContext *C, TransInfo *t)
{
TransData *td = NULL;
TransDataExtension *tx;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 7e44632ecb9..cf66a9f9d93 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -67,6 +67,7 @@
#include "BKE_mesh.h"
#include "BKE_nla.h"
#include "BKE_context.h"
+#include "BKE_tessmesh.h"
#include "ED_anim_api.h"
#include "ED_armature.h"
@@ -109,19 +110,19 @@ void getViewVector(TransInfo *t, float coord[3], float vec[3])
if (t->persp != RV3D_ORTHO)
{
float p1[4], p2[4];
-
+
VECCOPY(p1, coord);
p1[3] = 1.0f;
VECCOPY(p2, p1);
p2[3] = 1.0f;
mul_m4_v4(t->viewmat, p2);
-
+
p2[0] = 2.0f * p2[0];
p2[1] = 2.0f * p2[1];
p2[2] = 2.0f * p2[2];
-
+
mul_m4_v4(t->viewinv, p2);
-
+
sub_v3_v3v3(vec, p1, p2);
}
else {
@@ -137,11 +138,11 @@ static void clipMirrorModifier(TransInfo *t, Object *ob)
ModifierData *md= ob->modifiers.first;
float tolerance[3] = {0.0f, 0.0f, 0.0f};
int axis = 0;
-
+
for (; md; md=md->next) {
if (md->type==eModifierType_Mirror) {
MirrorModifierData *mmd = (MirrorModifierData*) md;
-
+
if(mmd->flag & MOD_MIR_CLIPPING) {
axis = 0;
if(mmd->flag & MOD_MIR_AXIS_X) {
@@ -160,35 +161,35 @@ static void clipMirrorModifier(TransInfo *t, Object *ob)
float mtx[4][4], imtx[4][4];
int i;
TransData *td = t->data;
-
+
if (mmd->mirror_ob) {
float obinv[4][4];
-
+
invert_m4_m4(obinv, mmd->mirror_ob->obmat);
mul_m4_m4m4(mtx, ob->obmat, obinv);
invert_m4_m4(imtx, mtx);
}
-
+
for(i = 0 ; i < t->total; i++, td++) {
int clip;
float loc[3], iloc[3];
-
+
if (td->flag & TD_NOACTION)
break;
if (td->loc==NULL)
break;
-
+
if (td->flag & TD_SKIP)
continue;
-
+
copy_v3_v3(loc, td->loc);
copy_v3_v3(iloc, td->iloc);
-
+
if (mmd->mirror_ob) {
mul_m4_v3(mtx, loc);
mul_m4_v3(mtx, iloc);
}
-
+
clip = 0;
if(axis & 1) {
if(fabs(iloc[0])<=tolerance[0] ||
@@ -197,7 +198,7 @@ static void clipMirrorModifier(TransInfo *t, Object *ob)
clip = 1;
}
}
-
+
if(axis & 2) {
if(fabs(iloc[1])<=tolerance[1] ||
loc[1]*iloc[1]<0.0f) {
@@ -220,19 +221,19 @@ static void clipMirrorModifier(TransInfo *t, Object *ob)
}
}
}
-
+
}
}
}
}
/* assumes obedit set to mesh object */
-static void editmesh_apply_to_mirror(TransInfo *t)
+static void editbmesh_apply_to_mirror(TransInfo *t)
{
TransData *td = t->data;
- EditVert *eve;
+ BMVert *eve;
int i;
-
+
for(i = 0 ; i < t->total; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -240,7 +241,7 @@ static void editmesh_apply_to_mirror(TransInfo *t)
break;
if (td->flag & TD_SKIP)
continue;
-
+
eve = td->extra;
if (eve) {
eve->co[0]= -td->loc[0];
@@ -654,8 +655,7 @@ void recalcData(TransInfo *t)
nu= nu->next;
}
}
- }
- else if(t->obedit->type==OB_LATTICE) {
+ } else if(t->obedit->type==OB_LATTICE) {
Lattice *la= t->obedit->data;
if(t->state != TRANS_CANCEL) {
@@ -667,18 +667,20 @@ void recalcData(TransInfo *t)
if(la->editlatt->latt->flag & LT_OUTSIDE) outside_lattice(la->editlatt->latt);
}
else if (t->obedit->type == OB_MESH) {
- EditMesh *em = ((Mesh*)t->obedit->data)->edit_mesh;
+ BMEditMesh *em = ((Mesh*)t->obedit->data)->edit_btmesh;
+
/* mirror modifier clipping? */
if(t->state != TRANS_CANCEL) {
clipMirrorModifier(t, t->obedit);
applyProject(t);
}
if((t->options & CTX_NO_MIRROR) == 0 && (t->flag & T_MIRROR))
- editmesh_apply_to_mirror(t);
-
+ editbmesh_apply_to_mirror(t);
+
DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
-
- recalc_editnormals(em);
+
+ EDBM_RecalcNormals(em);
+ BMEdit_RecalcTesselation(em);
}
else if(t->obedit->type==OB_ARMATURE) { /* no recalc flag, does pose */
bArmature *arm= t->obedit->data;
@@ -769,6 +771,7 @@ void recalcData(TransInfo *t)
}
DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
}
+
}
else if( (t->flag & T_POSE) && t->poseobj) {
Object *ob= t->poseobj;
@@ -848,18 +851,18 @@ void drawLine(TransInfo *t, float *center, float *dir, char axis, short options)
if (t->spacetype == SPACE_VIEW3D)
{
View3D *v3d = t->view;
-
+
glPushMatrix();
-
+
//if(t->obedit) glLoadMatrixf(t->obedit->obmat); // sets opengl viewing
-
-
+
+
copy_v3_v3(v3, dir);
mul_v3_fl(v3, v3d->far);
-
+
sub_v3_v3v3(v2, center, v3);
add_v3_v3v3(v1, center, v3);
-
+
if (options & DRAWLIGHT) {
col[0] = col[1] = col[2] = 220;
}
@@ -868,13 +871,13 @@ void drawLine(TransInfo *t, float *center, float *dir, char axis, short options)
}
UI_make_axis_color(col, col2, axis);
glColor3ubv(col2);
-
+
setlinestyle(0);
glBegin(GL_LINE_STRIP);
glVertex3fv(v1);
glVertex3fv(v2);
glEnd();
-
+
glPopMatrix();
}
}
@@ -891,33 +894,33 @@ int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
ARegion *ar = CTX_wm_region(C);
ScrArea *sa = CTX_wm_area(C);
Object *obedit = CTX_data_edit_object(C);
-
+
/* moving: is shown in drawobject() (transform color) */
// TRANSFORM_FIX_ME
// if(obedit || (t->flag & T_POSE) ) G.moving= G_TRANSFORM_EDIT;
// else if(G.f & G_PARTICLEEDIT) G.moving= G_TRANSFORM_PARTICLE;
// else G.moving= G_TRANSFORM_OBJ;
-
+
t->scene = sce;
t->sa = sa;
t->ar = ar;
t->obedit = obedit;
t->settings = ts;
-
+
t->data = NULL;
t->ext = NULL;
-
+
t->helpline = HLP_NONE;
-
+
t->flag = 0;
-
+
t->redraw = 1; /* redraw first time */
-
+
if (event)
{
t->imval[0] = event->x - t->ar->winrct.xmin;
t->imval[1] = event->y - t->ar->winrct.ymin;
-
+
t->event_type = event->type;
}
else
@@ -925,30 +928,30 @@ int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
t->imval[0] = 0;
t->imval[1] = 0;
}
-
+
t->con.imval[0] = t->imval[0];
t->con.imval[1] = t->imval[1];
-
+
t->mval[0] = t->imval[0];
t->mval[1] = t->imval[1];
-
+
t->transform = NULL;
t->handleEvent = NULL;
-
+
t->total = 0;
-
+
t->val = 0.0f;
-
+
t->vec[0] =
t->vec[1] =
t->vec[2] = 0.0f;
-
+
t->center[0] =
t->center[1] =
t->center[2] = 0.0f;
-
+
unit_m3(t->mat);
-
+
/* if there's an event, we're modal */
if (event) {
t->flag |= T_MODAL;
@@ -963,10 +966,10 @@ int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
if(t->spacetype == SPACE_VIEW3D)
{
View3D *v3d = sa->spacedata.first;
-
+
t->view = v3d;
t->animtimer= CTX_wm_screen(C)->animtimer;
-
+
/* turn manipulator off during transform */
// FIXME: but don't do this when USING the manipulator...
if (t->flag & T_MODAL) {
@@ -976,11 +979,11 @@ int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
if(v3d->flag & V3D_ALIGN) t->flag |= T_V3D_ALIGN;
t->around = v3d->around;
-
+
if (op && RNA_struct_find_property(op->ptr, "constraint_orientation") && RNA_property_is_set(op->ptr, "constraint_orientation"))
{
t->current_orientation = RNA_enum_get(op->ptr, "constraint_orientation");
-
+
if (t->current_orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C))
{
t->current_orientation = V3D_MANIP_GLOBAL;
@@ -1015,10 +1018,11 @@ int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
{
// XXX for now, get View2D from the active region
t->view = &ar->v2d;
+
// XXX for now, the center point is the midpoint of the data
t->around = V3D_CENTER;
}
-
+
if (op && RNA_property_is_set(op->ptr, "release_confirm"))
{
if (RNA_boolean_get(op->ptr, "release_confirm"))
@@ -1051,8 +1055,7 @@ int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
t->mirror = 1;
}
}
-
- /* setting PET flag only if property exist in operator. Otherwise, assume it's not supported */
+
if (op && RNA_struct_find_property(op->ptr, "proportional"))
{
if (RNA_property_is_set(op->ptr, "proportional"))
@@ -1122,7 +1125,7 @@ int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
setTransformViewMatrices(t);
initNumInput(&t->num);
initNDofInput(&t->ndof);
-
+
return 1;
}
@@ -1130,7 +1133,7 @@ int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
void postTrans (bContext *C, TransInfo *t)
{
TransData *td;
-
+
if (t->draw_handle_view)
ED_region_draw_cb_exit(t->ar->type, t->draw_handle_view);
if (t->draw_handle_apply)
@@ -1151,7 +1154,7 @@ void postTrans (bContext *C, TransInfo *t)
/* postTrans can be called when nothing is selected, so data is NULL already */
if (t->data) {
int a;
-
+
/* free data malloced per trans-data */
for(a=0, td= t->data; a<t->total; a++, td++) {
if (td->flag & TD_BEZTRIPLE)
@@ -1159,7 +1162,7 @@ void postTrans (bContext *C, TransInfo *t)
}
MEM_freeN(t->data);
}
-
+
BLI_freelistN(&t->tsnap.points);
if (t->ext) MEM_freeN(t->ext);
@@ -1167,7 +1170,7 @@ void postTrans (bContext *C, TransInfo *t)
MEM_freeN(t->data2d);
t->data2d= NULL;
}
-
+
if(t->spacetype==SPACE_IMAGE) {
SpaceImage *sima= t->sa->spacedata.first;
if(sima->flag & SI_LIVE_UNWRAP)
@@ -1185,12 +1188,19 @@ void postTrans (bContext *C, TransInfo *t)
{
MEM_freeN(t->mouse.data);
}
+
+ if (t->customFree) {
+ t->customFree(t);
+ }
+ else if (t->customData) {
+ MEM_freeN(t->customData);
+ }
}
void applyTransObjects(TransInfo *t)
{
TransData *td;
-
+
for (td = t->data; td < t->data + t->total; td++) {
VECCOPY(td->iloc, td->loc);
if (td->ext->rot) {
@@ -1226,16 +1236,16 @@ static void restoreElement(TransData *td) {
if (td->ext->size) {
VECCOPY(td->ext->size, td->ext->isize);
}
- if (td->ext->quat) {
- QUATCOPY(td->ext->quat, td->ext->iquat);
+ if (td->ext->quat) {
+ QUATCOPY(td->ext->quat, td->ext->iquat);
+ }
}
- }
-
+
if (td->flag & TD_BEZTRIPLE) {
*(td->hdata->h1) = td->hdata->ih1;
*(td->hdata->h2) = td->hdata->ih2;
}
-}
+ }
void restoreTransObjects(TransInfo *t)
{
@@ -1245,7 +1255,7 @@ void restoreTransObjects(TransInfo *t)
for (td = t->data; td < t->data + t->total; td++) {
restoreElement(td);
}
-
+
for (td2d=t->data2d; t->data2d && td2d < t->data2d + t->total; td2d++) {
if (td2d->h1) {
td2d->h1[0] = td2d->ih1[0];
@@ -1258,7 +1268,7 @@ void restoreTransObjects(TransInfo *t)
}
unit_m3(t->mat);
-
+
recalcData(t);
}
@@ -1267,7 +1277,7 @@ void calculateCenter2D(TransInfo *t)
if (t->flag & (T_EDIT|T_POSE)) {
Object *ob= t->obedit?t->obedit:t->poseobj;
float vec[3];
-
+
VECCOPY(vec, t->center);
mul_m4_v3(ob->obmat, vec);
projectIntView(t, vec, t->center2d);
@@ -1280,21 +1290,21 @@ void calculateCenter2D(TransInfo *t)
void calculateCenterCursor(TransInfo *t)
{
float *cursor;
-
+
cursor = give_cursor(t->scene, t->view);
VECCOPY(t->center, cursor);
-
+
/* If edit or pose mode, move cursor in local space */
if (t->flag & (T_EDIT|T_POSE)) {
Object *ob = t->obedit?t->obedit:t->poseobj;
float mat[3][3], imat[3][3];
-
+
sub_v3_v3v3(t->center, t->center, ob->obmat[3]);
copy_m3_m4(mat, ob->obmat);
invert_m3_m3(imat, mat);
mul_m3_v3(imat, t->center);
}
-
+
calculateCenter2D(t);
}
@@ -1309,12 +1319,12 @@ void calculateCenterCursor2D(TransInfo *t)
ED_space_image_uv_aspect(sima, &aspx, &aspy);
cursor = sima->cursor;
}
-
+
if (cursor) {
t->center[0] = cursor[0] * aspx;
t->center[1] = cursor[1] * aspy;
}
-
+
calculateCenter2D(t);
}
@@ -1335,7 +1345,7 @@ void calculateCenterMedian(TransInfo *t)
float partial[3] = {0.0f, 0.0f, 0.0f};
int total = 0;
int i;
-
+
for(i = 0; i < t->total; i++) {
if (t->data[i].flag & TD_SELECTED) {
if (!(t->data[i].flag & TD_NOCENTER))
@@ -1355,7 +1365,7 @@ void calculateCenterMedian(TransInfo *t)
if(i)
mul_v3_fl(partial, 1.0f / total);
VECCOPY(t->center, partial);
-
+
calculateCenter2D(t);
}
@@ -1385,7 +1395,7 @@ void calculateCenterBound(TransInfo *t)
}
add_v3_v3v3(t->center, min, max);
mul_v3_fl(t->center, 0.5);
-
+
calculateCenter2D(t);
}
@@ -1417,16 +1427,16 @@ void calculateCenter(TransInfo *t)
/* EDIT MODE ACTIVE EDITMODE ELEMENT */
if (t->obedit && t->obedit->type == OB_MESH) {
- EditSelection ese;
- EditMesh *em = BKE_mesh_get_editmesh(t->obedit->data);
+ BMEditSelection ese;
+ BMEditMesh *em = ((Mesh*)t->obedit->data)->edit_btmesh;
- if (EM_get_actSelection(em, &ese)) {
- EM_editselection_center(t->center, &ese);
- calculateCenter2D(t);
- break;
+ if (EDBM_get_actSelection(em, &ese)) {
+ EDBM_editselection_center(em, t->center, &ese);
+ calculateCenter2D(t);
+ break;
}
} /* END EDIT MODE ACTIVE ELEMENT */
-
+
calculateCenterMedian(t);
if((t->flag & (T_EDIT|T_POSE))==0)
{
@@ -1438,10 +1448,10 @@ void calculateCenter(TransInfo *t)
projectIntView(t, t->center, t->center2d);
}
}
-
+
}
}
-
+
/* setting constraint center */
VECCOPY(t->con.center, t->center);
if(t->flag & (T_EDIT|T_POSE))
@@ -1449,7 +1459,7 @@ void calculateCenter(TransInfo *t)
Object *ob= t->obedit?t->obedit:t->poseobj;
mul_m4_v3(ob->obmat, t->con.center);
}
-
+
/* for panning from cameraview */
if(t->flag & T_OBJECT)
{
@@ -1458,21 +1468,21 @@ void calculateCenter(TransInfo *t)
View3D *v3d = t->view;
Scene *scene = t->scene;
RegionView3D *rv3d = t->ar->regiondata;
-
+
if(v3d->camera == OBACT && rv3d->persp==RV3D_CAMOB)
{
float axis[3];
/* persinv is nasty, use viewinv instead, always right */
VECCOPY(axis, t->viewinv[2]);
normalize_v3(axis);
-
+
/* 6.0 = 6 grid units */
axis[0]= t->center[0]- 6.0f*axis[0];
axis[1]= t->center[1]- 6.0f*axis[1];
axis[2]= t->center[2]- 6.0f*axis[2];
-
+
projectIntView(t, axis, t->center2d);
-
+
/* rotate only needs correct 2d center, grab needs initgrabz() value */
if(t->mode==TFM_TRANSLATION)
{
@@ -1482,14 +1492,14 @@ void calculateCenter(TransInfo *t)
}
}
}
-
+
if(t->spacetype==SPACE_VIEW3D)
{
/* initgrabz() defines a factor for perspective depth correction, used in window_to_3d_delta() */
if(t->flag & (T_EDIT|T_POSE)) {
Object *ob= t->obedit?t->obedit:t->poseobj;
float vec[3];
-
+
VECCOPY(vec, t->center);
mul_m4_v3(ob->obmat, vec);
initgrabz(t->ar->regiondata, vec[0], vec[1], vec[2]);
@@ -1534,7 +1544,7 @@ void calculatePropRatio(TransInfo *t)
else {
/* Use rdist for falloff calculations, it is the real distance */
td->flag &= ~TD_NOACTION;
-
+
if (connected)
dist= (t->prop_size-td->dist)/t->prop_size;
else
@@ -1547,7 +1557,7 @@ void calculatePropRatio(TransInfo *t)
*/
if (dist < 0.0f)
dist = 0.0f;
-
+
switch(t->prop_mode) {
case PROP_SHARP:
td->factor= dist*dist;
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index 6483d8c1f83..a281b388084 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -56,6 +56,7 @@
#include "BKE_mesh.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
+#include "BKE_tessmesh.h"
#include "BLI_math.h"
#include "BLI_editVert.h"
@@ -293,20 +294,22 @@ int calc_manipulator_stats(const bContext *C)
if((ob->lay & v3d->lay)==0) return 0;
if(obedit->type==OB_MESH) {
- EditMesh *em = BKE_mesh_get_editmesh(obedit->data);
- EditVert *eve;
- EditSelection ese;
+ BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMVert *eve;
+ BMEditSelection ese;
+ BMIter iter;
float vec[3]= {0,0,0};
/* USE LAST SELECTE WITH ACTIVE */
- if (v3d->around==V3D_ACTIVE && EM_get_actSelection(em, &ese)) {
- EM_editselection_center(vec, &ese);
+ if (v3d->around==V3D_ACTIVE && EDBM_get_actSelection(em, &ese)) {
+ EDBM_editselection_center(em, vec, &ese);
calc_tw_center(scene, vec);
totsel= 1;
} else {
/* do vertices for center, and if still no normal found, use vertex normals */
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(BM_TestHFlag(eve, BM_SELECT)) {
totsel++;
calc_tw_center(scene, eve->co);
}
@@ -503,7 +506,7 @@ int calc_manipulator_stats(const bContext *C)
case V3D_MANIP_GIMBAL:
{
- float mat[3][3];
+ float mat[3][3];
if (gimbal_axis(ob, mat)) {
copy_m4_m3(rv3d->twmat, mat);
break;
@@ -515,8 +518,8 @@ int calc_manipulator_stats(const bContext *C)
float mat[3][3];
ED_getTransformOrientationMatrix(C, mat, (v3d->around == V3D_ACTIVE));
copy_m4_m3(rv3d->twmat, mat);
- break;
- }
+ break;
+ }
/* no break we define 'normal' as 'local' in Object mode */
case V3D_MANIP_LOCAL:
copy_m4_m4(rv3d->twmat, ob->obmat);
@@ -918,12 +921,12 @@ static void draw_manipulator_rotate(View3D *v3d, RegionView3D *rv3d, int moving,
glBegin(GL_LINES);
glVertex3f(0.0f, 0.0f, 0.2f);
glVertex3f(0.0f, 0.0f, 1.0f);
- glEnd();
+ glEnd();
postOrtho(ortho);
- }
}
}
}
+ }
if(arcs==0 && moving) {
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 0a867acd018..b63d279a42b 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -37,6 +37,7 @@
#include "BKE_armature.h"
#include "BKE_context.h"
+#include "BKE_tessmesh.h"
#include "BKE_report.h"
#include "BLI_math.h"
@@ -70,9 +71,9 @@ void BIF_clearTransformOrientation(bContext *C)
// Need to loop over all view3d
if(v3d && v3d->twmode >= V3D_MANIP_CUSTOM) {
v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global */
- }
}
-
+}
+
static TransformOrientation* findOrientationName(ListBase *lb, const char *name)
{
TransformOrientation *ts= NULL;
@@ -131,16 +132,16 @@ TransformOrientation *createObjectSpace(bContext *C, ReportList *UNUSED(reports)
ob = base->object;
-
+
copy_m3_m4(mat, ob->obmat);
normalize_m3(mat);
/* use object name if no name is given */
if (name[0] == 0)
- {
+{
strncpy(name, ob->id.name+2, 35);
}
-
+
return addMatrixSpace(C, mat, name, overwrite);
}
@@ -149,7 +150,7 @@ TransformOrientation *createBoneSpace(bContext *C, ReportList *reports, char *na
float normal[3], plane[3];
getTransformOrientation(C, normal, plane, 0);
-
+
if (createSpaceNormalTangent(mat, normal, plane) == 0) {
BKE_reports_prepend(reports, "Cannot use zero-length bone");
return NULL;
@@ -157,7 +158,7 @@ TransformOrientation *createBoneSpace(bContext *C, ReportList *reports, char *na
if (name[0] == 0)
{
- strcpy(name, "Bone");
+ strcpy(name, "Bone");
}
return addMatrixSpace(C, mat, name, overwrite);
@@ -180,7 +181,7 @@ TransformOrientation *createMeshSpace(bContext *C, ReportList *reports, char *na
if (name[0] == 0)
{
- strcpy(name, "Vertex");
+ strcpy(name, "Vertex");
}
break;
case ORIENTATION_EDGE:
@@ -191,7 +192,7 @@ TransformOrientation *createMeshSpace(bContext *C, ReportList *reports, char *na
if (name[0] == 0)
{
- strcpy(name, "Edge");
+ strcpy(name, "Edge");
}
break;
case ORIENTATION_FACE:
@@ -202,7 +203,7 @@ TransformOrientation *createMeshSpace(bContext *C, ReportList *reports, char *na
if (name[0] == 0)
{
- strcpy(name, "Face");
+ strcpy(name, "Face");
}
break;
default:
@@ -268,7 +269,7 @@ TransformOrientation* addMatrixSpace(bContext *C, float mat[3][3], char name[],
if (overwrite)
{
ts = findOrientationName(transform_spaces, name);
- }
+ }
else
{
uniqueOrientationName(transform_spaces, name);
@@ -299,14 +300,14 @@ void BIF_removeTransformOrientation(bContext *C, TransformOrientation *target) {
if(v3d) {
int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
- // Transform_fix_me NEED TO DO THIS FOR ALL VIEW3D
+ // Transform_fix_me NEED TO DO THIS FOR ALL VIEW3D
if (selected_index == i) {
v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global */
}
else if (selected_index > i) {
v3d->twmode--;
}
-
+
}
BLI_freelinkN(transform_spaces, ts);
@@ -355,7 +356,7 @@ void BIF_selectTransformOrientation(bContext *C, TransformOrientation *target) {
void BIF_selectTransformOrientationValue(bContext *C, int orientation) {
View3D *v3d = CTX_wm_view3d(C);
if(v3d) /* currently using generic poll */
- v3d->twmode = orientation;
+ v3d->twmode = orientation;
}
EnumPropertyItem *BIF_enumTransformOrientation(bContext *C)
@@ -501,15 +502,15 @@ void initTransformOrientation(bContext *C, TransInfo *t)
if(obedit || (ob && ob->mode & OB_MODE_POSE)) {
strcpy(t->spacename, "normal");
ED_getTransformOrientationMatrix(C, t->spacemtx, (v3d->around == V3D_ACTIVE));
- break;
- }
+ break;
+ }
/* no break we define 'normal' as 'local' in Object mode */
case V3D_MANIP_LOCAL:
strcpy(t->spacename, "local");
if(ob) {
- copy_m3_m4(t->spacemtx, ob->obmat);
- normalize_m3(t->spacemtx);
+ copy_m3_m4(t->spacemtx, ob->obmat);
+ normalize_m3(t->spacemtx);
} else {
unit_m3(t->spacemtx);
}
@@ -547,8 +548,8 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
Object *ob = OBACT;
int result = ORIENTATION_NONE;
- normal[0] = normal[1] = normal[2] = 0;
- plane[0] = plane[1] = plane[2] = 0;
+ normal[0] = normal[1] = normal[2] = 0.0f;
+ plane[0] = plane[1] = plane[2] = 0.0f;
if(obedit)
{
@@ -565,56 +566,56 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
if(ob->type==OB_MESH)
{
Mesh *me= ob->data;
- EditMesh *em = me->edit_mesh;
- EditVert *eve;
- EditSelection ese;
+ BMEditMesh *em = me->edit_btmesh;
+ BMVert *eve;
+ BMEditSelection ese;
float vec[3]= {0,0,0};
/* USE LAST SELECTED WITH ACTIVE */
- if (activeOnly && EM_get_actSelection(em, &ese))
+ if (activeOnly && EDBM_get_actSelection(em, &ese))
{
- EM_editselection_normal(normal, &ese);
- EM_editselection_plane(plane, &ese);
+ EDBM_editselection_normal(normal, &ese);
+ EDBM_editselection_plane(em, plane, &ese);
switch (ese.type)
{
- case EDITVERT:
+ case BM_VERT:
result = ORIENTATION_VERT;
break;
- case EDITEDGE:
+ case BM_EDGE:
result = ORIENTATION_EDGE;
break;
- case EDITFACE:
+ case BM_FACE:
result = ORIENTATION_FACE;
break;
}
}
else
{
- if (em->totfacesel >= 1)
+ if (em->bm->totfacesel >= 1)
{
- EditFace *efa;
-
- for(efa= em->faces.first; efa; efa= efa->next)
- {
- if(efa->f & SELECT)
- {
- VECADD(normal, normal, efa->n);
- sub_v3_v3v3(vec, efa->v2->co, efa->v1->co);
+ BMFace *efa;
+ BMIter iter;
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if(BM_TestHFlag(efa, BM_SELECT)) {
+ VECADD(normal, normal, efa->no);
+ sub_v3_v3v3(vec, ((BMLoopList*)efa->loops.first)->first->v->co,
+ (((BMLoopList*)efa->loops.first)->first->next)->v->co);
VECADD(plane, plane, vec);
}
}
result = ORIENTATION_FACE;
}
- else if (em->totvertsel == 3)
+ else if (em->bm->totvertsel == 3)
{
- EditVert *v1 = NULL, *v2 = NULL, *v3 = NULL;
+ BMVert *v1 = NULL, *v2 = NULL, *v3 = NULL;
+ BMIter iter;
float cotangent[3];
- for (eve = em->verts.first; eve; eve = eve->next)
- {
- if ( eve->f & SELECT ) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_SELECT)) {
if (v1 == NULL) {
v1 = eve;
}
@@ -633,12 +634,13 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
}
/* if there's an edge available, use that for the tangent */
- if (em->totedgesel >= 1)
+ if (em->bm->totedgesel >= 1)
{
- EditEdge *eed = NULL;
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
+ BMEdge *eed = NULL;
+ BMIter iter;
+
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_TestHFlag(eed, BM_SELECT)) {
sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
break;
}
@@ -647,12 +649,13 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
result = ORIENTATION_FACE;
}
- else if (em->totedgesel == 1)
+ else if (em->bm->totedgesel == 1)
{
- EditEdge *eed;
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
+ BMEdge *eed = NULL;
+ BMIter iter;
+
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_TestHFlag(eed, BM_SELECT)) {
/* use average vert normals as plane and edge vector as normal */
VECCOPY(plane, eed->v1->no);
VECADD(plane, plane, eed->v2->no);
@@ -662,13 +665,13 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
}
result = ORIENTATION_EDGE;
}
- else if (em->totvertsel == 2)
+ else if (em->bm->totvertsel == 2)
{
- EditVert *v1 = NULL, *v2 = NULL;
-
- for (eve = em->verts.first; eve; eve = eve->next)
- {
- if ( eve->f & SELECT ) {
+ BMVert *v1 = NULL, *v2 = NULL;
+ BMIter iter;
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_SELECT)) {
if (v1 == NULL) {
v1 = eve;
}
@@ -684,24 +687,25 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
}
result = ORIENTATION_EDGE;
}
- else if (em->totvertsel == 1)
+ else if (em->bm->totvertsel == 1)
{
- for (eve = em->verts.first; eve; eve = eve->next)
- {
- if ( eve->f & SELECT ) {
+ BMIter iter;
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_SELECT)) {
VECCOPY(normal, eve->no);
break;
}
}
result = ORIENTATION_VERT;
}
- else if (em->totvertsel > 3)
+ else if (em->bm->totvertsel > 3)
{
- normal[0] = normal[1] = normal[2] = 0;
-
- for (eve = em->verts.first; eve; eve = eve->next)
- {
- if ( eve->f & SELECT ) {
+ BMIter iter;
+ normal[0] = normal[1] = normal[2] = 0.0f;
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_SELECT)) {
add_v3_v3(normal, eve->no);
}
}
@@ -887,10 +891,18 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
}
}
- if (ob) {
+ if (!ob) {
+ normal[0] = 0.0f;
+ normal[1] = 0.0f;
+ normal[2] = 1.0f;
+ plane[0] = 1.0f;
+ plane[1] = 0.0f;
+ plane[2] = 0.0f;
+ } else {
VECCOPY(normal, ob->obmat[2]);
VECCOPY(plane, ob->obmat[1]);
}
+
result = ORIENTATION_NORMAL;
}
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 164876078f1..7379eb46a3a 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -65,6 +65,8 @@
#include "BKE_object.h"
#include "BKE_anim.h" /* for duplis */
#include "BKE_context.h"
+#include "BKE_tessmesh.h"
+#include "BKE_mesh.h"
#include "ED_armature.h"
#include "ED_image.h"
@@ -805,8 +807,8 @@ void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
else
{
found = snapObjectsTransform(t, mval, &dist, loc, no, t->tsnap.modeSelect);
- }
-
+ }
+
if (found == 1)
{
float tangent[3];
@@ -1269,11 +1271,14 @@ static int snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *arm
return retval;
}
-static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, EditMesh *em, float obmat[][4], float ray_start[3], float ray_normal[3], float mval[2], float *loc, float *no, int *dist, float *depth)
+static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob,
+ DerivedMesh *dm, BMEditMesh *em, float obmat[][4],
+ float ray_start[3], float ray_normal[3], float mval[2],
+ float *loc, float *no, int *dist, float *depth)
{
int retval = 0;
int totvert = dm->getNumVerts(dm);
- int totface = dm->getNumFaces(dm);
+ int totface = dm->getNumTessFaces(dm);
if (totvert > 0) {
float imat[4][4];
@@ -1341,19 +1346,19 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh
#else
MVert *verts = dm->getVertArray(dm);
- MFace *faces = dm->getFaceArray(dm);
+ MFace *faces = dm->getTessFaceArray(dm);
int *index_array = NULL;
int index = 0;
int i;
if (em != NULL)
{
- index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX);
- EM_init_index_arrays(em, 0, 0, 1);
+ index_array = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ EDBM_init_index_arrays(em, 0, 0, 1);
}
for( i = 0; i < totface; i++) {
- EditFace *efa = NULL;
+ BMFace *efa = NULL;
MFace *f = faces + i;
test = 1; /* reset for every face */
@@ -1375,11 +1380,22 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh
}
else
{
- efa = EM_get_face_for_index(index);
+ efa = EDBM_get_face_for_index(em, index);
- if (efa && (efa->h || (efa->v1->f & SELECT) || (efa->v2->f & SELECT) || (efa->v3->f & SELECT) || (efa->v4 && efa->v4->f & SELECT)))
+ if (efa && BM_TestHFlag(efa, BM_HIDDEN))
{
test = 0;
+ } else if (efa) {
+ BMIter iter;
+ BMLoop *l;
+
+ l = BMIter_New(&iter, em->bm, BM_LOOPS_OF_FACE, efa);
+ for ( ; l; l=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(l->v, BM_SELECT)) {
+ test = 0;
+ break;
+ }
+ }
}
}
}
@@ -1407,7 +1423,7 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh
if (em != NULL)
{
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
}
#endif
break;
@@ -1422,11 +1438,11 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh
if (em != NULL)
{
index_array = dm->getVertDataArray(dm, CD_ORIGINDEX);
- EM_init_index_arrays(em, 1, 0, 0);
+ EDBM_init_index_arrays(em, 1, 0, 0);
}
for( i = 0; i < totvert; i++) {
- EditVert *eve = NULL;
+ BMVert *eve = NULL;
MVert *v = verts + i;
test = 1; /* reset for every vert */
@@ -1448,9 +1464,9 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh
}
else
{
- eve = EM_get_vert_for_index(index);
+ eve = EDBM_get_vert_for_index(em, index);
- if (eve && (eve->h || (eve->f & SELECT)))
+ if (eve && (BM_TestHFlag(eve, BM_HIDDEN) || BM_TestHFlag(eve, BM_SELECT)))
{
test = 0;
}
@@ -1466,7 +1482,7 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh
if (em != NULL)
{
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
}
break;
}
@@ -1482,11 +1498,11 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh
if (em != NULL)
{
index_array = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
- EM_init_index_arrays(em, 0, 1, 0);
+ EDBM_init_index_arrays(em, 0, 1, 0);
}
for( i = 0; i < totedge; i++) {
- EditEdge *eed = NULL;
+ BMEdge *eed = NULL;
MEdge *e = edges + i;
test = 1; /* reset for every vert */
@@ -1508,9 +1524,11 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh
}
else
{
- eed = EM_get_edge_for_index(index);
+ eed = EDBM_get_edge_for_index(em, index);
- if (eed && (eed->h || (eed->v1->f & SELECT) || (eed->v2->f & SELECT)))
+ if (eed && (BM_TestHFlag(eed, BM_HIDDEN) ||
+ BM_TestHFlag(eed->v1, BM_SELECT) ||
+ BM_TestHFlag(eed->v2, BM_SELECT)))
{
test = 0;
}
@@ -1526,7 +1544,7 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh
if (em != NULL)
{
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
}
break;
}
@@ -1543,14 +1561,14 @@ static int snapObject(Scene *scene, ARegion *ar, Object *ob, int editobject, flo
int retval = 0;
if (ob->type == OB_MESH) {
- EditMesh *em;
+ BMEditMesh *em;
DerivedMesh *dm;
if (editobject)
{
- em = ((Mesh *)ob->data)->edit_mesh;
- /* dm = editmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH); */
- dm = editmesh_get_derived_base(ob, em); /* limitation, em & dm MUST have the same number of faces */
+ em = ((Mesh *)ob->data)->edit_btmesh;
+ /* dm = editbmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH); */
+ dm = editbmesh_get_derived_base(ob, em); /* limitation, em & dm MUST have the same number of faces */
}
else
{
@@ -1697,7 +1715,7 @@ static int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float
{
int retval = 0;
int totvert = dm->getNumVerts(dm);
- int totface = dm->getNumFaces(dm);
+ int totface = dm->getNumTessFaces(dm);
if (totvert > 0) {
float imat[4][4];
@@ -1727,7 +1745,7 @@ static int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float
if (test == 1) {
MVert *verts = dm->getVertArray(dm);
- MFace *faces = dm->getFaceArray(dm);
+ MFace *faces = dm->getTessFaceArray(dm);
int i;
for( i = 0; i < totface; i++) {
@@ -1823,6 +1841,7 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L
Object *dob = dupli_ob->ob;
if (dob->type == OB_MESH) {
+#if 0 //BMESH_TODO
EditMesh *em;
DerivedMesh *dm = NULL;
int val;
@@ -1844,6 +1863,7 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L
retval = retval || val;
dm->release(dm);
+#endif
}
}
@@ -1851,7 +1871,7 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L
}
if (ob->type == OB_MESH) {
- EditMesh *em;
+ BMEditMesh *em;
DerivedMesh *dm = NULL;
int val;
@@ -1863,8 +1883,8 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L
}
else
{
- em = ((Mesh *)ob->data)->edit_mesh;
- dm = editmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
+ em = ((Mesh *)ob->data)->edit_btmesh;
+ dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels);
}
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index 0be6ccaee2c..511b1ab49e0 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenkernel
../../blenloader
../../blenlib
+ ../../bmesh
../../makesdna
../../makesrna
../../windowmanager
diff --git a/source/blender/editors/util/SConscript b/source/blender/editors/util/SConscript
index a694b211ca4..2d5ee84333b 100644
--- a/source/blender/editors/util/SConscript
+++ b/source/blender/editors/util/SConscript
@@ -5,7 +5,7 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
-incs += ' ../../makesrna'
+incs += ' ../../makesrna ../../bmesh'
incs += ' ../../blenloader'
env.BlenderLib ( 'bf_editors_util', sources, Split(incs), [], libtype=['core'], priority=[130] )
diff --git a/source/blender/editors/util/crazyspace.c b/source/blender/editors/util/crazyspace.c
index 20152f6681b..6b7292fe6c7 100644
--- a/source/blender/editors/util/crazyspace.c
+++ b/source/blender/editors/util/crazyspace.c
@@ -38,6 +38,7 @@
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_mesh.h"
+#include "BKE_tessmesh.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
@@ -96,13 +97,13 @@ float *crazyspace_get_mapped_editverts(Scene *scene, Object *obedit)
/* disable subsurf temporal, get mapped cos, and enable it */
if(modifiers_disable_subsurf_temporary(obedit)) {
/* need to make new derivemesh */
- makeDerivedMesh(scene, obedit, me->edit_mesh, CD_MASK_BAREMESH);
+ makeDerivedMesh(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH);
}
/* now get the cage */
- dm= editmesh_get_derived_cage(scene, obedit, me->edit_mesh, CD_MASK_BAREMESH);
+ dm= editbmesh_get_derived_cage(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH);
- vertexcos= MEM_mallocN(3*sizeof(float)*me->edit_mesh->totvert, "vertexcos map");
+ vertexcos= MEM_mallocN(3*sizeof(float)*me->edit_btmesh->bm->totvert, "vertexcos map");
dm->foreachMappedVert(dm, make_vertexcos__mapFunc, vertexcos);
dm->release(dm);
@@ -113,10 +114,12 @@ float *crazyspace_get_mapped_editverts(Scene *scene, Object *obedit)
return vertexcos;
}
-void crazyspace_set_quats_editmesh(EditMesh *em, float *origcos, float *mappedcos, float *quats)
+void crazyspace_set_quats_editmesh(BMEditMesh *em, float *origcos, float *mappedcos, float *quats)
{
- EditVert *eve, *prev;
- EditFace *efa;
+#if 0
+ BMEditVert *eve, *prev;
+ BMEditFace *efa;
+ BMIter iter;
float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4;
intptr_t index= 0;
@@ -181,7 +184,7 @@ void crazyspace_set_quats_editmesh(EditMesh *em, float *origcos, float *mappedco
/* restore abused prev pointer */
for(prev= NULL, eve= em->verts.first; eve; prev= eve, eve= eve->next)
eve->prev= prev;
-
+#endif
}
void crazyspace_set_quats_mesh(Mesh *me, float *origcos, float *mappedcos, float *quats)
@@ -244,7 +247,8 @@ void crazyspace_set_quats_mesh(Mesh *me, float *origcos, float *mappedcos, float
}
}
-int editmesh_get_first_deform_matrices(Scene *scene, Object *ob, EditMesh *em, float (**deformmats)[3][3], float (**deformcos)[3])
+int editbmesh_get_first_deform_matrices(Scene *scene, Object *ob, BMEditMesh *em,
+ float (**deformmats)[3][3], float (**deformcos)[3])
{
ModifierData *md;
DerivedMesh *dm;
@@ -263,13 +267,13 @@ int editmesh_get_first_deform_matrices(Scene *scene, Object *ob, EditMesh *em, f
for(i = 0; md && i <= cageIndex; i++, md = md->next) {
ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if(!editmesh_modifier_is_enabled(scene, md, dm))
+ if(!editbmesh_modifier_is_enabled(scene, md, dm))
continue;
if(mti->type==eModifierTypeType_OnlyDeform && mti->deformMatricesEM) {
if(!defmats) {
- dm= editmesh_get_derived(em, NULL);
- deformedVerts= editmesh_get_vertex_cos(em, &numVerts);
+ dm= getEditDerivedBMesh(em, ob, NULL);
+ deformedVerts= editbmesh_get_vertex_cos(em, &numVerts);
defmats= MEM_callocN(sizeof(*defmats)*numVerts, "defmats");
for(a=0; a<numVerts; a++)
@@ -284,7 +288,7 @@ int editmesh_get_first_deform_matrices(Scene *scene, Object *ob, EditMesh *em, f
}
for(; md && i <= cageIndex; md = md->next, i++)
- if(editmesh_modifier_is_enabled(scene, md, dm) && modifier_isCorrectableDeformed(md))
+ if(editbmesh_modifier_is_enabled(scene, md, dm) && modifier_isCorrectableDeformed(md))
numleft++;
if(dm)
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 2f3392d7f8c..314fcdc601b 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -101,16 +101,16 @@ void ED_editors_exit(bContext *C)
Object *ob= sce->obedit;
/* global in meshtools... */
- mesh_octree_table(NULL, NULL, NULL, 'e');
- mesh_mirrtopo_table(NULL, 'e');
+ //BMESH_TODO mesh_octree_table(NULL, NULL, NULL, 'e');
+ //BMESH_TODO mesh_mirrtopo_table(NULL, 'e');
if(ob) {
if(ob->type==OB_MESH) {
Mesh *me= ob->data;
- if(me->edit_mesh) {
- free_editMesh(me->edit_mesh);
- MEM_freeN(me->edit_mesh);
- me->edit_mesh= NULL;
+ if(me->edit_btmesh) {
+ EDBM_FreeEditBMesh(me->edit_btmesh);
+ MEM_freeN(me->edit_btmesh);
+ me->edit_btmesh= NULL;
}
}
else if(ob->type==OB_ARMATURE) {
@@ -130,8 +130,8 @@ void ED_editors_exit(bContext *C)
/* if weight-painting is on, free mesh octree data */
if(ob->mode & OB_MODE_WEIGHT_PAINT) {
- mesh_octree_table(NULL, NULL, NULL, 'e');
- mesh_mirrtopo_table(NULL, 'e');
+ //BMESH_TODO mesh_octree_table(NULL, NULL, NULL, 'e');
+ //BMESH_TODO mesh_mirrtopo_table(NULL, 'e');
}
}
}
diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c
index 08f801b8039..1e6f7cd8804 100644
--- a/source/blender/editors/util/editmode_undo.c
+++ b/source/blender/editors/util/editmode_undo.c
@@ -93,8 +93,8 @@ typedef struct UndoElem {
char name[MAXUNDONAME];
void * (*getdata)(bContext *C);
void (*freedata)(void *);
- void (*to_editmode)(void *, void *);
- void * (*from_editmode)(void *);
+ void (*to_editmode)(void *, void *, void *);
+ void * (*from_editmode)(void *, void *);
int (*validate_undo)(void *, void *);
} UndoElem;
@@ -104,10 +104,10 @@ static UndoElem *curundo= NULL;
/* ********************* xtern api calls ************* */
-static void undo_restore(UndoElem *undo, void *editdata)
+static void undo_restore(UndoElem *undo, void *editdata, void *obdata)
{
if(undo) {
- undo->to_editmode(undo->undodata, editdata);
+ undo->to_editmode(undo->undodata, editdata, obdata);
}
}
@@ -115,8 +115,8 @@ static void undo_restore(UndoElem *undo, void *editdata)
void undo_editmode_push(bContext *C, const char *name,
void * (*getdata)(bContext *C),
void (*freedata)(void *),
- void (*to_editmode)(void *, void *),
- void *(*from_editmode)(void *),
+ void (*to_editmode)(void *, void *, void *),
+ void *(*from_editmode)(void *, void *),
int (*validate_undo)(void *, void *))
{
UndoElem *uel;
@@ -165,7 +165,7 @@ void undo_editmode_push(bContext *C, const char *name,
/* copy */
memused= MEM_get_memory_in_use();
editdata= getdata(C);
- curundo->undodata= curundo->from_editmode(editdata);
+ curundo->undodata= curundo->from_editmode(editdata, obedit->data);
curundo->undosize= MEM_get_memory_in_use() - memused;
curundo->ob= obedit;
curundo->id= obedit->id;
@@ -245,7 +245,7 @@ void undo_editmode_step(bContext *C, int step)
undo_clean_stack(C);
if(step==0) {
- undo_restore(curundo, curundo->getdata(C));
+ undo_restore(curundo, curundo->getdata(C), obedit->data);
}
else if(step==1) {
@@ -253,7 +253,7 @@ void undo_editmode_step(bContext *C, int step)
else {
if(G.f & G_DEBUG) printf("undo %s\n", curundo->name);
curundo= curundo->prev;
- undo_restore(curundo, curundo->getdata(C));
+ undo_restore(curundo, curundo->getdata(C), obedit->data);
}
}
else {
@@ -261,7 +261,7 @@ void undo_editmode_step(bContext *C, int step)
if(curundo==NULL || curundo->next==NULL) error("No more steps to redo");
else {
- undo_restore(curundo->next, curundo->getdata(C));
+ undo_restore(curundo->next, curundo->getdata(C), obedit->data);
curundo= curundo->next;
if(G.f & G_DEBUG) printf("redo %s\n", curundo->name);
}
@@ -269,7 +269,7 @@ void undo_editmode_step(bContext *C, int step)
/* special case for editmesh, mode must be copied back to the scene */
if(obedit->type == OB_MESH) {
- EM_selectmode_to_scene(CTX_data_scene(C), obedit);
+ EDBM_selectmode_to_scene(CTX_data_scene(C), obedit);
}
DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt
index 852b120a826..b9e718b3e7d 100644
--- a/source/blender/editors/uvedit/CMakeLists.txt
+++ b/source/blender/editors/uvedit/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenkernel
../../blenloader
../../blenlib
+ ../../bmesh
../../makesdna
../../makesrna
../../windowmanager
diff --git a/source/blender/editors/uvedit/SConscript b/source/blender/editors/uvedit/SConscript
index 2523de005d0..3e8c3851962 100644
--- a/source/blender/editors/uvedit/SConscript
+++ b/source/blender/editors/uvedit/SConscript
@@ -5,6 +5,10 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
+<<<<<<< .working
+incs += ' ../../makesrna #/intern/opennl/extern ../../gpu ../../bmesh'
+=======
incs += ' ../../makesrna #/intern/opennl/extern ../../gpu ../../blenloader'
+>>>>>>> .merge-right.r35190
env.BlenderLib ( 'bf_editors_uvedit', sources, Split(incs), [], libtype=['core'], priority=[45] )
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index ef41ff23c24..04a6cf5c5b0 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -28,7 +28,11 @@
#include <float.h>
#include <math.h>
#include <stdlib.h>
+#include <string.h>
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -41,7 +45,9 @@
#include "BKE_DerivedMesh.h"
#include "BKE_mesh.h"
+#include "BKE_tessmesh.h"
+#include "BLI_array.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -118,34 +124,33 @@ static int draw_uvs_face_check(Scene *scene)
static void draw_uvs_shadow(Object *obedit)
{
- EditMesh *em;
- EditFace *efa;
- MTFace *tf;
+ BMEditMesh *em;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+ em= ((Mesh*)obedit->data)->edit_btmesh;
/* draws the grey mesh when painting */
glColor3ub(112, 112, 112);
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
glBegin(GL_LINE_LOOP);
- glVertex2fv(tf->uv[0]);
- glVertex2fv(tf->uv[1]);
- glVertex2fv(tf->uv[2]);
- if(efa->v4) glVertex2fv(tf->uv[3]);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv= CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ glVertex2fv(luv->uv);
+ }
glEnd();
}
-
- BKE_mesh_end_editmesh(obedit->data, em);
}
static int draw_uvs_dm_shadow(DerivedMesh *dm)
{
/* draw shadow mesh - this is the mesh with the modifier applied */
- if(dm && dm->drawUVEdges && CustomData_has_layer(&dm->faceData, CD_MTFACE)) {
+ if(dm && dm->drawUVEdges && CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
glColor3ub(112, 112, 112);
dm->drawUVEdges(dm);
return 1;
@@ -154,13 +159,19 @@ static int draw_uvs_dm_shadow(DerivedMesh *dm)
return 0;
}
-static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFace *activetf)
+static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTexPoly *activetf)
{
- EditFace *efa;
- MTFace *tf;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
Image *ima= sima->image;
- float aspx, aspy, col[4], tf_uv[4][2];
-
+ BLI_array_declare(tf_uv);
+ BLI_array_declare(tf_uvorig);
+ float aspx, aspy, col[4], (*tf_uv)[2] = NULL, (*tf_uvorig)[2] = NULL;
+ int i;
+
ED_space_image_uv_aspect(sima, &aspx, &aspy);
switch(sima->dt_uvstretch) {
@@ -168,21 +179,37 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac
{
float totarea=0.0f, totuvarea=0.0f, areadiff, uvarea, area;
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- uv_copy_aspect(tf->uv, tf_uv, aspx, aspy);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+
+ BLI_array_empty(tf_uv);
+ BLI_array_empty(tf_uvorig);
+
+ i = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv= CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ BLI_array_growone(tf_uv);
+ BLI_array_growone(tf_uvorig);
+
+ tf_uvorig[i][0] = luv->uv[0];
+ tf_uvorig[i][1] = luv->uv[1];
- totarea += EM_face_area(efa);
+ i++;
+ }
+
+ poly_copy_aspect(tf_uvorig, tf_uv, aspx, aspy, efa->len);
+
+ totarea += BM_face_area(efa);
//totuvarea += tf_area(tf, efa->v4!=0);
- totuvarea += uv_area(tf_uv, efa->v4!=0);
+ totuvarea += poly_uv_area(tf_uv, efa->len);
if(uvedit_face_visible(scene, ima, efa, tf)) {
- efa->tmp.p = tf;
+ BMINDEX_SET(efa, 1);
}
else {
if(tf == activetf)
activetf= NULL;
- efa->tmp.p = NULL;
+ BMINDEX_SET(efa, 0);
}
}
@@ -190,24 +217,41 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac
col[0] = 1.0;
col[1] = col[2] = 0.0;
glColor3fv(col);
- for(efa= em->faces.first; efa; efa= efa->next) {
- if((tf=(MTFace *)efa->tmp.p)) {
- glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
- glVertex2fv(tf->uv[0]);
- glVertex2fv(tf->uv[1]);
- glVertex2fv(tf->uv[2]);
- if(efa->v4) glVertex2fv(tf->uv[3]);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if(BMINDEX_GET(efa)) {
+ glBegin(GL_POLYGON);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
+ }
glEnd();
}
}
}
else {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if((tf=(MTFace *)efa->tmp.p)) {
- area = EM_face_area(efa) / totarea;
- uv_copy_aspect(tf->uv, tf_uv, aspx, aspy);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if(BMINDEX_GET(efa)) {
+ area = BM_face_area(efa) / totarea;
+
+ BLI_array_empty(tf_uv);
+ BLI_array_empty(tf_uvorig);
+
+ i = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv= CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ BLI_array_growone(tf_uv);
+ BLI_array_growone(tf_uvorig);
+
+ tf_uvorig[i][0] = luv->uv[0];
+ tf_uvorig[i][1] = luv->uv[1];
+
+ i++;
+ }
+
+ poly_copy_aspect(tf_uvorig, tf_uv, aspx, aspy, efa->len);
+
//uvarea = tf_area(tf, efa->v4!=0) / totuvarea;
- uvarea = uv_area(tf_uv, efa->v4!=0) / totuvarea;
+ uvarea = poly_uv_area(tf_uv, efa->len) / totuvarea;
if(area < FLT_EPSILON || uvarea < FLT_EPSILON)
areadiff = 1.0;
@@ -219,11 +263,11 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac
weight_to_rgb(areadiff, col, col+1, col+2);
glColor3fv(col);
- glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
- glVertex2fv(tf->uv[0]);
- glVertex2fv(tf->uv[1]);
- glVertex2fv(tf->uv[2]);
- if(efa->v4) glVertex2fv(tf->uv[3]);
+ glBegin(GL_POLYGON);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
+ }
glEnd();
}
}
@@ -232,6 +276,7 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac
}
case SI_UVDT_STRETCH_ANGLE:
{
+#if 0 //BMESH_TODO
float uvang1,uvang2,uvang3,uvang4;
float ang1,ang2,ang3,ang4;
float av1[3], av2[3], av3[3], av4[3]; /* use for 2d and 3d angle vectors */
@@ -242,7 +287,7 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac
glShadeModel(GL_SMOOTH);
for(efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ tf= CustomData_em_get(&em->fdata, efa->head.data, CD_MTFACE);
if(uvedit_face_visible(scene, ima, efa, tf)) {
efa->tmp.p = tf;
@@ -373,11 +418,13 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac
glShadeModel(GL_FLAT);
break;
+
+#endif
}
}
}
-static void draw_uvs_other(Scene *scene, Object *obedit, MTFace *activetf)
+static void draw_uvs_other(Scene *scene, Object *obedit, MTexPoly *activetf)
{
Base *base;
Image *curimage;
@@ -397,17 +444,19 @@ static void draw_uvs_other(Scene *scene, Object *obedit, MTFace *activetf)
Mesh *me= ob->data;
if(me->mtface) {
- MFace *mface= me->mface;
- MTFace *tface= me->mtface;
- int a;
+ MPoly *mface= me->mpoly;
+ MTexPoly *tface= me->mtpoly;
+ MLoopUV *mloopuv;
+ int a, b;
- for(a=me->totface; a>0; a--, tface++, mface++) {
+ for(a=me->totpoly; a>0; a--, tface++, mface++) {
if(tface->tpage == curimage) {
glBegin(GL_LINE_LOOP);
- glVertex2fv(tface->uv[0]);
- glVertex2fv(tface->uv[1]);
- glVertex2fv(tface->uv[2]);
- if(mface->v4) glVertex2fv(tface->uv[3]);
+
+ mloopuv = me->mloopuv + mface->loopstart;
+ for (b=0; b<mface->totloop; b++, mloopuv++) {
+ glVertex2fv(mloopuv->uv);
+ }
glEnd();
}
}
@@ -421,18 +470,22 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
{
ToolSettings *ts;
Mesh *me= obedit->data;
- EditMesh *em;
- EditFace *efa, *efa_act;
- MTFace *tf, *activetf = NULL;
+ BMEditMesh *em;
+ BMFace *efa, *efa_act, *activef;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf, *activetf = NULL;
+ MLoopUV *luv;
DerivedMesh *finaldm, *cagedm;
unsigned char col1[4], col2[4];
float pointsize;
int drawfaces, interpedges;
+ int i;
Image *ima= sima->image;
- em= BKE_mesh_get_editmesh(me);
- activetf= EM_get_active_mtface(em, &efa_act, NULL, 0); /* will be set to NULL if hidden */
-
+ em= me->edit_btmesh;
+ activetf= EDBM_get_active_mtexpoly(em, &efa_act, 0); /* will be set to NULL if hidden */
+ activef = EDBM_get_actFace(em, 0);
ts= scene->toolsettings;
drawfaces= draw_uvs_face_check(scene);
@@ -451,7 +504,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
/* first try existing derivedmesh */
if(!draw_uvs_dm_shadow(em->derivedFinal)) {
/* create one if it does not exist */
- cagedm = editmesh_get_derived_cage_and_final(scene, obedit, em, &finaldm, CD_MASK_BAREMESH|CD_MASK_MTFACE);
+ cagedm = editbmesh_get_derived_cage_and_final(scene, obedit, me->edit_btmesh, &finaldm, CD_MASK_BAREMESH|CD_MASK_MTFACE);
/* when sync selection is enabled, all faces are drawn (except for hidden)
* so if cage is the same as the final, theres no point in drawing this */
@@ -476,45 +529,46 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
if(uvedit_face_visible(scene, ima, efa, tf)) {
- efa->tmp.p = tf;
- if(tf==activetf) continue; /* important the temp pointer is set above */
+ BMINDEX_SET(efa, 1);
+ if(tf==activetf) continue; /* important the temp boolean is set above */
- if(uvedit_face_selected(scene, efa, tf))
+ if(uvedit_face_selected(scene, em, efa))
glColor4ubv((GLubyte *)col2);
else
glColor4ubv((GLubyte *)col1);
-
- glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
- glVertex2fv(tf->uv[0]);
- glVertex2fv(tf->uv[1]);
- glVertex2fv(tf->uv[2]);
- if(efa->v4) glVertex2fv(tf->uv[3]);
+
+ glBegin(GL_POLYGON);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
+ }
glEnd();
}
else {
if(tf == activetf)
activetf= NULL;
- efa->tmp.p = NULL;
+ BMINDEX_SET(efa, 0);
}
}
glDisable(GL_BLEND);
}
else {
/* would be nice to do this within a draw loop but most below are optional, so it would involve too many checks */
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
if(uvedit_face_visible(scene, ima, efa, tf)) {
- efa->tmp.p = tf;
+ BMINDEX_SET(efa, 1);
}
else {
if(tf == activetf)
activetf= NULL;
- efa->tmp.p = NULL;
+ BMINDEX_SET(efa, 0);
}
}
@@ -522,7 +576,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
/* 3. draw active face stippled */
- if(activetf) {
+ if(activef) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
UI_ThemeColor4(TH_EDITMESH_ACTIVE);
@@ -530,11 +584,11 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
glEnable(GL_POLYGON_STIPPLE);
glPolygonStipple(stipple_quarttone);
- glBegin(efa_act->v4? GL_QUADS: GL_TRIANGLES);
- glVertex2fv(activetf->uv[0]);
- glVertex2fv(activetf->uv[1]);
- glVertex2fv(activetf->uv[2]);
- if(efa_act->v4) glVertex2fv(activetf->uv[3]);
+ glBegin(GL_POLYGON);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, activef) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
+ }
glEnd();
glDisable(GL_POLYGON_STIPPLE);
@@ -551,39 +605,38 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
switch(sima->dt_uv) {
case SI_UVDT_DASH:
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= (MTFace *)efa->tmp.p; /* visible faces cached */
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMINDEX_GET(efa))
+ continue;
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
if(tf) {
cpack(0x111111);
glBegin(GL_LINE_LOOP);
- glVertex2fv(tf->uv[0]);
- glVertex2fv(tf->uv[1]);
- glVertex2fv(tf->uv[2]);
- if(efa->v4) glVertex2fv(tf->uv[3]);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
+ }
glEnd();
-
+
setlinestyle(2);
cpack(0x909090);
- glBegin(GL_LINE_STRIP);
- glVertex2fv(tf->uv[0]);
- glVertex2fv(tf->uv[1]);
- glEnd();
-
- glBegin(GL_LINE_STRIP);
- glVertex2fv(tf->uv[0]);
- if(efa->v4) glVertex2fv(tf->uv[3]);
- else glVertex2fv(tf->uv[2]);
- glEnd();
-
- glBegin(GL_LINE_STRIP);
- glVertex2fv(tf->uv[1]);
- glVertex2fv(tf->uv[2]);
- if(efa->v4) glVertex2fv(tf->uv[3]);
+ glBegin(GL_LINE_LOOP);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
+ }
glEnd();
+ /*glBegin(GL_LINE_STRIP);
+ luv = CustomData_bmesh_get(&em->bm->ldata, efa->lbase->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
+ luv = CustomData_bmesh_get(&em->bm->ldata, efa->lbase->next->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
+ glEnd();*/
+
setlinestyle(0);
}
}
@@ -593,34 +646,32 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
if(sima->dt_uv==SI_UVDT_WHITE) glColor3f(1.0f, 1.0f, 1.0f);
else glColor3f(0.0f, 0.0f, 0.0f);
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= (MTFace *)efa->tmp.p; /* visible faces cached */
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMINDEX_GET(efa))
+ continue;
- if(tf) {
- glBegin(GL_LINE_LOOP);
- glVertex2fv(tf->uv[0]);
- glVertex2fv(tf->uv[1]);
- glVertex2fv(tf->uv[2]);
- if(efa->v4) glVertex2fv(tf->uv[3]);
- glEnd();
+ glBegin(GL_LINE_LOOP);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
}
+ glEnd();
}
break;
case SI_UVDT_OUTLINE:
glLineWidth(3);
cpack(0x0);
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= (MTFace *)efa->tmp.p; /* visible faces cached */
-
- if(tf) {
- glBegin(GL_LINE_LOOP);
- glVertex2fv(tf->uv[0]);
- glVertex2fv(tf->uv[1]);
- glVertex2fv(tf->uv[2]);
- if(efa->v4) glVertex2fv(tf->uv[3]);
- glEnd();
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMINDEX_GET(efa))
+ continue;
+
+ glBegin(GL_LINE_LOOP);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
}
+ glEnd();
}
glLineWidth(1);
@@ -634,83 +685,60 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
if(interpedges) {
glShadeModel(GL_SMOOTH);
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= (MTFace *)efa->tmp.p; /* visible faces cached */
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMINDEX_GET(efa))
+ continue;
- if(tf) {
- glBegin(GL_LINE_LOOP);
- sel = (uvedit_uv_selected(scene, efa, tf, 0)? 1 : 0);
- if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
- glVertex2fv(tf->uv[0]);
-
- sel = uvedit_uv_selected(scene, efa, tf, 1)? 1 : 0;
- if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
- glVertex2fv(tf->uv[1]);
-
- sel = uvedit_uv_selected(scene, efa, tf, 2)? 1 : 0;
+ glBegin(GL_LINE_LOOP);
+ i = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ sel = (uvedit_uv_selected(em, scene, l)? 1 : 0);
if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
- glVertex2fv(tf->uv[2]);
-
- if(efa->v4) {
- sel = uvedit_uv_selected(scene, efa, tf, 3)? 1 : 0;
- if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
- glVertex2fv(tf->uv[3]);
- }
-
- glEnd();
+
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
+ i += 1;
}
+ glEnd();
}
glShadeModel(GL_FLAT);
}
else {
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= (MTFace *)efa->tmp.p; /* visible faces cached */
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMINDEX_GET(efa))
+ continue;
- if(tf) {
- glBegin(GL_LINES);
- sel = (uvedit_edge_selected(scene, efa, tf, 0)? 1 : 0);
- if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
- glVertex2fv(tf->uv[0]);
- glVertex2fv(tf->uv[1]);
-
- sel = uvedit_edge_selected(scene, efa, tf, 1)? 1 : 0;
- if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
- glVertex2fv(tf->uv[1]);
- glVertex2fv(tf->uv[2]);
-
- sel = uvedit_edge_selected(scene, efa, tf, 2)? 1 : 0;
+ glBegin(GL_LINE_LOOP);
+ i = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ sel = (uvedit_edge_selected(em, scene, l)? 1 : 0);
if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
- glVertex2fv(tf->uv[2]);
-
- if(efa->v4) {
- glVertex2fv(tf->uv[3]);
-
- sel = uvedit_edge_selected(scene, efa, tf, 3)? 1 : 0;
- if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
- glVertex2fv(tf->uv[3]);
- }
-
- glVertex2fv(tf->uv[0]);
-
- glEnd();
+
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
+ i += 1;
}
+ glEnd();
}
}
}
else {
/* no nice edges */
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= (MTFace *)efa->tmp.p; /* visible faces cached */
-
- if(tf) {
- glBegin(GL_LINE_LOOP);
- glVertex2fv(tf->uv[0]);
- glVertex2fv(tf->uv[1]);
- glVertex2fv(tf->uv[2]);
- if(efa->v4) glVertex2fv(tf->uv[3]);
- glEnd();
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMINDEX_GET(efa))
+ continue;
+
+ glBegin(GL_LINE_LOOP);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
}
+ glEnd();
}
}
@@ -734,11 +762,12 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
UI_ThemeColor(TH_WIRE);
bglBegin(GL_POINTS);
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= (MTFace *)efa->tmp.p; /* visible faces cached */
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMINDEX_GET(efa))
+ continue;
- if(tf && !uvedit_face_selected(scene, efa, tf)) {
- uv_center(tf->uv, cent, efa->v4 != NULL);
+ if(!uvedit_face_selected(scene, em, efa)) {
+ poly_uv_center(em, efa, cent);
bglVertex2fv(cent);
}
}
@@ -748,11 +777,12 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
UI_ThemeColor(TH_FACE_DOT);
bglBegin(GL_POINTS);
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= (MTFace *)efa->tmp.p; /* visible faces cached */
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMINDEX_GET(efa))
+ continue;
- if(tf && uvedit_face_selected(scene, efa, tf)) {
- uv_center(tf->uv, cent, efa->v4 != NULL);
+ if(uvedit_face_selected(scene, em, efa)) {
+ poly_uv_center(em, efa, cent);
bglVertex2fv(cent);
}
}
@@ -768,18 +798,14 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
glPointSize(pointsize);
bglBegin(GL_POINTS);
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= (MTFace *)efa->tmp.p; /* visible faces cached */
-
- if(tf) {
- if(!uvedit_uv_selected(scene, efa, tf, 0))
- bglVertex2fv(tf->uv[0]);
- if(!uvedit_uv_selected(scene, efa, tf, 1))
- bglVertex2fv(tf->uv[1]);
- if(!uvedit_uv_selected(scene, efa, tf, 2))
- bglVertex2fv(tf->uv[2]);
- if(efa->v4 && !uvedit_uv_selected(scene, efa, tf, 3))
- bglVertex2fv(tf->uv[3]);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMINDEX_GET(efa))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ if(!uvedit_uv_selected(em, scene, l))
+ bglVertex2fv(luv->uv);
}
}
bglEnd();
@@ -790,18 +816,15 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
cpack(0xFF);
bglBegin(GL_POINTS);
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= (MTFace *)efa->tmp.p; /* visible faces cached */
-
- if(tf) {
- if(tf->unwrap & TF_PIN1)
- bglVertex2fv(tf->uv[0]);
- if(tf->unwrap & TF_PIN2)
- bglVertex2fv(tf->uv[1]);
- if(tf->unwrap & TF_PIN3)
- bglVertex2fv(tf->uv[2]);
- if(efa->v4 && (tf->unwrap & TF_PIN4))
- bglVertex2fv(tf->uv[3]);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMINDEX_GET(efa))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if(luv->flag & MLOOPUV_PINNED)
+ bglVertex2fv(luv->uv);
}
}
bglEnd();
@@ -811,25 +834,21 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
glPointSize(pointsize);
bglBegin(GL_POINTS);
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= (MTFace *)efa->tmp.p; /* visible faces cached */
-
- if(tf) {
- if(uvedit_uv_selected(scene, efa, tf, 0))
- bglVertex2fv(tf->uv[0]);
- if(uvedit_uv_selected(scene, efa, tf, 1))
- bglVertex2fv(tf->uv[1]);
- if(uvedit_uv_selected(scene, efa, tf, 2))
- bglVertex2fv(tf->uv[2]);
- if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
- bglVertex2fv(tf->uv[3]);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMINDEX_GET(efa))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if(uvedit_uv_selected(em, scene, l))
+ bglVertex2fv(luv->uv);
}
}
bglEnd();
}
glPointSize(1.0);
- BKE_mesh_end_editmesh(obedit->data, em);
}
void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedit)
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 1312c6d9b55..276dc4cef12 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -30,23 +30,33 @@
#define ED_UVEDIT_INTERN_H
struct SpaceImage;
-struct EditFace;
-struct MTFace;
+struct MTexPoly;
struct Scene;
struct Image;
struct Object;
struct wmOperatorType;
+struct BMEditMesh;
+struct BMFace;
+struct BMLoop;
+struct BMEdge;
+struct BMVert;
/* id can be from 0 to 3 */
#define TF_PIN_MASK(id) (TF_PIN1 << id)
#define TF_SEL_MASK(id) (TF_SEL1 << id)
+/* visibility and selection */
+int uvedit_face_visible_nolocal(struct Scene *scene, struct BMFace *efa);
/* geometric utilities */
void uv_center(float uv[][2], float cent[2], int quad);
float uv_area(float uv[][2], int quad);
void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy);
+float poly_uv_area(float uv[][2], int len);
+void poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len);
+void poly_uv_center(struct BMEditMesh *em, struct BMFace *f, float cent[2]);
+
/* operators */
void UV_OT_average_islands_scale(struct wmOperatorType *ot);
void UV_OT_cube_project(struct wmOperatorType *ot);
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index e916170a5fa..a5d11d6796a 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -30,16 +30,20 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
+#include <string.h>
#include "MEM_guardedalloc.h"
#include "DNA_object_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_image_types.h"
+#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_editVert.h"
+#include "BLI_array.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
@@ -49,6 +53,7 @@
#include "BKE_library.h"
#include "BKE_mesh.h"
#include "BKE_report.h"
+#include "BKE_tessmesh.h"
#include "ED_image.h"
#include "ED_mesh.h"
@@ -67,19 +72,20 @@
#include "uvedit_intern.h"
+#define EFA_F1_FLAG 2
+
/************************* state testing ************************/
int ED_uvedit_test(Object *obedit)
{
- EditMesh *em;
+ BMEditMesh *em;
int ret;
- if(!obedit || obedit->type != OB_MESH)
+ if(obedit->type != OB_MESH)
return 0;
- em = BKE_mesh_get_editmesh(obedit->data);
- ret = EM_texFaceCheck(em);
- BKE_mesh_end_editmesh(obedit->data, em);
+ em = ((Mesh*)obedit->data)->edit_btmesh;
+ ret = EDBM_texFaceCheck(em);
return ret;
}
@@ -88,9 +94,10 @@ int ED_uvedit_test(Object *obedit)
void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *previma)
{
- EditMesh *em;
- EditFace *efa;
- MTFace *tf;
+ BMEditMesh *em;
+ BMFace *efa;
+ BMIter iter;
+ MTexPoly *tf;
int update= 0;
/* skip assigning these procedural images... */
@@ -101,21 +108,21 @@ void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *pre
if(!obedit || (obedit->type != OB_MESH))
return;
- em= BKE_mesh_get_editmesh(((Mesh*)obedit->data));
- if(!em || !em->faces.first) {
- BKE_mesh_end_editmesh(obedit->data, em);
+ em= ((Mesh*)obedit->data)->edit_btmesh;
+ if(!em || !em->bm->totface) {
return;
}
/* ensure we have a uv layer */
- if(!CustomData_has_layer(&em->fdata, CD_MTFACE)) {
- EM_add_data_layer(em, &em->fdata, CD_MTFACE, NULL);
+ if(!CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY)) {
+ BM_add_data_layer(em->bm, &em->bm->pdata, CD_MTEXPOLY);
+ BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPUV);
update= 1;
}
/* now assign to all visible faces */
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
if(uvedit_face_visible(scene, previma, efa, tf)) {
if(ima) {
@@ -137,17 +144,16 @@ void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *pre
/* and update depdency graph */
if(update)
DAG_id_tag_update(obedit->data, 0);
-
- BKE_mesh_end_editmesh(obedit->data, em);
}
/* dotile - 1, set the tile flag (from the space image)
* 2, set the tile index for the faces. */
static int uvedit_set_tile(Object *obedit, Image *ima, int curtile)
{
- EditMesh *em;
- EditFace *efa;
- MTFace *tf;
+ BMEditMesh *em;
+ BMFace *efa;
+ BMIter iter;
+ MTexPoly *tf;
/* verify if we have something to do */
if(!ima || !ED_uvedit_test(obedit))
@@ -160,17 +166,16 @@ static int uvedit_set_tile(Object *obedit, Image *ima, int curtile)
if(ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE)
return 0;
- em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+ em= ((Mesh*)obedit->data)->edit_btmesh;
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
- if(efa->h==0 && efa->f & SELECT)
+ if(!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT))
tf->tile= curtile; /* set tile index */
}
DAG_id_tag_update(obedit->data, 0);
- BKE_mesh_end_editmesh(obedit->data, em);
return 1;
}
@@ -181,13 +186,7 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist
{
int width, height;
- if(sima) {
- ED_space_image_size(sima, &width, &height);
- }
- else {
- width= 256;
- height= 256;
- }
+ ED_space_image_size(sima, &width, &height);
dist[0]= pixeldist/width;
dist[1]= pixeldist/height;
@@ -195,18 +194,17 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist
/*************** visibility and selection utilities **************/
-int uvedit_face_visible_nolocal(Scene *scene, EditFace *efa)
+int uvedit_face_visible_nolocal(Scene *scene, BMFace *efa)
{
ToolSettings *ts= scene->toolsettings;
if(ts->uv_flag & UV_SYNC_SELECTION)
- return (efa->h==0);
+ return (BM_TestHFlag(efa, BM_HIDDEN)==0);
else
- return (efa->h==0 && (efa->f & SELECT));
+ return (BM_TestHFlag(efa, BM_HIDDEN)==0 && BM_TestHFlag(efa, BM_SELECT));
}
-int uvedit_face_visible(Scene *scene, Image *ima, EditFace *efa, MTFace *tf)
-{
+int uvedit_face_visible(Scene *scene, Image *ima, BMFace *efa, MTexPoly *tf) {
ToolSettings *ts= scene->toolsettings;
if(ts->uv_flag & UV_SHOW_SAME_IMAGE)
@@ -215,134 +213,216 @@ int uvedit_face_visible(Scene *scene, Image *ima, EditFace *efa, MTFace *tf)
return uvedit_face_visible_nolocal(scene, efa);
}
-int uvedit_face_selected(Scene *scene, EditFace *efa, MTFace *tf)
+int uvedit_face_selected(Scene *scene, BMEditMesh *em, BMFace *efa)
{
ToolSettings *ts= scene->toolsettings;
if(ts->uv_flag & UV_SYNC_SELECTION)
- return (efa->f & SELECT);
- else
- return (!(~tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) &&(!efa->v4 || tf->flag & TF_SEL4));
+ return (BM_TestHFlag(efa, BM_SELECT));
+ else {
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ if (!(luv->flag & MLOOPUV_VERTSEL))
+ return 0;
+ }
+
+ return 1;
+ }
}
-void uvedit_face_select(Scene *scene, EditFace *efa, MTFace *tf)
+int uvedit_face_select(Scene *scene, BMEditMesh *em, BMFace *efa)
{
ToolSettings *ts= scene->toolsettings;
if(ts->uv_flag & UV_SYNC_SELECTION)
- EM_select_face(efa, 1);
- else
- tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ BM_Select(em->bm, efa, 1);
+ else {
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
+
+ return 1;
+ }
+
+ return 0;
}
-void uvedit_face_deselect(Scene *scene, EditFace *efa, MTFace *tf)
+int uvedit_face_deselect(Scene *scene, BMEditMesh *em, BMFace *efa)
{
ToolSettings *ts= scene->toolsettings;
if(ts->uv_flag & UV_SYNC_SELECTION)
- EM_select_face(efa, 0);
- else
- tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ BM_Select(em->bm, efa, 0);
+ else {
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
+
+ return 1;
+ }
+
+ return 0;
}
-int uvedit_edge_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
+int uvedit_edge_selected(BMEditMesh *em, Scene *scene, BMLoop *l)
{
ToolSettings *ts= scene->toolsettings;
- int nvert= (efa->v4)? 4: 3;
if(ts->uv_flag & UV_SYNC_SELECTION) {
if(ts->selectmode & SCE_SELECT_FACE)
- return (efa->f & SELECT);
- else if(ts->selectmode & SCE_SELECT_EDGE)
- return (*(&efa->e1 + i))->f & SELECT;
- else
- return (((efa->v1 + i)->f & SELECT) && ((efa->v1 + (i+1)%nvert)->f & SELECT));
+ return BM_TestHFlag(l->f, BM_SELECT);
+ else if(ts->selectmode == SCE_SELECT_EDGE) {
+ return BM_TestHFlag(l->e, BM_SELECT);
+ } else
+ return BM_TestHFlag(l->v, BM_SELECT) &&
+ BM_TestHFlag(((BMLoop*)l->next)->v, BM_SELECT);
+ }
+ else {
+ MLoopUV *luv1, *luv2;
+
+ luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
+
+ return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
}
- else
- return (tf->flag & TF_SEL_MASK(i)) && (tf->flag & TF_SEL_MASK((i+1)%nvert));
}
-void uvedit_edge_select(Scene *scene, EditFace *efa, MTFace *tf, int i)
+void uvedit_edge_select(BMEditMesh *em, Scene *scene, BMLoop *l)
+
{
ToolSettings *ts= scene->toolsettings;
- int nvert= (efa->v4)? 4: 3;
if(ts->uv_flag & UV_SYNC_SELECTION) {
if(ts->selectmode & SCE_SELECT_FACE)
- EM_select_face(efa, 1);
+ BM_Select(em->bm, l->f, 1);
else if(ts->selectmode & SCE_SELECT_EDGE)
- EM_select_edge((*(&efa->e1 + i)), 1);
+ BM_Select(em->bm, l->e, 1);
else {
- (efa->v1 + i)->f |= SELECT;
- (efa->v1 + (i+1)%nvert)->f |= SELECT;
+ BM_Select(em->bm, l->e->v1, 1);
+ BM_Select(em->bm, l->e->v2, 1);
}
}
- else
- tf->flag |= TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert);
+ else {
+ MLoopUV *luv1, *luv2;
+
+ luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
+
+ luv1->flag |= MLOOPUV_VERTSEL;
+ luv2->flag |= MLOOPUV_VERTSEL;
+ }
}
-void uvedit_edge_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i)
+void uvedit_edge_deselect(BMEditMesh *em, Scene *scene, BMLoop *l)
+
{
ToolSettings *ts= scene->toolsettings;
- int nvert= (efa->v4)? 4: 3;
if(ts->uv_flag & UV_SYNC_SELECTION) {
if(ts->selectmode & SCE_SELECT_FACE)
- EM_select_face(efa, 0);
+ BM_Select(em->bm, l->f, 0);
else if(ts->selectmode & SCE_SELECT_EDGE)
- EM_select_edge((*(&efa->e1 + i)), 0);
+ BM_Select(em->bm, l->e, 0);
else {
- (efa->v1 + i)->f &= ~SELECT;
- (efa->v1 + (i+1)%nvert)->f &= ~SELECT;
+ BM_Select(em->bm, l->e->v1, 0);
+ BM_Select(em->bm, l->e->v2, 0);
}
}
- else
- tf->flag &= ~(TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert));
+ else {
+ MLoopUV *luv1, *luv2;
+
+ luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
+
+ luv1->flag &= ~MLOOPUV_VERTSEL;
+ luv2->flag &= ~MLOOPUV_VERTSEL;
+ }
}
-int uvedit_uv_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
+int uvedit_uv_selected(BMEditMesh *em, Scene *scene, BMLoop *l)
{
ToolSettings *ts= scene->toolsettings;
if(ts->uv_flag & UV_SYNC_SELECTION) {
if(ts->selectmode & SCE_SELECT_FACE)
- return (efa->f & SELECT);
+ return BM_TestHFlag(l->f, BM_SELECT);
else
- return (*(&efa->v1 + i))->f & SELECT;
+ return BM_TestHFlag(l, BM_SELECT);
+ }
+ else {
+ MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ return luv->flag & MLOOPUV_VERTSEL;
}
- else
- return tf->flag & TF_SEL_MASK(i);
}
-void uvedit_uv_select(Scene *scene, EditFace *efa, MTFace *tf, int i)
+void uvedit_uv_select(BMEditMesh *em, Scene *scene, BMLoop *l)
{
ToolSettings *ts= scene->toolsettings;
if(ts->uv_flag & UV_SYNC_SELECTION) {
if(ts->selectmode & SCE_SELECT_FACE)
- EM_select_face(efa, 1);
+ BM_Select(em->bm, l->f, 1);
else
- (*(&efa->v1 + i))->f |= SELECT;
+ BM_Select(em->bm, l->v, 1);
+ }
+ else {
+ MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ luv->flag |= MLOOPUV_VERTSEL;
}
- else
- tf->flag |= TF_SEL_MASK(i);
}
-void uvedit_uv_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i)
+void uvedit_uv_deselect(BMEditMesh *em, Scene *scene, BMLoop *l)
{
ToolSettings *ts= scene->toolsettings;
if(ts->uv_flag & UV_SYNC_SELECTION) {
if(ts->selectmode & SCE_SELECT_FACE)
- EM_select_face(efa, 0);
+ BM_Select(em->bm, l->f, 0);
else
- (*(&efa->v1 + i))->f &= ~SELECT;
+ BM_Select(em->bm, l->v, 0);
+ }
+ else {
+ MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ luv->flag &= ~MLOOPUV_VERTSEL;
}
- else
- tf->flag &= ~TF_SEL_MASK(i);
}
/*********************** geometric utilities ***********************/
+void poly_uv_center(BMEditMesh *em, BMFace *f, float cent[2])
+{
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ cent[0] = cent[1] = 0.0f;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ cent[0] += luv->uv[0];
+ cent[1] += luv->uv[1];
+ }
+
+ cent[0] /= (float) f->len;
+ cent[1] /= (float) f->len;
+}
+
void uv_center(float uv[][2], float cent[2], int quad)
{
@@ -364,6 +444,28 @@ float uv_area(float uv[][2], int quad)
return area_tri_v2(uv[0], uv[1], uv[2]);
}
+float poly_uv_area(float uv[][2], int len)
+{
+ //BMESH_TODO: make this not suck
+ //maybe use scanfill? I dunno.
+
+ if(len >= 4)
+ return area_tri_v2(uv[0], uv[1], uv[2]) + area_tri_v2(uv[0], uv[2], uv[3]);
+ else
+ return area_tri_v2(uv[0], uv[1], uv[2]);
+
+ return 1.0;
+}
+
+void poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
+{
+ int i;
+ for (i=0; i<len; i++) {
+ uv[i][0] = uv_orig[i][0]*aspx;
+ uv[i][1] = uv_orig[i][1]*aspy;
+ }
+}
+
void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy)
{
uv[0][0] = uv_orig[0][0]*aspx;
@@ -381,33 +483,42 @@ void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy)
int ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float *min, float *max)
{
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tf;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
int sel;
INIT_MINMAX2(min, max);
sel= 0;
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- if(uvedit_uv_selected(scene, efa, tf, 0)) { DO_MINMAX2(tf->uv[0], min, max); sel = 1; }
- if(uvedit_uv_selected(scene, efa, tf, 1)) { DO_MINMAX2(tf->uv[1], min, max); sel = 1; }
- if(uvedit_uv_selected(scene, efa, tf, 2)) { DO_MINMAX2(tf->uv[2], min, max); sel = 1; }
- if(efa->v4 && (uvedit_uv_selected(scene, efa, tf, 3))) { DO_MINMAX2(tf->uv[3], min, max); sel = 1; }
- }
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (uvedit_uv_selected(em, scene, l))
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ DO_MINMAX2(luv->uv, min, max);
+ sel = 1;
+ }
}
-
- BKE_mesh_end_editmesh(obedit->data, em);
+
return sel;
}
-static int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent, int mode)
+static int uvedit_center(Scene *scene, Image *ima, Object *obedit,
+ float *cent, int mode)
{
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tf;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
float min[2], max[2];
int change= 0;
@@ -418,14 +529,18 @@ static int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent,
else if(mode==1) {
INIT_MINMAX2(min, max);
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- if(uvedit_uv_selected(scene, efa, tf, 0)) { DO_MINMAX2(tf->uv[0], min, max); change= 1;}
- if(uvedit_uv_selected(scene, efa, tf, 1)) { DO_MINMAX2(tf->uv[1], min, max); change= 1;}
- if(uvedit_uv_selected(scene, efa, tf, 2)) { DO_MINMAX2(tf->uv[2], min, max); change= 1;}
- if(efa->v4 && (uvedit_uv_selected(scene, efa, tf, 3))) { DO_MINMAX2(tf->uv[3], min, max); change= 1;}
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (uvedit_uv_selected(em, scene, l)) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ DO_MINMAX2(luv->uv, min, max);
+ change= 1;
+ }
}
}
}
@@ -434,108 +549,147 @@ static int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent,
cent[0]= (min[0]+max[0])/2.0;
cent[1]= (min[1]+max[1])/2.0;
- BKE_mesh_end_editmesh(obedit->data, em);
return 1;
}
- BKE_mesh_end_editmesh(obedit->data, em);
return 0;
}
/************************** find nearest ****************************/
typedef struct NearestHit {
- EditFace *efa;
- MTFace *tf;
-
- int vert, uv;
- int edge, vert2;
+ BMFace *efa;
+ MTexPoly *tf;
+ BMLoop *l, *nextl;
+ MLoopUV *luv, *nextluv;
+ int lindex; //index of loop within face
+ int vert1, vert2; //index in mesh of edge vertices
} NearestHit;
-static void find_nearest_uv_edge(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
+static void find_nearest_uv_edge(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
{
- MTFace *tf;
- EditFace *efa;
- EditVert *eve;
+ MTexPoly *tf;
+ BMFace *efa;
+ BMLoop *l;
+ BMVert *eve;
+ BMIter iter, liter;
+ MLoopUV *luv, *nextluv;
float mindist, dist;
- int i, nverts;
+ int i;
mindist= 1e10f;
memset(hit, 0, sizeof(*hit));
- for(i=0, eve=em->verts.first; eve; eve=eve->next, i++)
- eve->tmp.l = i;
+ eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++) {
+ BMINDEX_SET(eve, i);
+ }
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- nverts= efa->v4? 4: 3;
-
- for(i=0; i<nverts; i++) {
- dist= dist_to_line_segment_v2(co, tf->uv[i], tf->uv[(i+1)%nverts]);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ i = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
- if(dist < mindist) {
- hit->tf= tf;
- hit->efa= efa;
- hit->edge= i;
- mindist= dist;
+ dist= dist_to_line_segment_v2(co, luv->uv, nextluv->uv);
- hit->vert= (*(&efa->v1 + i))->tmp.l;
- hit->vert2= (*(&efa->v1 + ((i+1)%nverts)))->tmp.l;
- }
+ if(dist < mindist) {
+ hit->tf= tf;
+ hit->efa= efa;
+
+ hit->l = l;
+ hit->nextl = (BMLoop*)l->next;
+ hit->luv = luv;
+ hit->nextluv = nextluv;
+ hit->lindex = i;
+ hit->vert1 = BMINDEX_GET(hit->l->v);
+ hit->vert2 = BMINDEX_GET(((BMLoop*)hit->l->next)->v);
+
+ mindist = dist;
}
+
+ i++;
}
}
}
-static void find_nearest_uv_face(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
+static void find_nearest_uv_face(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
{
- MTFace *tf;
- EditFace *efa;
+ MTexPoly *tf;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
float mindist, dist, cent[2];
- int i, nverts;
mindist= 1e10f;
memset(hit, 0, sizeof(*hit));
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- nverts= efa->v4? 4: 3;
- cent[0]= cent[1]= 0.0f;
+ /*this will fill in hit.vert1 and hit.vert2*/
+ find_nearest_uv_edge(scene, ima, em, co, hit);
+ hit->l = hit->nextl = NULL;
+ hit->luv = hit->nextluv = NULL;
- for(i=0; i<nverts; i++) {
- cent[0] += tf->uv[i][0];
- cent[1] += tf->uv[i][1];
- }
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ cent[0]= cent[1]= 0.0f;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- cent[0] /= nverts;
- cent[1] /= nverts;
- dist= fabs(co[0]- cent[0]) + fabs(co[1]- cent[1]);
+ cent[0] += luv->uv[0];
+ cent[1] += luv->uv[1];
+ }
- if(dist < mindist) {
- hit->tf= tf;
- hit->efa= efa;
- mindist= dist;
- }
+ cent[0] /= efa->len;
+ cent[1] /= efa->len;
+ dist= fabs(co[0]- cent[0]) + fabs(co[1]- cent[1]);
+
+ if(dist < mindist) {
+ hit->tf= tf;
+ hit->efa= efa;
+ mindist= dist;
}
}
}
-static int nearest_uv_between(MTFace *tf, int nverts, int id, float co[2], float uv[2])
+static int nearest_uv_between(BMEditMesh *em, BMFace *efa, int nverts, int id,
+ float co[2], float uv[2])
{
- float m[3], v1[3], v2[3], c1, c2;
- int id1, id2;
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter iter;
+ float m[3], v1[3], v2[3], c1, c2, *uv1, *uv2, *uv3;
+ int id1, id2, i;
- id1= (id+nverts-1)%nverts;
- id2= (id+nverts+1)%nverts;
+ id1= (id+efa->len-1)%efa->len;
+ id2= (id+efa->len+1)%efa->len;
m[0]= co[0]-uv[0];
m[1]= co[1]-uv[1];
- sub_v2_v2v2(v1, tf->uv[id1], tf->uv[id]);
- sub_v2_v2v2(v2, tf->uv[id2], tf->uv[id]);
+
+ i = 0;
+ BM_ITER(l, &iter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if (i == id1)
+ uv1 = luv->uv;
+ else if (i == id)
+ uv2 = luv->uv;
+ else if (i == id2)
+ uv3 = luv->uv;
+
+ i++;
+ }
+
+ sub_v3_v3v3(v1, uv1, uv);
+ sub_v3_v3v3(v2, uv3, uv);
/* m and v2 on same side of v-v1? */
c1= v1[0]*m[1] - v1[1]*m[0];
@@ -551,83 +705,103 @@ static int nearest_uv_between(MTFace *tf, int nverts, int id, float co[2], float
return (c1*c2 >= 0.0f);
}
-static void find_nearest_uv_vert(Scene *scene, Image *ima, EditMesh *em, float co[2], float penalty[2], NearestHit *hit)
+static void find_nearest_uv_vert(Scene *scene, Image *ima, BMEditMesh *em,
+ float co[2], float penalty[2], NearestHit *hit)
{
- EditFace *efa;
- EditVert *eve;
- MTFace *tf;
+ BMFace *efa;
+ BMVert *eve;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
float mindist, dist;
int i, nverts;
+ /*this will fill in hit.vert1 and hit.vert2*/
+ find_nearest_uv_edge(scene, ima, em, co, hit);
+ hit->l = hit->nextl = NULL;
+ hit->luv = hit->nextluv = NULL;
+
mindist= 1e10f;
memset(hit, 0, sizeof(*hit));
- for(i=0, eve=em->verts.first; eve; eve=eve->next, i++)
- eve->tmp.l = i;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- nverts= efa->v4? 4: 3;
+ eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++) {
+ BMINDEX_SET(eve, i);
+ }
- for(i=0; i<nverts; i++) {
- if(penalty && uvedit_uv_selected(scene, efa, tf, i))
- dist= fabs(co[0]-tf->uv[i][0])+penalty[0] + fabs(co[1]-tf->uv[i][1])+penalty[1];
- else
- dist= fabs(co[0]-tf->uv[i][0]) + fabs(co[1]-tf->uv[i][1]);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ i = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- if(dist<=mindist) {
- if(dist==mindist)
- if(!nearest_uv_between(tf, nverts, i, co, tf->uv[i]))
- continue;
+ if(penalty && uvedit_uv_selected(em, scene, l))
+ dist= fabs(co[0]-luv->uv[0])+penalty[0] + fabs(co[1]-luv->uv[1])+penalty[1];
+ else
+ dist= fabs(co[0]-luv->uv[0]) + fabs(co[1]-luv->uv[1]);
- mindist= dist;
+ if(dist<=mindist) {
+ if(dist==mindist)
+ if(!nearest_uv_between(em, efa, efa->len, i, co, luv->uv)) {
+ i++;
+ continue;
+ }
- hit->uv= i;
- hit->tf= tf;
- hit->efa= efa;
+ mindist= dist;
- hit->vert= (*(&efa->v1 + i))->tmp.l;
- }
+ hit->l = l;
+ hit->nextl = (BMLoop*)l->next;
+ hit->luv = luv;
+ hit->nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
+ hit->tf= tf;
+ hit->efa= efa;
+ hit->lindex = i;
+ hit->vert1 = BMINDEX_GET(hit->l->v);
}
+
+ i++;
}
}
}
int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, float co[2], float uv[2])
{
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tf;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
float mindist, dist;
- int i, nverts, found= 0;
+ int found= 0;
mindist= 1e10f;
uv[0]= co[0];
uv[1]= co[1];
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- nverts= efa->v4? 4: 3;
-
- for(i=0; i<nverts; i++) {
- dist= fabs(co[0]-tf->uv[i][0]) + fabs(co[1]-tf->uv[i][1]);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ dist= fabs(co[0]-luv->uv[0]) + fabs(co[1]-luv->uv[1]);
- if(dist<=mindist) {
- mindist= dist;
+ if(dist<=mindist) {
+ mindist= dist;
- uv[0]= tf->uv[i][0];
- uv[1]= tf->uv[i][1];
- found= 1;
- }
+ uv[0]= luv->uv[0];
+ uv[1]= luv->uv[1];
+ found= 1;
}
}
}
- BKE_mesh_end_editmesh(obedit->data, em);
return found;
}
@@ -649,26 +823,28 @@ static void uv_vertex_loop_flag(UvMapVert *first)
first->flag= 1;
}
-static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, EditFace *efa, int a)
+static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, BMFace *efa, int a)
{
UvMapVert *iterv, *first;
-
- first= EM_get_uv_map_vert(vmap, (*(&efa->v1 + a))->tmp.l);
+ BMLoop *l;
+
+ l = BMIter_AtIndex(NULL, BM_LOOPS_OF_FACE, efa, a);
+ first= EDBM_get_uv_map_vert(vmap, BMINDEX_GET(l->v));
for(iterv=first; iterv; iterv=iterv->next) {
if(iterv->separate)
first= iterv;
- if(iterv->f == efa->tmp.l)
+ if(iterv->f == BMINDEX_GET(efa))
return first;
}
return NULL;
}
-static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface)
+static int uv_edge_tag_faces(BMEditMesh *em, UvMapVert *first1, UvMapVert *first2, int *totface)
{
UvMapVert *iterv1, *iterv2;
- EditFace *efa;
+ BMFace *efa;
int tot = 0;
/* count number of faces this edge has */
@@ -682,8 +858,8 @@ static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface)
if(iterv1->f == iterv2->f) {
/* if face already tagged, don't do this edge */
- efa= EM_get_face_for_index(iterv1->f);
- if(efa->f1)
+ efa= EDBM_get_face_for_index(em, iterv1->f);
+ if(BMO_TestFlag(em->bm, efa, EFA_F1_FLAG))
return 0;
tot++;
@@ -707,8 +883,8 @@ static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface)
break;
if(iterv1->f == iterv2->f) {
- efa= EM_get_face_for_index(iterv1->f);
- efa->f1= 1;
+ efa= EDBM_get_face_for_index(em, iterv1->f);
+ BMO_SetFlag(em->bm, efa, EFA_F1_FLAG);
break;
}
}
@@ -717,41 +893,47 @@ static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface)
return 1;
}
-static int select_edgeloop(Scene *scene, Image *ima, EditMesh *em, NearestHit *hit, float limit[2], int extend)
+static int select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestHit *hit, float limit[2], int extend)
{
- EditVert *eve;
- EditFace *efa;
- MTFace *tf;
+ BMVert *eve;
+ BMFace *efa;
+ BMIter iter, liter;
+ BMLoop *l;
+ MTexPoly *tf;
UvVertMap *vmap;
UvMapVert *iterv1, *iterv2;
int a, count, looking, nverts, starttotf, select;
/* setup */
- EM_init_index_arrays(em, 0, 0, 1);
- vmap= EM_make_uv_vert_map(em, 0, 0, limit);
+ EDBM_init_index_arrays(em, 0, 0, 1);
+ vmap= EDBM_make_uv_vert_map(em, 0, 0, limit);
- for(count=0, eve=em->verts.first; eve; count++, eve= eve->next)
- eve->tmp.l = count;
+ count = 0;
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(eve, count);
+ count++;
+ }
- for(count=0, efa= em->faces.first; efa; count++, efa= efa->next) {
+ count = 0;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
if(!extend) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- uvedit_face_deselect(scene, efa, tf);
+ uvedit_face_deselect(scene, em, efa);
}
-
- efa->tmp.l= count;
- efa->f1= 0;
+
+ BMO_ClearFlag(em->bm, efa, EFA_F1_FLAG);
+ BMINDEX_SET(efa, count);
+ count++;
}
-
+
/* set flags for first face and verts */
- nverts= (hit->efa->v4)? 4: 3;
- iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge);
- iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts);
+ nverts= hit->efa->len;
+ iterv1= uv_vertex_map_get(vmap, hit->efa, hit->lindex);
+ iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->lindex+1)%nverts);
uv_vertex_loop_flag(iterv1);
uv_vertex_loop_flag(iterv2);
starttotf= 0;
- uv_edge_tag_faces(iterv1, iterv2, &starttotf);
+ uv_edge_tag_faces(em, iterv1, iterv2, &starttotf);
/* sorry, first edge isnt even ok */
if(iterv1->flag==0 && iterv2->flag==0) looking= 0;
@@ -762,21 +944,25 @@ static int select_edgeloop(Scene *scene, Image *ima, EditMesh *em, NearestHit *h
looking= 0;
/* find correct valence edges which are not tagged yet, but connect to tagged one */
- for(efa= em->faces.first; efa; efa=efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if(!efa->f1 && uvedit_face_visible(scene, ima, efa, tf)) {
- nverts= (efa->v4)? 4: 3;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+
+ if(!BMO_TestFlag(em->bm, efa, EFA_F1_FLAG) && uvedit_face_visible(scene, ima, efa, tf)) {
+ nverts= efa->len;
for(a=0; a<nverts; a++) {
/* check face not hidden and not tagged */
iterv1= uv_vertex_map_get(vmap, efa, a);
iterv2= uv_vertex_map_get(vmap, efa, (a+1)%nverts);
+
+ if (!iterv1 || !iterv2)
+ continue;
/* check if vertex is tagged and has right valence */
if(iterv1->flag || iterv2->flag) {
- if(uv_edge_tag_faces(iterv1, iterv2, &starttotf)) {
+ if(uv_edge_tag_faces(em, iterv1, iterv2, &starttotf)) {
looking= 1;
- efa->f1= 1;
+ BMO_SetFlag(em->bm, efa, EFA_F1_FLAG);
uv_vertex_loop_flag(iterv1);
uv_vertex_loop_flag(iterv2);
@@ -789,16 +975,14 @@ static int select_edgeloop(Scene *scene, Image *ima, EditMesh *em, NearestHit *h
}
/* do the actual select/deselect */
- nverts= (hit->efa->v4)? 4: 3;
- iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge);
- iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts);
+ nverts= hit->efa->len;
+ iterv1= uv_vertex_map_get(vmap, hit->efa, hit->lindex);
+ iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->lindex+1)%nverts);
iterv1->flag= 1;
iterv2->flag= 1;
if(extend) {
- tf= CustomData_em_get(&em->fdata, hit->efa->data, CD_MTFACE);
-
- if(uvedit_uv_selected(scene, hit->efa, tf, hit->edge) && uvedit_uv_selected(scene, hit->efa, tf, hit->edge))
+ if(uvedit_uv_selected(em, scene, hit->l) && uvedit_uv_selected(em, scene, hit->l))
select= 0;
else
select= 1;
@@ -806,82 +990,108 @@ static int select_edgeloop(Scene *scene, Image *ima, EditMesh *em, NearestHit *h
else
select= 1;
- for(efa= em->faces.first; efa; efa=efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
- nverts= (efa->v4)? 4: 3;
- for(a=0; a<nverts; a++) {
+ a = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
iterv1= uv_vertex_map_get(vmap, efa, a);
if(iterv1->flag) {
- if(select) uvedit_uv_select(scene, efa, tf, a);
- else uvedit_uv_deselect(scene, efa, tf, a);
+ if(select) uvedit_uv_select(em, scene, l);
+ else uvedit_uv_deselect(em, scene, l);
}
+
+ a++;
}
}
/* cleanup */
- EM_free_uv_vert_map(vmap);
- EM_free_index_arrays();
+ EDBM_free_uv_vert_map(vmap);
+ EDBM_free_index_arrays(em);
return (select)? 1: -1;
}
/*********************** linked select ***********************/
-static void select_linked(Scene *scene, Image *ima, EditMesh *em, float limit[2], NearestHit *hit, int extend)
+static void select_linked(Scene *scene, Image *ima, BMEditMesh *em, float limit[2], NearestHit *hit, int extend)
{
- EditFace *efa;
- MTFace *tf;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
UvVertMap *vmap;
UvMapVert *vlist, *iterv, *startv;
int a, i, nverts, stacksize= 0, *stack;
char *flag;
- EM_init_index_arrays(em, 0, 0, 1); /* we can use this too */
- vmap= EM_make_uv_vert_map(em, 1, 0, limit);
+ EDBM_init_index_arrays(em, 0, 0, 1); /* we can use this too */
+ vmap= EDBM_make_uv_vert_map(em, 1, 1, limit);
+
if(vmap == NULL)
return;
- stack= MEM_mallocN(sizeof(*stack) * em->totface, "UvLinkStack");
- flag= MEM_callocN(sizeof(*flag) * em->totface, "UvLinkFlag");
+ stack= MEM_mallocN(sizeof(*stack)*em->bm->totface, "UvLinkStack");
+ flag= MEM_callocN(sizeof(*flag)*em->bm->totface, "UvLinkFlag");
if(!hit) {
- for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ a = 0;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
- if(tf->flag & select_flag) {
- stack[stacksize]= a;
- stacksize++;
- flag[a]= 1;
+ if(uvedit_face_visible(scene, ima, efa, tf)) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ stack[stacksize]= a;
+ stacksize++;
+ flag[a]= 1;
+
+ break;
+ }
}
}
}
+ a++;
}
else {
- for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
+ a = 0;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
if(efa == hit->efa) {
stack[stacksize]= a;
stacksize++;
flag[a]= 1;
break;
}
+
+ a++;
}
}
while(stacksize > 0) {
+ int j;
+
stacksize--;
a= stack[stacksize];
+
+ j = 0;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if(j==a)
+ break;
- efa = EM_get_face_for_index(a);
+ j++;
+ }
+
+ nverts= efa->len;
- nverts= efa->v4? 4: 3;
+ i = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
- for(i=0; i<nverts; i++) {
/* make_uv_vert_map_EM sets verts tmp.l to the indices */
- vlist= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l);
+ vlist= EDBM_get_uv_map_vert(vmap, BMINDEX_GET(l->v));
startv= vlist;
@@ -901,50 +1111,71 @@ static void select_linked(Scene *scene, Image *ima, EditMesh *em, float limit[2]
stacksize++;
}
}
+
+ i++;
}
}
- if(!extend) {
- for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if(flag[a])
- tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
- else
- tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ if(!extend || hit) {
+ a = 0;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if (flag[a])
+ luv->flag |= MLOOPUV_VERTSEL;
+ else
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
}
}
else {
- for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
- if(flag[a]) {
- const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if((tf->flag & select_flag))
+ a = 0;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if (luv->flag & MLOOPUV_VERTSEL)
break;
}
+
+ a++;
}
if(efa) {
- for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
- if(flag[a]) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ a = 0;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!flag[a]) continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ luv->flag &= ~MLOOPUV_VERTSEL;
}
+
+ a++;
}
}
else {
- for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
- if(flag[a]) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ a = 0;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!flag[a]) continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ luv->flag |= MLOOPUV_VERTSEL;
}
+
+ a++;
}
}
}
MEM_freeN(stack);
MEM_freeN(flag);
- EM_free_uv_vert_map(vmap);
- EM_free_index_arrays();
+ EDBM_free_uv_vert_map(vmap);
+ EDBM_free_index_arrays(em);
}
/* ******************** align operator **************** */
@@ -954,31 +1185,33 @@ static void weld_align_uv(bContext *C, int tool)
Scene *scene;
Object *obedit;
Image *ima;
- EditMesh *em;
- EditFace *efa;
- MTFace *tf;
+ BMEditMesh *em;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
float cent[2], min[2], max[2];
scene= CTX_data_scene(C);
obedit= CTX_data_edit_object(C);
- em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+ em= ((Mesh*)obedit->data)->edit_btmesh;
ima= CTX_data_edit_image(C);
INIT_MINMAX2(min, max);
if(tool == 'a') {
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- if(uvedit_uv_selected(scene, efa, tf, 0))
- DO_MINMAX2(tf->uv[0], min, max)
- if(uvedit_uv_selected(scene, efa, tf, 1))
- DO_MINMAX2(tf->uv[1], min, max)
- if(uvedit_uv_selected(scene, efa, tf, 2))
- DO_MINMAX2(tf->uv[2], min, max)
- if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
- DO_MINMAX2(tf->uv[3], min, max)
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (uvedit_uv_selected(em, scene, l)) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ DO_MINMAX2(luv->uv, min, max)
+ }
}
}
@@ -988,41 +1221,39 @@ static void weld_align_uv(bContext *C, int tool)
uvedit_center(scene, ima, obedit, cent, 0);
if(tool == 'x' || tool == 'w') {
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- if(uvedit_uv_selected(scene, efa, tf, 0))
- tf->uv[0][0]= cent[0];
- if(uvedit_uv_selected(scene, efa, tf, 1))
- tf->uv[1][0]= cent[0];
- if(uvedit_uv_selected(scene, efa, tf, 2))
- tf->uv[2][0]= cent[0];
- if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
- tf->uv[3][0]= cent[0];
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (uvedit_uv_selected(em, scene, l)) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ luv->uv[0] = cent[0];
+ }
+
}
}
}
if(tool == 'y' || tool == 'w') {
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- if(uvedit_uv_selected(scene, efa, tf, 0))
- tf->uv[0][1]= cent[1];
- if(uvedit_uv_selected(scene, efa, tf, 1))
- tf->uv[1][1]= cent[1];
- if(uvedit_uv_selected(scene, efa, tf, 2))
- tf->uv[2][1]= cent[1];
- if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
- tf->uv[3][1]= cent[1];
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (uvedit_uv_selected(em, scene, l)) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ luv->uv[1] = cent[1];
+ }
+
}
}
}
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
}
static int align_exec(bContext *C, wmOperator *op)
@@ -1088,36 +1319,40 @@ static int stitch_exec(bContext *C, wmOperator *op)
{
Scene *scene;
Object *obedit;
- EditMesh *em;
- EditFace *efa;
- EditVert *eve;
+ BMEditMesh *em;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ BMVert *eve;
Image *ima;
- MTFace *tf;
+ SpaceImage *sima= CTX_wm_space_image(C);
+ MTexPoly *tf;
+ MLoopUV *luv;
scene= CTX_data_scene(C);
obedit= CTX_data_edit_object(C);
- em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+ em= ((Mesh*)obedit->data)->edit_btmesh;
ima= CTX_data_edit_image(C);
if(RNA_boolean_get(op->ptr, "use_limit")) {
UvVertMap *vmap;
UvMapVert *vlist, *iterv;
- float newuv[2], limit[2];
+ float newuv[2], limit[2], pixels;
int a, vtot;
- limit[0]= RNA_float_get(op->ptr, "limit");
- limit[1]= limit[0];
+ pixels= RNA_float_get(op->ptr, "limit");
+ uvedit_pixel_to_float(sima, limit, pixels);
- EM_init_index_arrays(em, 0, 0, 1);
- vmap= EM_make_uv_vert_map(em, 1, 0, limit);
+ EDBM_init_index_arrays(em, 0, 0, 1);
+ vmap= EDBM_make_uv_vert_map(em, 1, 0, limit);
if(vmap == NULL) {
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
-
- for(a=0, eve= em->verts.first; eve; a++, eve= eve->next) {
- vlist= EM_get_uv_map_vert(vmap, a);
+
+ a = 0;
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ vlist= EDBM_get_uv_map_vert(vmap, a);
while(vlist) {
newuv[0]= 0; newuv[1]= 0;
@@ -1127,12 +1362,15 @@ static int stitch_exec(bContext *C, wmOperator *op)
if((iterv != vlist) && iterv->separate)
break;
- efa = EM_get_face_for_index(iterv->f);
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ efa = EDBM_get_face_for_index(em, iterv->f);
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
- if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) {
- newuv[0] += tf->uv[iterv->tfindex][0];
- newuv[1] += tf->uv[iterv->tfindex][1];
+ l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
+ if (uvedit_uv_selected(em, scene, l)) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ newuv[0] += luv->uv[0];
+ newuv[1] += luv->uv[1];
vtot++;
}
}
@@ -1144,95 +1382,72 @@ static int stitch_exec(bContext *C, wmOperator *op)
if((iterv != vlist) && iterv->separate)
break;
- efa = EM_get_face_for_index(iterv->f);
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ efa = EDBM_get_face_for_index(em, iterv->f);
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+
+ l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
+ if (uvedit_uv_selected(em, scene, l)) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) {
- tf->uv[iterv->tfindex][0]= newuv[0];
- tf->uv[iterv->tfindex][1]= newuv[1];
+ luv->uv[0] = newuv[0];
+ luv->uv[1] = newuv[1];
+ vtot++;
}
}
}
vlist= iterv;
}
+
+ a++;
}
- EM_free_uv_vert_map(vmap);
- EM_free_index_arrays();
+ EDBM_free_uv_vert_map(vmap);
+ EDBM_free_index_arrays(em);
}
else {
UVVertAverage *uv_average, *uvav;
int count;
// index and count verts
- for(count=0, eve=em->verts.first; eve; count++, eve= eve->next)
- eve->tmp.l = count;
+ count=0;
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(eve, count);
+ count++;
+ }
uv_average= MEM_callocN(sizeof(UVVertAverage)*count, "Stitch");
// gather uv averages per vert
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- if(uvedit_uv_selected(scene, efa, tf, 0)) {
- uvav = uv_average + efa->v1->tmp.l;
- uvav->count++;
- uvav->uv[0] += tf->uv[0][0];
- uvav->uv[1] += tf->uv[0][1];
- }
-
- if(uvedit_uv_selected(scene, efa, tf, 1)) {
- uvav = uv_average + efa->v2->tmp.l;
- uvav->count++;
- uvav->uv[0] += tf->uv[1][0];
- uvav->uv[1] += tf->uv[1][1];
- }
-
- if(uvedit_uv_selected(scene, efa, tf, 2)) {
- uvav = uv_average + efa->v3->tmp.l;
- uvav->count++;
- uvav->uv[0] += tf->uv[2][0];
- uvav->uv[1] += tf->uv[2][1];
- }
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if(uvedit_uv_selected(em, scene, l)) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ uvav = uv_average + BMINDEX_GET(l->v);
- if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
- uvav = uv_average + efa->v4->tmp.l;
uvav->count++;
- uvav->uv[0] += tf->uv[3][0];
- uvav->uv[1] += tf->uv[3][1];
+ uvav->uv[0] += luv->uv[0];
+ uvav->uv[1] += luv->uv[1];
}
}
}
// apply uv welding
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- if(uvedit_uv_selected(scene, efa, tf, 0)) {
- uvav = uv_average + efa->v1->tmp.l;
- tf->uv[0][0] = uvav->uv[0]/uvav->count;
- tf->uv[0][1] = uvav->uv[1]/uvav->count;
- }
-
- if(uvedit_uv_selected(scene, efa, tf, 1)) {
- uvav = uv_average + efa->v2->tmp.l;
- tf->uv[1][0] = uvav->uv[0]/uvav->count;
- tf->uv[1][1] = uvav->uv[1]/uvav->count;
- }
-
- if(uvedit_uv_selected(scene, efa, tf, 2)) {
- uvav = uv_average + efa->v3->tmp.l;
- tf->uv[2][0] = uvav->uv[0]/uvav->count;
- tf->uv[2][1] = uvav->uv[1]/uvav->count;
- }
-
- if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
- uvav = uv_average + efa->v4->tmp.l;
- tf->uv[3][0] = uvav->uv[0]/uvav->count;
- tf->uv[3][1] = uvav->uv[1]/uvav->count;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if(uvedit_uv_selected(em, scene, l)) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ uvav = uv_average + BMINDEX_GET(l->v);
+ luv->uv[0] = uvav->uv[0]/uvav->count;
+ luv->uv[1] = uvav->uv[1]/uvav->count;
}
}
}
@@ -1243,7 +1458,6 @@ static int stitch_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -1261,7 +1475,7 @@ static void UV_OT_stitch(wmOperatorType *ot)
/* properties */
RNA_def_boolean(ot->srna, "use_limit", 1, "Use Limit", "Stitch UVs within a specified limit distance.");
- RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit", "Limit distance in normalized coordinates.", -FLT_MAX, FLT_MAX);
+ RNA_def_float(ot->srna, "limit", 20.0, 0.0f, FLT_MAX, "Limit", "Limit distance in image pixels.", -FLT_MAX, FLT_MAX);
}
/* ******************** (de)select all operator **************** */
@@ -1271,36 +1485,39 @@ static int select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene;
ToolSettings *ts;
Object *obedit;
- EditMesh *em;
- EditFace *efa;
+ BMEditMesh *em;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
Image *ima;
- MTFace *tf;
+ MTexPoly *tf;
+ MLoopUV *luv;
scene= CTX_data_scene(C);
ts= CTX_data_tool_settings(C);
obedit= CTX_data_edit_object(C);
- em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+ em= ((Mesh*)obedit->data)->edit_btmesh;
ima= CTX_data_edit_image(C);
if(ts->uv_flag & UV_SYNC_SELECTION) {
- EM_select_swap(em);
+ EDBM_select_swap(em);
}
else {
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- tf->flag ^= TF_SEL1;
- tf->flag ^= TF_SEL2;
- tf->flag ^= TF_SEL3;
- if(efa->v4) tf->flag ^= TF_SEL4;
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ luv->flag = luv->flag ^ MLOOPUV_VERTSEL;
}
}
}
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -1324,44 +1541,52 @@ static int select_all_exec(bContext *C, wmOperator *op)
Scene *scene;
ToolSettings *ts;
Object *obedit;
- EditMesh *em;
- EditFace *efa;
+ BMEditMesh *em;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
Image *ima;
- MTFace *tf;
+ MTexPoly *tf;
+ MLoopUV *luv;
int action = RNA_enum_get(op->ptr, "action");
+ int sel = 1;
scene= CTX_data_scene(C);
ts= CTX_data_tool_settings(C);
obedit= CTX_data_edit_object(C);
- em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+ em= ((Mesh*)obedit->data)->edit_btmesh;
ima= CTX_data_edit_image(C);
if(ts->uv_flag & UV_SYNC_SELECTION) {
+
switch (action) {
case SEL_TOGGLE:
- EM_toggle_select_all(em);
+ EDBM_toggle_select_all(((Mesh*)obedit->data)->edit_btmesh);
break;
case SEL_SELECT:
- EM_select_all(em);
+ EDBM_set_flag_all(em, BM_SELECT);
break;
case SEL_DESELECT:
- EM_deselect_all(em);
+ EDBM_clear_flag_all(em, BM_SELECT);
break;
case SEL_INVERT:
- EM_select_swap(em);
+ EDBM_select_swap(em);
break;
}
}
else {
-
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
- for(efa= em->faces.first; efa; efa= efa->next) {
- const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- if(tf->flag & select_flag) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
action = SEL_DESELECT;
break;
}
@@ -1369,25 +1594,25 @@ static int select_all_exec(bContext *C, wmOperator *op)
}
}
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
switch (action) {
case SEL_SELECT:
- tf->flag |= select_flag;
+ luv->flag |= MLOOPUV_VERTSEL;
break;
case SEL_DESELECT:
- tf->flag &= ~select_flag;
+ luv->flag &= MLOOPUV_VERTSEL;
break;
case SEL_INVERT:
- if ((tf->flag & select_flag) == select_flag) {
- tf->flag &= ~select_flag;
- } else {
- tf->flag &= ~select_flag;
- }
+ luv->flag ^= MLOOPUV_VERTSEL;
break;
}
}
@@ -1396,7 +1621,6 @@ static int select_all_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -1417,7 +1641,7 @@ static void UV_OT_select_all(wmOperatorType *ot)
/* ******************** mouse select operator **************** */
-static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky)
+static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky, int hitlen)
{
int i;
@@ -1426,7 +1650,7 @@ static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], floa
if(sticky == SI_STICKY_DISABLE)
return 0;
- for(i=0; i<4; i++) {
+ for(i=0; i<hitlen; i++) {
if(hitv[i] == v) {
if(sticky == SI_STICKY_LOC) {
if(fabs(hituv[i][0]-uv[0]) < limit[0] && fabs(hituv[i][1]-uv[1]) < limit[1])
@@ -1447,14 +1671,20 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
ToolSettings *ts= CTX_data_tool_settings(C);
Object *obedit= CTX_data_edit_object(C);
Image *ima= CTX_data_edit_image(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tf;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
NearestHit hit;
- int a, i, select = 1, selectmode, sticky, sync, hitv[4], nvert;
- int flush = 0; /* 0 == dont flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
- float limit[2], *hituv[4], penalty[2];
-
+ int a, i, select = 1, selectmode, sticky, sync, *hitv=NULL, nvert;
+ BLI_array_declare(hitv);
+ int flush = 0, hitlen=0; /* 0 == dont flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
+ float limit[2], **hituv = NULL;
+ BLI_array_declare(hituv);
+ float penalty[2];
+
uvedit_pixel_to_float(sima, limit, 0.05f);
uvedit_pixel_to_float(sima, penalty, 5.0f);
@@ -1474,7 +1704,7 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
else {
sync= 0;
selectmode= ts->uv_selectmode;
- sticky= (sima)? sima->sticky: 1;
+ sticky= sima->sticky;
}
/* find nearest element */
@@ -1482,76 +1712,88 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
/* find edge */
find_nearest_uv_edge(scene, ima, em, co, &hit);
if(hit.efa == NULL) {
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
+
+ hitlen = 0;
}
else if(selectmode == UV_SELECT_VERTEX) {
/* find vertex */
find_nearest_uv_vert(scene, ima, em, co, penalty, &hit);
if(hit.efa == NULL) {
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
/* mark 1 vertex as being hit */
- for(i=0; i<4; i++)
+ for(i=0; i<hit.efa->len; i++) {
+ BLI_array_growone(hitv);
+ BLI_array_growone(hituv);
hitv[i]= 0xFFFFFFFF;
+ }
+
+ hitv[hit.lindex]= hit.vert1;
+ hituv[hit.lindex]= hit.luv->uv;
- hitv[hit.uv]= hit.vert;
- hituv[hit.uv]= hit.tf->uv[hit.uv];
+ hitlen = hit.efa->len;
}
else if(selectmode == UV_SELECT_EDGE) {
/* find edge */
find_nearest_uv_edge(scene, ima, em, co, &hit);
if(hit.efa == NULL) {
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
/* mark 2 edge vertices as being hit */
- for(i=0; i<4; i++)
+ for(i=0; i<hit.efa->len; i++) {
+ BLI_array_growone(hitv);
+ BLI_array_growone(hituv);
hitv[i]= 0xFFFFFFFF;
+ }
- nvert= (hit.efa->v4)? 4: 3;
+ nvert= hit.efa->len;
- hitv[hit.edge]= hit.vert;
- hitv[(hit.edge+1)%nvert]= hit.vert2;
- hituv[hit.edge]= hit.tf->uv[hit.edge];
- hituv[(hit.edge+1)%nvert]= hit.tf->uv[(hit.edge+1)%nvert];
+ hitv[hit.lindex]= hit.vert1;
+ hitv[(hit.lindex+1)%nvert]= hit.vert2;
+ hituv[hit.lindex]= hit.luv->uv;
+ hituv[(hit.lindex+1)%nvert]= hit.nextluv->uv;
+
+ hitlen = hit.efa->len;
}
else if(selectmode == UV_SELECT_FACE) {
/* find face */
find_nearest_uv_face(scene, ima, em, co, &hit);
if(hit.efa == NULL) {
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
/* make active */
- EM_set_actFace(em, hit.efa);
+ EDBM_set_actFace(em, hit.efa);
/* mark all face vertices as being hit */
- for(i=0; i<4; i++)
- hituv[i]= hit.tf->uv[i];
+ i = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, hit.efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- hitv[0]= hit.efa->v1->tmp.l;
- hitv[1]= hit.efa->v2->tmp.l;
- hitv[2]= hit.efa->v3->tmp.l;
+ BLI_array_growone(hitv);
+ BLI_array_growone(hituv);
+ hituv[i]= luv->uv;
+ hitv[i] = BMINDEX_GET(l->v);
+ i++;
+ }
- if(hit.efa->v4) hitv[3]= hit.efa->v4->tmp.l;
- else hitv[3]= 0xFFFFFFFF;
+ hitlen = hit.efa->len;
}
else if(selectmode == UV_SELECT_ISLAND) {
find_nearest_uv_vert(scene, ima, em, co, NULL, &hit);
if(hit.efa==NULL) {
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
+
+ hitlen = 0;
}
else {
- BKE_mesh_end_editmesh(obedit->data, em);
+ hitlen = 0;
return OPERATOR_CANCELLED;
}
@@ -1565,36 +1807,36 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
else if(extend) {
if(selectmode == UV_SELECT_VERTEX) {
/* (de)select uv vertex */
- if(uvedit_uv_selected(scene, hit.efa, hit.tf, hit.uv)) {
- uvedit_uv_deselect(scene, hit.efa, hit.tf, hit.uv);
+ if(uvedit_uv_selected(em, scene, hit.l)) {
+ uvedit_uv_deselect(em, scene, hit.l);
select= 0;
}
else {
- uvedit_uv_select(scene, hit.efa, hit.tf, hit.uv);
+ uvedit_uv_select(em, scene, hit.l);
select= 1;
}
flush = 1;
}
else if(selectmode == UV_SELECT_EDGE) {
/* (de)select edge */
- if(uvedit_edge_selected(scene, hit.efa, hit.tf, hit.edge)) {
- uvedit_edge_deselect(scene, hit.efa, hit.tf, hit.edge);
+ if(uvedit_edge_selected(em, scene, hit.l)) {
+ uvedit_edge_deselect(em, scene, hit.l);
select= 0;
}
else {
- uvedit_edge_select(scene, hit.efa, hit.tf, hit.edge);
+ uvedit_edge_select(em, scene, hit.l);
select= 1;
}
flush = 1;
}
else if(selectmode == UV_SELECT_FACE) {
/* (de)select face */
- if(uvedit_face_selected(scene, hit.efa, hit.tf)) {
- uvedit_face_deselect(scene, hit.efa, hit.tf);
+ if(uvedit_face_selected(scene, em, hit.efa)) {
+ uvedit_face_deselect(scene, em, hit.efa);
select= 0;
}
else {
- uvedit_face_select(scene, hit.efa, hit.tf);
+ uvedit_face_select(scene, em, hit.efa);
select= 1;
}
flush = -1;
@@ -1602,97 +1844,89 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
/* (de)select sticky uv nodes */
if(sticky != SI_STICKY_DISABLE) {
- EditVert *ev;
-
- for(a=0, ev=em->verts.first; ev; ev = ev->next, a++)
- ev->tmp.l = a;
+ BMVert *ev;
+ a = 0;
+ BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(ev, a);
+ a++;
+ }
+
/* deselect */
if(select==0) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
- uvedit_uv_deselect(scene, efa, tf, 0);
- if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
- uvedit_uv_deselect(scene, efa, tf, 1);
- if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
- uvedit_uv_deselect(scene, efa, tf, 2);
- if(efa->v4)
- if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
- uvedit_uv_deselect(scene, efa, tf, 3);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ if(sticky_select(limit, hitv, BMINDEX_GET(l->v), hituv, luv->uv, sticky, hitlen))
+ uvedit_uv_deselect(em, scene, l);
}
}
flush = -1;
}
/* select */
else {
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
- uvedit_uv_select(scene, efa, tf, 0);
- if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
- uvedit_uv_select(scene, efa, tf, 1);
- if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
- uvedit_uv_select(scene, efa, tf, 2);
- if(efa->v4)
- if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
- uvedit_uv_select(scene, efa, tf, 3);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ if(sticky_select(limit, hitv, BMINDEX_GET(l->v), hituv, luv->uv, sticky, hitlen))
+ uvedit_uv_select(em, scene, l);
}
}
-
+
flush = 1;
}
}
}
else {
/* deselect all */
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- uvedit_face_deselect(scene, efa, tf);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ uvedit_face_deselect(scene, em, efa);
}
if(selectmode == UV_SELECT_VERTEX) {
/* select vertex */
- uvedit_uv_select(scene, hit.efa, hit.tf, hit.uv);
+ uvedit_uv_select(em, scene, hit.l);
flush= 1;
}
else if(selectmode == UV_SELECT_EDGE) {
/* select edge */
- uvedit_edge_select(scene, hit.efa, hit.tf, hit.edge);
+ uvedit_edge_select(em, scene, hit.l);
flush= 1;
}
else if(selectmode == UV_SELECT_FACE) {
/* select face */
- uvedit_face_select(scene, hit.efa, hit.tf);
+ uvedit_face_select(scene, em, hit.efa);
}
/* select sticky uvs */
if(sticky != SI_STICKY_DISABLE) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if(uvedit_face_visible(scene, ima, efa, tf)) {
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
if(sticky == SI_STICKY_DISABLE) continue;
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
- uvedit_uv_select(scene, efa, tf, 0);
- if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
- uvedit_uv_select(scene, efa, tf, 1);
- if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
- uvedit_uv_select(scene, efa, tf, 2);
- if(efa->v4)
- if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
- uvedit_uv_select(scene, efa, tf, 3);
+ if(sticky_select(limit, hitv, BMINDEX_GET(l->v), hituv, luv->uv, sticky, hitlen))
+ uvedit_uv_select(em, scene, l);
flush= 1;
}
}
}
}
-
+#if 0 //bmesh does flushing through the BM_Select functions, so not sure
+ //what to do about this bit.
if(sync) {
/* flush for mesh selection */
if(ts->selectmode != SCE_SELECT_FACE) {
@@ -1700,11 +1934,10 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
else if(flush==-1) EM_deselect_flush(em);
}
}
-
+#endif
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
}
@@ -1813,7 +2046,7 @@ static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, i
ToolSettings *ts= CTX_data_tool_settings(C);
Object *obedit= CTX_data_edit_object(C);
Image *ima= CTX_data_edit_image(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
float limit[2];
int extend;
@@ -1821,7 +2054,6 @@ static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, i
if(ts->uv_flag & UV_SYNC_SELECTION) {
BKE_report(op->reports, RPT_ERROR, "Can't select linked when sync selection is enabled.");
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
@@ -1856,7 +2088,6 @@ static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, i
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -1921,31 +2152,45 @@ static int unlink_selection_exec(bContext *C, wmOperator *op)
ToolSettings *ts= CTX_data_tool_settings(C);
Object *obedit= CTX_data_edit_object(C);
Image *ima= CTX_data_edit_image(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tf;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
if(ts->uv_flag & UV_SYNC_SELECTION) {
BKE_report(op->reports, RPT_ERROR, "Can't unlink selection when sync selection is enabled.");
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ int desel = 0;
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
- if(~tf->flag & select_flag)
- tf->flag &= ~select_flag;
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->pdata, l->head.data, CD_MLOOPUV);
+
+ if (!(luv->flag & MLOOPUV_VERTSEL)) {
+ desel = 1;
+ break;
+ }
+ }
+
+ if (desel) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->pdata, l->head.data, CD_MLOOPUV);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
}
}
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -1980,78 +2225,77 @@ static void uv_faces_do_sticky(bContext *C, SpaceImage *sima, Scene *scene, Obje
* selection (so for sticky modes, vertex or location based). */
ToolSettings *ts= CTX_data_tool_settings(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tf;
- int nverts, i;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
if((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_VERTEX) {
/* Tag all verts as untouched, then touch the ones that have a face center
- * in the loop and select all MTFace UV's that use a touched vert. */
- EditVert *eve;
+ * in the loop and select all MLoopUV's that use a touched vert. */
+ BMVert *eve;
- for(eve= em->verts.first; eve; eve= eve->next)
- eve->tmp.l = 0;
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL)
+ BMINDEX_SET(eve, 0);
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->tmp.l) {
- if(efa->v4)
- efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= efa->v4->tmp.l=1;
- else
- efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= 1;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if(BMINDEX_GET(efa)) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ BMINDEX_SET(l->v, 1);
+ }
}
}
/* now select tagged verts */
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- nverts= efa->v4? 4: 3;
- for(i=0; i<nverts; i++) {
- if((*(&efa->v1 + i))->tmp.l) {
- if(select)
- uvedit_uv_select(scene, efa, tf, i);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (BMINDEX_GET(l->v)) {
+ if (select)
+ uvedit_uv_select(em, scene, l);
else
- uvedit_uv_deselect(scene, efa, tf, i);
+ uvedit_uv_deselect(em, scene, l);
}
}
}
}
else if((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_LOC) {
- EditFace *efa_vlist;
- MTFace *tf_vlist;
+ BMFace *efa_vlist;
+ MTexPoly *tf_vlist;
UvMapVert *start_vlist=NULL, *vlist_iter;
struct UvVertMap *vmap;
float limit[2];
int efa_index;
- //EditVert *eve; /* removed vert counting for now */
+ //BMVert *eve; /* removed vert counting for now */
//int a;
uvedit_pixel_to_float(sima, limit, 0.05);
- EM_init_index_arrays(em, 0, 0, 1);
- vmap= EM_make_uv_vert_map(em, 0, 0, limit);
+ EDBM_init_index_arrays(em, 0, 0, 1);
+ vmap= EDBM_make_uv_vert_map(em, 0, 0, limit);
/* verts are numbered above in make_uv_vert_map_EM, make sure this stays true! */
/*for(a=0, eve= em->verts.first; eve; a++, eve= eve->next)
eve->tmp.l = a; */
if(vmap == NULL) {
- BKE_mesh_end_editmesh(obedit->data, em);
return;
}
- for(efa_index=0, efa= em->faces.first; efa; efa_index++, efa= efa->next) {
- if(efa->tmp.l) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- nverts= efa->v4? 4: 3;
-
- for(i=0; i<nverts; i++) {
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for (efa_index=0; efa; efa=BMIter_Step(&iter), efa_index++) {
+ if(BMINDEX_GET(efa)) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
if(select)
- uvedit_uv_select(scene, efa, tf, i);
+ uvedit_uv_select(em, scene, l);
else
- uvedit_uv_deselect(scene, efa, tf, i);
+ uvedit_uv_deselect(em, scene, l);
- vlist_iter= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l);
+ vlist_iter= EDBM_get_uv_map_vert(vmap, BMINDEX_GET(l->v));
while (vlist_iter) {
if(vlist_iter->separate)
@@ -2070,35 +2314,33 @@ static void uv_faces_do_sticky(bContext *C, SpaceImage *sima, Scene *scene, Obje
break;
if(efa_index != vlist_iter->f) {
- efa_vlist = EM_get_face_for_index(vlist_iter->f);
- tf_vlist = CustomData_em_get(&em->fdata, efa_vlist->data, CD_MTFACE);
+ efa_vlist = EDBM_get_face_for_index(em, vlist_iter->f);
+ tf_vlist = CustomData_bmesh_get(&em->bm->pdata, efa_vlist->head.data, CD_MTEXPOLY);
if(select)
- uvedit_uv_select(scene, efa_vlist, tf_vlist, vlist_iter->tfindex);
+ uvedit_uv_select(em, scene, BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->tfindex));
else
- uvedit_uv_deselect(scene, efa_vlist, tf_vlist, vlist_iter->tfindex);
+ uvedit_uv_deselect(em, scene, BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->tfindex));
}
vlist_iter = vlist_iter->next;
}
}
}
}
- EM_free_index_arrays();
- EM_free_uv_vert_map(vmap);
+ EDBM_free_index_arrays(em);
+ EDBM_free_uv_vert_map(vmap);
}
else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->tmp.l) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if(BMINDEX_GET(efa)) {
if(select)
- uvedit_face_select(scene, efa, tf);
+ uvedit_face_select(scene, em, efa);
else
- uvedit_face_deselect(scene, efa, tf);
+ uvedit_face_deselect(scene, em, efa);
}
}
}
- BKE_mesh_end_editmesh(obedit->data, em);
}
static int border_select_exec(bContext *C, wmOperator *op)
@@ -2109,9 +2351,12 @@ static int border_select_exec(bContext *C, wmOperator *op)
Object *obedit= CTX_data_edit_object(C);
Image *ima= CTX_data_edit_image(C);
ARegion *ar= CTX_wm_region(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tface;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
rcti rect;
rctf rectf;
int change, pinned, select, faces;
@@ -2141,14 +2386,16 @@ static int border_select_exec(bContext *C, wmOperator *op)
change= 0;
- for(efa= em->faces.first; efa; efa= efa->next) {
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
/* assume not touched */
- efa->tmp.l = 0;
- tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if(uvedit_face_visible(scene, ima, efa, tface)) {
- uv_center(tface->uv, cent, efa->v4 != NULL);
+ BMINDEX_SET(efa, 0);
+
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(uvedit_face_visible(scene, ima, efa, tf)) {
+ poly_uv_center(em, efa, cent);
if(BLI_in_rctf(&rectf, cent[0], cent[1])) {
- efa->tmp.l = change = 1;
+ BMINDEX_SET(efa, 1);
+ change = 1;
}
}
}
@@ -2160,51 +2407,26 @@ static int border_select_exec(bContext *C, wmOperator *op)
else {
/* other selection modes */
change= 1;
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tf))
+ continue;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- for(efa= em->faces.first; efa; efa= efa->next) {
- tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if(uvedit_face_visible(scene, ima, efa, tface)) {
if(!pinned || (ts->uv_flag & UV_SYNC_SELECTION) ) {
+
/* UV_SYNC_SELECTION - can't do pinned selection */
- if(BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
- if(select) uvedit_uv_select(scene, efa, tface, 0);
- else uvedit_uv_deselect(scene, efa, tface, 0);
+ if(BLI_in_rctf(&rectf, luv->uv[0], luv->uv[1])) {
+ if(select) uvedit_uv_select(em, scene, l);
+ else uvedit_uv_deselect(em, scene, l);
}
- if(BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
- if(select) uvedit_uv_select(scene, efa, tface, 1);
- else uvedit_uv_deselect(scene, efa, tface, 1);
- }
- if(BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
- if(select) uvedit_uv_select(scene, efa, tface, 2);
- else uvedit_uv_deselect(scene, efa, tface, 2);
- }
- if(efa->v4 && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
- if(select) uvedit_uv_select(scene, efa, tface, 3);
- else uvedit_uv_deselect(scene, efa, tface, 3);
- }
- }
- else if(pinned) {
- if((tface->unwrap & TF_PIN1) &&
- BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
-
- if(select) uvedit_uv_select(scene, efa, tface, 0);
- else uvedit_uv_deselect(scene, efa, tface, 0);
- }
- if((tface->unwrap & TF_PIN2) &&
- BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
-
- if(select) uvedit_uv_select(scene, efa, tface, 1);
- else uvedit_uv_deselect(scene, efa, tface, 1);
- }
- if((tface->unwrap & TF_PIN3) &&
- BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
-
- if(select) uvedit_uv_select(scene, efa, tface, 2);
- else uvedit_uv_deselect(scene, efa, tface, 2);
- }
- if((efa->v4) && (tface->unwrap & TF_PIN4) && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
- if(select) uvedit_uv_select(scene, efa, tface, 3);
- else uvedit_uv_deselect(scene, efa, tface, 3);
+ } else if(pinned) {
+ if ((luv->flag & MLOOPUV_PINNED) &&
+ BLI_in_rctf(&rectf, luv->uv[0], luv->uv[1])) {
+ if(select) uvedit_uv_select(em, scene, l);
+ else uvedit_uv_deselect(em, scene, l);
}
}
}
@@ -2213,20 +2435,20 @@ static int border_select_exec(bContext *C, wmOperator *op)
if(change) {
/* make sure newly selected vert selection is updated*/
+#if 0 //ok, I think the BM_Select API handles all of this?
if(ts->uv_flag & UV_SYNC_SELECTION) {
if(ts->selectmode != SCE_SELECT_FACE) {
if(select) EM_select_flush(em);
else EM_deselect_flush(em);
}
}
+#endif
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
-
- BKE_mesh_end_editmesh(obedit->data, em);
+
return OPERATOR_CANCELLED;
}
@@ -2254,20 +2476,22 @@ static void UV_OT_select_border(wmOperatorType *ot)
/* ******************** circle select operator **************** */
-static void select_uv_inside_ellipse(Scene *scene, int select, EditFace *efa, MTFace *tface, int index, float *offset, float *ell, int select_index)
+static void select_uv_inside_ellipse(BMEditMesh *em, SpaceImage *sima, Scene *scene, int select,
+ float *offset, float *ell, BMLoop *l, MLoopUV *luv)
{
/* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
float x, y, r2, *uv;
- uv= tface->uv[index];
+
+ uv= luv->uv;
x= (uv[0] - offset[0])*ell[0];
y= (uv[1] - offset[1])*ell[1];
r2 = x*x + y*y;
if(r2 < 1.0) {
- if(select) uvedit_uv_select(scene, efa, tface, select_index);
- else uvedit_uv_deselect(scene, efa, tface, select_index);
+ if(select) uvedit_uv_select(em, scene, l);
+ else uvedit_uv_deselect(em, scene, l);
}
}
@@ -2276,10 +2500,13 @@ static int circle_select_exec(bContext *C, wmOperator *op)
SpaceImage *sima= CTX_wm_space_image(C);
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
ARegion *ar= CTX_wm_region(C);
- EditFace *efa;
- MTFace *tface;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ MTexPoly *tface;
int x, y, radius, width, height, select;
float zoomx, zoomy, offset[2], ellipse[2];
int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
@@ -2301,21 +2528,19 @@ static int circle_select_exec(bContext *C, wmOperator *op)
UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
/* do selection */
- for(efa= em->faces.first; efa; efa= efa->next) {
- tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- select_uv_inside_ellipse(scene, select, efa, tface, 0, offset, ellipse, 0);
- select_uv_inside_ellipse(scene, select, efa, tface, 1, offset, ellipse, 1);
- select_uv_inside_ellipse(scene, select, efa, tface, 2, offset, ellipse, 2);
- if(efa->v4)
- select_uv_inside_ellipse(scene, select, efa, tface, 3, offset, ellipse, 3);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ select_uv_inside_ellipse(em, sima, scene, select, offset, ellipse, l, luv);
+ }
}
+#if 0 //I think the BM_Select api stuff handles all this as necassary?
if(select) EM_select_flush(em);
else EM_deselect_flush(em);
-
+#endif
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -2414,97 +2639,88 @@ static void UV_OT_snap_cursor(wmOperatorType *ot)
static int snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
{
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tface;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tface;
+ MLoopUV *luv;
short change= 0;
- for(efa= em->faces.first; efa; efa= efa->next) {
- tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if(uvedit_face_visible(scene, ima, efa, tface)) {
- if(uvedit_uv_selected(scene, efa, tface, 0)) VECCOPY2D(tface->uv[0], sima->cursor);
- if(uvedit_uv_selected(scene, efa, tface, 1)) VECCOPY2D(tface->uv[1], sima->cursor);
- if(uvedit_uv_selected(scene, efa, tface, 2)) VECCOPY2D(tface->uv[2], sima->cursor);
- if(efa->v4)
- if(uvedit_uv_selected(scene, efa, tface, 3)) VECCOPY2D(tface->uv[3], sima->cursor);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tface))
+ continue;
- change= 1;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if(uvedit_uv_selected(em, scene, l)) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ VECCOPY2D(luv->uv, sima->cursor);
+ change= 1;
+ }
}
}
- BKE_mesh_end_editmesh(obedit->data, em);
return change;
}
static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit)
{
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- EditVert *eve;
- MTFace *tface;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ BMVert *eve;
+ MTexPoly *tface;
+ MLoopUV *luv;
short change = 0;
int count = 0;
float *coords;
short *usercount, users;
/* set all verts to -1 : an unused index*/
- for(eve= em->verts.first; eve; eve= eve->next)
- eve->tmp.l=-1;
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL)
+ BMINDEX_SET(eve, -1);
/* index every vert that has a selected UV using it, but only once so as to
* get unique indices and to count how much to malloc */
- for(efa= em->faces.first; efa; efa= efa->next) {
- tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- if(uvedit_face_visible(scene, ima, efa, tface)) {
- if(uvedit_uv_selected(scene, efa, tface, 0) && efa->v1->tmp.l==-1) efa->v1->tmp.l= count++;
- if(uvedit_uv_selected(scene, efa, tface, 1) && efa->v2->tmp.l==-1) efa->v2->tmp.l= count++;
- if(uvedit_uv_selected(scene, efa, tface, 2) && efa->v3->tmp.l==-1) efa->v3->tmp.l= count++;
- if(efa->v4)
- if(uvedit_uv_selected(scene, efa, tface, 3) && efa->v4->tmp.l==-1) efa->v4->tmp.l= count++;
-
- change = 1;
-
- /* optional speedup */
- efa->tmp.p = tface;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tface)) {
+ BMINDEX_SET(efa, 0);
+ continue;
+ } else {
+ BMINDEX_SET(efa, 1);
+ }
+
+ change = 1;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (uvedit_uv_selected(em, scene, l) && BMINDEX_GET(l->v) == -1) {
+ BMINDEX_SET(l->v, count);
+ count++;
+ }
}
- else
- efa->tmp.p = NULL;
}
coords = MEM_callocN(sizeof(float)*count*2, "snap to adjacent coords");
usercount = MEM_callocN(sizeof(short)*count, "snap to adjacent counts");
/* add all UV coords from visible, unselected UV coords as well as counting them to average later */
- for(efa= em->faces.first; efa; efa= efa->next) {
- if((tface=(MTFace *)efa->tmp.p)) {
- /* is this an unselected UV we can snap to? */
- if(efa->v1->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 0))) {
- coords[efa->v1->tmp.l*2] += tface->uv[0][0];
- coords[(efa->v1->tmp.l*2)+1] += tface->uv[0][1];
- usercount[efa->v1->tmp.l]++;
- change = 1;
- }
- if(efa->v2->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 1))) {
- coords[efa->v2->tmp.l*2] += tface->uv[1][0];
- coords[(efa->v2->tmp.l*2)+1] += tface->uv[1][1];
- usercount[efa->v2->tmp.l]++;
- change = 1;
- }
- if(efa->v3->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 2))) {
- coords[efa->v3->tmp.l*2] += tface->uv[2][0];
- coords[(efa->v3->tmp.l*2)+1] += tface->uv[2][1];
- usercount[efa->v3->tmp.l]++;
- change = 1;
- }
-
- if(efa->v4) {
- if(efa->v4->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 3))) {
- coords[efa->v4->tmp.l*2] += tface->uv[3][0];
- coords[(efa->v4->tmp.l*2)+1] += tface->uv[3][1];
- usercount[efa->v4->tmp.l]++;
- change = 1;
- }
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMINDEX_GET(efa))
+ continue;
+
+ tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tface))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (BMINDEX_GET(l->v) >= 0 &&
+ (!uvedit_uv_selected(em, scene, l))) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ coords[BMINDEX_GET(l->v)*2] += luv->uv[0];
+ coords[BMINDEX_GET(l->v)*2+1] += luv->uv[1];
+ change = 1;
}
}
}
@@ -2513,46 +2729,24 @@ static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obe
if(!change) {
MEM_freeN(coords);
MEM_freeN(usercount);
- BKE_mesh_end_editmesh(obedit->data, em);
return change;
}
/* copy the averaged unselected UVs back to the selected UVs */
- for(efa= em->faces.first; efa; efa= efa->next) {
- if((tface=(MTFace *)efa->tmp.p)) {
-
- if( uvedit_uv_selected(scene, efa, tface, 0) &&
- efa->v1->tmp.l >= 0 &&
- (users = usercount[efa->v1->tmp.l])
- ) {
- tface->uv[0][0] = coords[efa->v1->tmp.l*2] / users;
- tface->uv[0][1] = coords[(efa->v1->tmp.l*2)+1] / users;
- }
-
- if( uvedit_uv_selected(scene, efa, tface, 1) &&
- efa->v2->tmp.l >= 0 &&
- (users = usercount[efa->v2->tmp.l])
- ) {
- tface->uv[1][0] = coords[efa->v2->tmp.l*2] / users;
- tface->uv[1][1] = coords[(efa->v2->tmp.l*2)+1] / users;
- }
-
- if( uvedit_uv_selected(scene, efa, tface, 2) &&
- efa->v3->tmp.l >= 0 &&
- (users = usercount[efa->v3->tmp.l])
- ) {
- tface->uv[2][0] = coords[efa->v3->tmp.l*2] / users;
- tface->uv[2][1] = coords[(efa->v3->tmp.l*2)+1] / users;
- }
-
- if(efa->v4) {
- if( uvedit_uv_selected(scene, efa, tface, 3) &&
- efa->v4->tmp.l >= 0 &&
- (users = usercount[efa->v4->tmp.l])
- ) {
- tface->uv[3][0] = coords[efa->v4->tmp.l*2] / users;
- tface->uv[3][1] = coords[(efa->v4->tmp.l*2)+1] / users;
- }
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMINDEX_GET(efa))
+ continue;
+
+ tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tface))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (uvedit_uv_selected(em, scene, l) && BMINDEX_GET(l->v) >= 0
+ && (users = usercount[BMINDEX_GET(l->v)])) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ luv->uv[0] = coords[BMINDEX_GET(l->v)*2];
+ luv->uv[1] = coords[BMINDEX_GET(l->v)*2+1];
}
}
}
@@ -2560,43 +2754,41 @@ static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obe
MEM_freeN(coords);
MEM_freeN(usercount);
- BKE_mesh_end_editmesh(obedit->data, em);
return change;
}
static int snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
{
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- Image *ima;
- EditFace *efa;
- MTFace *tface;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ Image *ima= sima->image;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tface;
+ MLoopUV *luv;
int width= 0, height= 0;
float w, h;
short change = 0;
- if(!sima)
- return 0;
-
- ima= sima->image;
-
ED_space_image_size(sima, &width, &height);
w = (float)width;
h = (float)height;
- for(efa= em->faces.first; efa; efa= efa->next) {
- tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if(uvedit_face_visible(scene, ima, efa, tface)) {
- if(uvedit_uv_selected(scene, efa, tface, 0)) snap_uv_to_pixel(tface->uv[0], w, h);
- if(uvedit_uv_selected(scene, efa, tface, 1)) snap_uv_to_pixel(tface->uv[1], w, h);
- if(uvedit_uv_selected(scene, efa, tface, 2)) snap_uv_to_pixel(tface->uv[2], w, h);
- if(efa->v4)
- if(uvedit_uv_selected(scene, efa, tface, 3)) snap_uv_to_pixel(tface->uv[3], w, h);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tface))
+ continue;
- change = 1;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (uvedit_uv_selected(em, scene, l)) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ snap_uv_to_pixel(luv->uv, w, h);
+ }
}
+
+ change = 1;
}
- BKE_mesh_end_editmesh(obedit->data, em);
return change;
}
@@ -2658,35 +2850,34 @@ static int pin_exec(bContext *C, wmOperator *op)
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
Image *ima= CTX_data_edit_image(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tface;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tface;
+ MLoopUV *luv;
int clear= RNA_boolean_get(op->ptr, "clear");
- for(efa= em->faces.first; efa; efa= efa->next) {
- tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tface))
+ continue;
- if(uvedit_face_visible(scene, ima, efa, tface)) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
if(!clear) {
- if(uvedit_uv_selected(scene, efa, tface, 0)) tface->unwrap |= TF_PIN1;
- if(uvedit_uv_selected(scene, efa, tface, 1)) tface->unwrap |= TF_PIN2;
- if(uvedit_uv_selected(scene, efa, tface, 2)) tface->unwrap |= TF_PIN3;
- if(efa->v4)
- if(uvedit_uv_selected(scene, efa, tface, 3)) tface->unwrap |= TF_PIN4;
- }
- else {
- if(uvedit_uv_selected(scene, efa, tface, 0)) tface->unwrap &= ~TF_PIN1;
- if(uvedit_uv_selected(scene, efa, tface, 1)) tface->unwrap &= ~TF_PIN2;
- if(uvedit_uv_selected(scene, efa, tface, 2)) tface->unwrap &= ~TF_PIN3;
- if(efa->v4)
- if(uvedit_uv_selected(scene, efa, tface, 3)) tface->unwrap &= ~TF_PIN4;
+ if (uvedit_uv_selected(em, scene, l))
+ luv->flag |= MLOOPUV_PINNED;
+ } else {
+ if (uvedit_uv_selected(em, scene, l))
+ luv->flag &= ~MLOOPUV_PINNED;
}
}
}
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -2713,26 +2904,28 @@ static int select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
Image *ima= CTX_data_edit_image(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tface;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- if(uvedit_face_visible(scene, ima, efa, tface)) {
- if(tface->unwrap & TF_PIN1) uvedit_uv_select(scene, efa, tface, 0);
- if(tface->unwrap & TF_PIN2) uvedit_uv_select(scene, efa, tface, 1);
- if(tface->unwrap & TF_PIN3) uvedit_uv_select(scene, efa, tface, 2);
- if(efa->v4) {
- if(tface->unwrap & TF_PIN4) uvedit_uv_select(scene, efa, tface, 3);
- }
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tface;
+ MLoopUV *luv;
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if(!uvedit_face_visible(scene, ima, efa, tface))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if (luv->flag & MLOOPUV_PINNED)
+ uvedit_uv_select(em, scene, l);
}
}
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -2756,122 +2949,76 @@ static int hide_exec(bContext *C, wmOperator *op)
SpaceImage *sima= CTX_wm_space_image(C);
ToolSettings *ts= CTX_data_tool_settings(C);
Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tf;
+ Scene *scene = CTX_data_scene(C);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
int swap= RNA_boolean_get(op->ptr, "unselected");
int facemode= sima ? sima->flag & SI_SELACTFACE : 0;
if(ts->uv_flag & UV_SYNC_SELECTION) {
- EM_hide_mesh(em, swap);
+ EDBM_hide_mesh(em, swap);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
- if(swap) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if(facemode) {
- /* Pretend face mode */
- if(( (efa->v4==NULL &&
- ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) == (TF_SEL1|TF_SEL2|TF_SEL3) ) ||
- ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) == (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) ) == 0) {
-
- if(em->selectmode == SCE_SELECT_FACE) {
- efa->f &= ~SELECT;
- /* must re-select after */
- efa->e1->f &= ~SELECT;
- efa->e2->f &= ~SELECT;
- efa->e3->f &= ~SELECT;
- if(efa->e4) efa->e4->f &= ~SELECT;
- }
- else
- EM_select_face(efa, 0);
- }
- tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
- }
- else if(em->selectmode == SCE_SELECT_FACE) {
- const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
- if((tf->flag & select_flag)==0) {
- EM_select_face(efa, 0);
- tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
- }
- }
- else {
- /* EM_deselect_flush will deselect the face */
- if((tf->flag & TF_SEL1)==0) efa->v1->f &= ~SELECT;
- if((tf->flag & TF_SEL2)==0) efa->v2->f &= ~SELECT;
- if((tf->flag & TF_SEL3)==0) efa->v3->f &= ~SELECT;
- if((efa->v4) && (tf->flag & TF_SEL4)==0) efa->v4->f &= ~SELECT;
-
- tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
- }
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ int hide = 0;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ hide = 1;
+ break;
}
}
- }
- else {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- if(facemode) {
- if( (efa->v4==NULL &&
- ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) == (TF_SEL1|TF_SEL2|TF_SEL3) ) ||
- ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) == (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) ) {
-
- if(em->selectmode == SCE_SELECT_FACE) {
- efa->f &= ~SELECT;
- /* must re-select after */
- efa->e1->f &= ~SELECT;
- efa->e2->f &= ~SELECT;
- efa->e3->f &= ~SELECT;
- if(efa->e4) efa->e4->f &= ~SELECT;
- }
- else
- EM_select_face(efa, 0);
- }
- tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ if (swap)
+ hide = !hide;
+
+ if (hide) {
+ if (facemode) {
+ /*check that every UV is selected*/
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ if (!(luv->flag & MLOOPUV_VERTSEL))
+ break;
}
- else if(em->selectmode == SCE_SELECT_FACE) {
- const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
- if(tf->flag & select_flag)
- EM_select_face(efa, 0);
-
- tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+
+ if (!luv) {
+ BM_Select(em->bm, efa, 0);
+ uvedit_face_deselect(scene, em, efa);
+ }
+ } else if(em->selectmode == SCE_SELECT_FACE) {
+ /*check if a UV is selected*/
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ BM_Select(em->bm, efa, 0);
+ }
+ luv->flag &= ~MLOOPUV_VERTSEL;
}
- else {
- /* EM_deselect_flush will deselect the face */
- if(tf->flag & TF_SEL1) efa->v1->f &= ~SELECT;
- if(tf->flag & TF_SEL2) efa->v2->f &= ~SELECT;
- if(tf->flag & TF_SEL3) efa->v3->f &= ~SELECT;
- if((efa->v4) && tf->flag & TF_SEL4) efa->v4->f &= ~SELECT;
-
- tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ } else {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ BM_Select(em->bm, l->v, 0);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
}
}
}
}
- /*deselects too many but ok for now*/
- if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX))
- EM_deselect_flush(em);
-
- if(em->selectmode==SCE_SELECT_FACE) {
- /* de-selected all edges from faces that were de-selected.
- * now make sure all faces that are selected also have selected edges */
- for(efa= em->faces.first; efa; efa= efa->next)
- if(efa->f & SELECT)
- EM_select_face(efa, 1);
- }
- EM_validate_selections(em);
+ EDBM_validate_selections(em);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -2898,114 +3045,44 @@ static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
SpaceImage *sima= CTX_wm_space_image(C);
ToolSettings *ts= CTX_data_tool_settings(C);
Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tf;
- int facemode= sima ? sima->flag & SI_SELACTFACE : 0;
- int stickymode= sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
+ Scene *scene = CTX_data_scene(C);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMVert *v;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(v, BM_TestHFlag(v, BM_SELECT));
+ }
+
/* call the mesh function if we are in mesh sync sel */
if(ts->uv_flag & UV_SYNC_SELECTION) {
- EM_reveal_mesh(em);
+ EDBM_reveal_mesh(em);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
-
- if(facemode) {
- if(em->selectmode == SCE_SELECT_FACE) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(!(efa->h) && !(efa->f & SELECT)) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- EM_select_face(efa, 1);
- tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
- }
- }
- }
- else {
- /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
- if(!stickymode) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(!(efa->h) && !(efa->f & SELECT)) {
- /* All verts must be unselected for the face to be selected in the UV view */
- if((efa->v1->f&SELECT)==0 && (efa->v2->f&SELECT)==0 && (efa->v3->f&SELECT)==0 && (efa->v4==0 || (efa->v4->f&SELECT)==0)) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
- /* Cant use EM_select_face here because it unselects the verts
- * and we cant tell if the face was totally unselected or not */
- /*EM_select_face(efa, 1);
- *
- * See Loop with EM_select_face() below... */
- efa->f |= SELECT;
- }
- }
- }
- }
- else {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(!(efa->h) && !(efa->f & SELECT)) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- if((efa->v1->f & SELECT)==0) {tf->flag |= TF_SEL1;}
- if((efa->v2->f & SELECT)==0) {tf->flag |= TF_SEL2;}
- if((efa->v3->f & SELECT)==0) {tf->flag |= TF_SEL3;}
- if((efa->v4 && (efa->v4->f & SELECT)==0)) {tf->flag |= TF_SEL4;}
- efa->f |= SELECT;
- }
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (em->selectmode == SCE_SELECT_FACE) {
+ uvedit_face_select(scene, em, efa);
+ } else {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (!BMINDEX_GET(l->v)) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ luv->flag |= MLOOPUV_VERTSEL;
}
}
-
- /* Select all edges and verts now */
- for(efa= em->faces.first; efa; efa= efa->next)
- /* we only selected the face flags, and didnt changes edges or verts, fix this now */
- if(!(efa->h) && (efa->f & SELECT))
- EM_select_face(efa, 1);
-
- EM_select_flush(em);
- }
- }
- else if(em->selectmode == SCE_SELECT_FACE) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(!(efa->h) && !(efa->f & SELECT)) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- efa->f |= SELECT;
- tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
- }
}
-
- /* Select all edges and verts now */
- for(efa= em->faces.first; efa; efa= efa->next)
- /* we only selected the face flags, and didnt changes edges or verts, fix this now */
- if(!(efa->h) && (efa->f & SELECT))
- EM_select_face(efa, 1);
- }
- else {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(!(efa->h) && !(efa->f & SELECT)) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- if((efa->v1->f & SELECT)==0) {tf->flag |= TF_SEL1;}
- if((efa->v2->f & SELECT)==0) {tf->flag |= TF_SEL2;}
- if((efa->v3->f & SELECT)==0) {tf->flag |= TF_SEL3;}
- if((efa->v4 && (efa->v4->f & SELECT)==0)) {tf->flag |= TF_SEL4;}
- efa->f |= SELECT;
- }
- }
-
- /* Select all edges and verts now */
- for(efa= em->faces.first; efa; efa= efa->next)
- /* we only selected the face flags, and didnt changes edges or verts, fix this now */
- if(!(efa->h) && (efa->f & SELECT))
- EM_select_face(efa, 1);
+ BM_Select(em->bm, efa, 1);
}
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 981332c8fbf..524706fe42d 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -728,8 +728,10 @@ static PEdge *p_edge_lookup(PHandle *handle, PHashKey *vkeys)
return NULL;
}
-static PBool p_face_exists(PHandle *handle, PHashKey *vkeys, int i1, int i2, int i3)
+int p_face_exists(ParamHandle *phandle, ParamKey *pvkeys, int i1, int i2, int i3)
{
+ PHandle *handle = (PHandle*)phandle;
+ PHashKey *vkeys = (PHashKey*)pvkeys;
PHashKey key = PHASH_edge(vkeys[i1], vkeys[i2]);
PEdge *e = (PEdge*)phash_lookup(handle->hash_edges, key);
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.h b/source/blender/editors/uvedit/uvedit_parametrizer.h
index 147ea430b3b..92ec80987e5 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.h
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.h
@@ -30,6 +30,8 @@ ParamHandle *param_construct_begin(void);
void param_aspect_ratio(ParamHandle *handle, float aspx, float aspy);
+int p_face_exists(ParamHandle *handle, ParamKey *vkeys, int i1, int i2, int i3);
+
void param_face_add(ParamHandle *handle,
ParamKey key,
int nverts,
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 7e686f818f7..57264e2cd5c 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -49,6 +49,14 @@
#include "BKE_depsgraph.h"
#include "BKE_image.h"
#include "BKE_mesh.h"
+#include "BKE_tessmesh.h"
+
+#include "BLI_math.h"
+#include "BLI_edgehash.h"
+#include "BLI_editVert.h"
+#include "BLI_scanfill.h"
+#include "BLI_array.h"
+#include "BLI_uvproject.h"
#include "PIL_time.h"
@@ -70,9 +78,9 @@
static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit)
{
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tf;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMIter iter;
Image *ima;
bScreen *sc;
ScrArea *sa;
@@ -80,15 +88,15 @@ static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit)
SpaceImage *sima;
if(ED_uvedit_test(obedit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
return 1;
}
- if(em && em->faces.first)
- EM_add_data_layer(em, &em->fdata, CD_MTFACE, NULL);
-
+ if(em && em->bm->totface && !CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY)) {
+ BM_add_data_layer(em->bm, &em->bm->pdata, CD_MTEXPOLY);
+ BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPUV);
+ }
+
if(!ED_uvedit_test(obedit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
return 0;
}
@@ -118,34 +126,36 @@ static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit)
ED_uvedit_assign_image(scene, obedit, ima, NULL);
/* select new UV's */
- for(efa=em->faces.first; efa; efa=efa->next) {
- tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- uvedit_face_select(scene, efa, tf);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ uvedit_face_select(scene, em, efa);
}
- BKE_mesh_end_editmesh(obedit->data, em);
return 1;
}
/****************** Parametrizer Conversion ***************/
-static ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short implicit, short fill, short sel, short correct_aspect)
+static ParamHandle *construct_param_handle(Scene *scene, BMEditMesh *em,
+ short implicit, short fill, short sel,
+ short correct_aspect)
{
ParamHandle *handle;
- EditFace *efa;
- EditEdge *eed;
- EditVert *ev;
- MTFace *tf;
+ BMFace *efa;
+ BMLoop *l;
+ BMEdge *eed;
+ BMVert *ev;
+ BMIter iter, liter;
+ MTexPoly *tf;
int a;
handle = param_construct_begin();
if(correct_aspect) {
- efa = EM_get_actFace(em, 1);
+ efa = EDBM_get_actFace(em, 1);
if(efa) {
+ MTexPoly *tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
float aspx, aspy;
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
ED_image_uv_aspect(tf->tpage, &aspx, &aspy);
@@ -155,71 +165,103 @@ static ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short imp
}
/* we need the vert indices */
- for(ev= em->verts.first, a=0; ev; ev= ev->next, a++)
- ev->tmp.l = a;
+ a = 0;
+ BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(ev, a);
+ a++;
+ }
- for(efa= em->faces.first; efa; efa= efa->next) {
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ EditVert *v, *lastv, *firstv;
+ EditFace *sefa;
ParamKey key, vkeys[4];
ParamBool pin[4], select[4];
+ BMLoop *ls[3];
+ MLoopUV *luvs[3];
float *co[4];
float *uv[4];
- int nverts;
+ int lsel;
- if((efa->h) || (sel && (efa->f & SELECT)==0))
+ if((BM_TestHFlag(efa, BM_HIDDEN)) || (sel && BM_TestHFlag(efa, BM_SELECT)==0))
continue;
- tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- if(implicit &&
- !( uvedit_uv_selected(scene, efa, tf, 0) ||
- uvedit_uv_selected(scene, efa, tf, 1) ||
- uvedit_uv_selected(scene, efa, tf, 2) ||
- (efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) )
- ) {
- continue;
+ tf= (MTexPoly *)CustomData_em_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ lsel = 0;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (uvedit_uv_selected(em, scene, l)) {
+ lsel = 1;
+ break;
+ }
}
+ if (implicit && !lsel)
+ continue;
+
key = (ParamKey)efa;
- vkeys[0] = (ParamKey)efa->v1->tmp.l;
- vkeys[1] = (ParamKey)efa->v2->tmp.l;
- vkeys[2] = (ParamKey)efa->v3->tmp.l;
-
- co[0] = efa->v1->co;
- co[1] = efa->v2->co;
- co[2] = efa->v3->co;
-
- uv[0] = tf->uv[0];
- uv[1] = tf->uv[1];
- uv[2] = tf->uv[2];
-
- pin[0] = ((tf->unwrap & TF_PIN1) != 0);
- pin[1] = ((tf->unwrap & TF_PIN2) != 0);
- pin[2] = ((tf->unwrap & TF_PIN3) != 0);
-
- select[0] = ((uvedit_uv_selected(scene, efa, tf, 0)) != 0);
- select[1] = ((uvedit_uv_selected(scene, efa, tf, 1)) != 0);
- select[2] = ((uvedit_uv_selected(scene, efa, tf, 2)) != 0);
-
- if(efa->v4) {
- vkeys[3] = (ParamKey)efa->v4->tmp.l;
- co[3] = efa->v4->co;
- uv[3] = tf->uv[3];
- pin[3] = ((tf->unwrap & TF_PIN4) != 0);
- select[3] = (uvedit_uv_selected(scene, efa, tf, 3) != 0);
- nverts = 4;
+
+ /*scanfill time!*/
+ firstv = lastv = NULL;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ v = BLI_addfillvert(l->v->co);
+
+ v->tmp.p = l;
+
+ if (lastv) {
+ BLI_addfilledge(lastv, v);
+ }
+
+ lastv = v;
+ if (!firstv)
+ firstv = v;
}
- else
- nverts = 3;
- param_face_add(handle, key, nverts, vkeys, co, uv, pin, select);
+ BLI_addfilledge(firstv, v);
+
+ /*mode 2 enables shortest-diagonal for quads*/
+ BLI_edgefill(0);
+ for (sefa = fillfacebase.first; sefa; sefa=sefa->next) {
+ ls[0] = sefa->v1->tmp.p;
+ ls[1] = sefa->v2->tmp.p;
+ ls[2] = sefa->v3->tmp.p;
+
+ luvs[0] = CustomData_bmesh_get(&em->bm->ldata, ls[0]->head.data, CD_MLOOPUV);
+ luvs[1] = CustomData_bmesh_get(&em->bm->ldata, ls[1]->head.data, CD_MLOOPUV);
+ luvs[2] = CustomData_bmesh_get(&em->bm->ldata, ls[2]->head.data, CD_MLOOPUV);
+
+ vkeys[0] = (ParamKey)BMINDEX_GET(ls[0]->v);
+ vkeys[1] = (ParamKey)BMINDEX_GET(ls[1]->v);
+ vkeys[2] = (ParamKey)BMINDEX_GET(ls[2]->v);
+
+ co[0] = ls[0]->v->co;
+ co[1] = ls[1]->v->co;
+ co[2] = ls[2]->v->co;
+
+ uv[0] = luvs[0]->uv;
+ uv[1] = luvs[1]->uv;
+ uv[2] = luvs[2]->uv;
+
+ pin[0] = (luvs[0]->flag & MLOOPUV_PINNED) != 0;
+ pin[1] = (luvs[1]->flag & MLOOPUV_PINNED) != 0;
+ pin[2] = (luvs[2]->flag & MLOOPUV_PINNED) != 0;
+
+ select[0] = uvedit_uv_selected(em, scene, ls[0]) != 0;
+ select[1] = uvedit_uv_selected(em, scene, ls[1]) != 0;
+ select[2] = uvedit_uv_selected(em, scene, ls[2]) != 0;
+
+ if (!p_face_exists(handle,vkeys,0,1,2))
+ param_face_add(handle, key, 3, vkeys, co, uv, pin, select);
+ }
+
+ BLI_end_edgefill();
}
if(!implicit) {
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->seam) {
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_TestHFlag(eed, BM_SEAM)) {
ParamKey vkeys[2];
- vkeys[0] = (ParamKey)eed->v1->tmp.l;
- vkeys[1] = (ParamKey)eed->v2->tmp.l;
+ vkeys[0] = (ParamKey)BMINDEX_GET(eed->v1);
+ vkeys[1] = (ParamKey)BMINDEX_GET(eed->v2);
param_edge_set_seam(handle, vkeys);
}
}
@@ -235,7 +277,7 @@ static ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short imp
typedef struct MinStretch {
Scene *scene;
Object *obedit;
- EditMesh *em;
+ BMEditMesh *em;
ParamHandle *handle;
float blend;
double lasttime;
@@ -247,7 +289,7 @@ static void minimize_stretch_init(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
MinStretch *ms;
int fill_holes= RNA_boolean_get(op->ptr, "fill_holes");
@@ -430,7 +472,7 @@ static int pack_islands_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
ParamHandle *handle;
handle = construct_param_handle(scene, em, 1, 0, 1, 1);
@@ -441,7 +483,6 @@ static int pack_islands_exec(bContext *C, wmOperator *UNUSED(op))
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -463,7 +504,7 @@ static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
ParamHandle *handle;
handle= construct_param_handle(scene, em, 1, 0, 1, 1);
@@ -474,7 +515,6 @@ static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -496,19 +536,17 @@ static ParamHandle *liveHandle = NULL;
void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
{
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
short abf = scene->toolsettings->unwrapper == 0;
short fillholes = scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES;
if(!ED_uvedit_test(obedit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
return;
}
- liveHandle = construct_param_handle(scene, em, 0, fillholes, 1, 1);
+ liveHandle = construct_param_handle(scene, em, 0, fillholes, 0, 1);
param_lscm_begin(liveHandle, PARAM_TRUE, abf);
- BKE_mesh_end_editmesh(obedit->data, em);
}
void ED_uvedit_live_unwrap_re_solve(void)
@@ -539,9 +577,12 @@ void ED_uvedit_live_unwrap_end(short cancel)
#define POLAR_ZX 0
#define POLAR_ZY 1
-static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result, Object *ob, EditMesh *em)
+static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result,
+ Object *ob, BMEditMesh *em)
{
- EditFace *efa;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
float min[3], max[3], *cursx;
int around= (v3d)? v3d->around: V3D_CENTER;
@@ -551,13 +592,12 @@ static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result, Ob
case V3D_CENTER: /* bounding box center */
min[0]= min[1]= min[2]= 1e20f;
max[0]= max[1]= max[2]= -1e20f;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- DO_MINMAX(efa->v1->co, min, max);
- DO_MINMAX(efa->v2->co, min, max);
- DO_MINMAX(efa->v3->co, min, max);
- if(efa->v4) DO_MINMAX(efa->v4->co, min, max);
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if(BM_TestHFlag(efa, BM_SELECT)) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ DO_MINMAX(l->v->co, min, max);
+ }
}
}
mid_v3_v3v3(result, min, max);
@@ -631,7 +671,7 @@ static void uv_map_transform(bContext *C, wmOperator *op, float center[3], float
/* context checks are messy here, making it work in both 3d view and uv editor */
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
View3D *v3d= CTX_wm_view3d(C);
RegionView3D *rv3d= CTX_wm_region_view3d(C);
/* common operator properties */
@@ -658,7 +698,6 @@ static void uv_map_transform(bContext *C, wmOperator *op, float center[3], float
else
uv_map_rotation_matrix(rotmat, rv3d, obedit, upangledeg, sideangledeg, radius);
- BKE_mesh_end_editmesh(obedit->data, em);
}
static void uv_transform_properties(wmOperatorType *ot, int radius)
@@ -681,14 +720,17 @@ static void uv_transform_properties(wmOperatorType *ot, int radius)
RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius", "Radius of the sphere or cylinder.", 0.0001f, 100.0f);
}
-static void correct_uv_aspect(EditMesh *em)
+static void correct_uv_aspect(BMEditMesh *em)
{
- EditFace *efa= EM_get_actFace(em, 1);
- MTFace *tf;
+ BMFace *efa= EDBM_get_actFace(em, 1);
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
float scale, aspx= 1.0f, aspy=1.0f;
if(efa) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
ED_image_uv_aspect(tf->tpage, &aspx, &aspy);
}
@@ -698,30 +740,28 @@ static void correct_uv_aspect(EditMesh *em)
if(aspx > aspy) {
scale= aspy/aspx;
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- tf->uv[0][0]= ((tf->uv[0][0]-0.5)*scale)+0.5;
- tf->uv[1][0]= ((tf->uv[1][0]-0.5)*scale)+0.5;
- tf->uv[2][0]= ((tf->uv[2][0]-0.5)*scale)+0.5;
- if(efa->v4)
- tf->uv[3][0]= ((tf->uv[3][0]-0.5)*scale)+0.5;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if (!BM_TestHFlag(efa, BM_SELECT))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ luv->uv[0] = ((luv->uv[0]-0.5)*scale)+0.5;
}
}
}
else {
scale= aspx/aspy;
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- tf->uv[0][1]= ((tf->uv[0][1]-0.5)*scale)+0.5;
- tf->uv[1][1]= ((tf->uv[1][1]-0.5)*scale)+0.5;
- tf->uv[2][1]= ((tf->uv[2][1]-0.5)*scale)+0.5;
- if(efa->v4)
- tf->uv[3][1]= ((tf->uv[3][1]-0.5)*scale)+0.5;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if (!BM_TestHFlag(efa, BM_SELECT))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ luv->uv[1] = ((luv->uv[1]-0.5)*scale)+0.5;
}
}
}
@@ -736,10 +776,12 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "scale_to_bounds", 0, "Scale to Bounds", "Scale UV coordinates to bounds after unwrapping.");
}
-static void uv_map_clip_correct(EditMesh *em, wmOperator *op)
+static void uv_map_clip_correct(BMEditMesh *em, wmOperator *op)
{
- EditFace *efa;
- MTFace *tf;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
float dx, dy, min[2], max[2];
int b, nverts;
int correct_aspect= RNA_boolean_get(op->ptr, "correct_aspect");
@@ -753,16 +795,13 @@ static void uv_map_clip_correct(EditMesh *em, wmOperator *op)
if(scale_to_bounds) {
INIT_MINMAX2(min, max);
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(efa, BM_SELECT))
+ continue;
- DO_MINMAX2(tf->uv[0], min, max);
- DO_MINMAX2(tf->uv[1], min, max);
- DO_MINMAX2(tf->uv[2], min, max);
-
- if(efa->v4)
- DO_MINMAX2(tf->uv[3], min, max);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ DO_MINMAX2(luv->uv, min, max);
}
}
@@ -775,31 +814,28 @@ static void uv_map_clip_correct(EditMesh *em, wmOperator *op)
if(dy > 0.0f)
dy= 1.0f/dy;
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- nverts= (efa->v4)? 4: 3;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(efa, BM_SELECT))
+ continue;
- for(b=0; b<nverts; b++) {
- tf->uv[b][0]= (tf->uv[b][0]-min[0])*dx;
- tf->uv[b][1]= (tf->uv[b][1]-min[1])*dy;
- }
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ luv->uv[0] = (luv->uv[0]-min[0])*dx;
+ luv->uv[1] = (luv->uv[1]-min[1])*dy;
}
}
}
else if(clip_to_bounds) {
/* clipping and wrapping */
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- nverts= (efa->v4)? 4: 3;
-
- for(b=0; b<nverts; b++) {
- CLAMP(tf->uv[b][0], 0.0, 1.0);
- CLAMP(tf->uv[b][1], 0.0, 1.0);
- }
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(efa, BM_SELECT))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ CLAMP(luv->uv[0], 0.0, 1.0);
+ CLAMP(luv->uv[1], 0.0, 1.0);
}
}
}
@@ -811,7 +847,7 @@ static int unwrap_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
ParamHandle *handle;
int method = RNA_enum_get(op->ptr, "method");
int fill_holes = RNA_boolean_get(op->ptr, "fill_holes");
@@ -819,7 +855,6 @@ static int unwrap_exec(bContext *C, wmOperator *op)
/* add uvs if they don't exist yet */
if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
@@ -841,7 +876,6 @@ static int unwrap_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -873,17 +907,18 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
Camera *camera= NULL;
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- ARegion *ar= CTX_wm_region(C);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ ARegion *ar = CTX_wm_region(C);
View3D *v3d= CTX_wm_view3d(C);
- RegionView3D *rv3d= ar->regiondata;
- EditFace *efa;
- MTFace *tf;
+ RegionView3D *rv3d= CTX_wm_region_view3d(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
float rotmat[4][4];
/* add uvs if they don't exist yet */
if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
@@ -893,17 +928,15 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
}
if(RNA_boolean_get(op->ptr, "orthographic")) {
- uv_map_rotation_matrix(rotmat, ar->regiondata, obedit, 90.0f, 0.0f, 1.0f);
+ uv_map_rotation_matrix(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f);
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- project_from_view_ortho(tf->uv[0], efa->v1->co, rotmat);
- project_from_view_ortho(tf->uv[1], efa->v2->co, rotmat);
- project_from_view_ortho(tf->uv[2], efa->v3->co, rotmat);
- if(efa->v4)
- project_from_view_ortho(tf->uv[3], efa->v4->co, rotmat);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(efa, BM_SELECT))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ project_from_view_ortho(luv->uv, l->v->co, rotmat);
}
}
}
@@ -911,15 +944,13 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
struct UvCameraInfo *uci= project_camera_info(v3d->camera, obedit->obmat, scene->r.xsch, scene->r.ysch);
if(uci) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- project_from_camera(tf->uv[0], efa->v1->co, uci);
- project_from_camera(tf->uv[1], efa->v2->co, uci);
- project_from_camera(tf->uv[2], efa->v3->co, uci);
- if(efa->v4)
- project_from_camera(tf->uv[3], efa->v4->co, uci);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(efa, BM_SELECT))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ project_from_camera(luv->uv, l->v->co, uci);
}
}
@@ -929,15 +960,13 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
else {
copy_m4_m4(rotmat, obedit->obmat);
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(efa, BM_SELECT))
+ continue;
- project_from_view(tf->uv[0], efa->v1->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
- project_from_view(tf->uv[1], efa->v2->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
- project_from_view(tf->uv[2], efa->v3->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
- if(efa->v4)
- project_from_view(tf->uv[3], efa->v4->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ project_from_view(luv->uv, l->v->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
}
}
}
@@ -947,7 +976,6 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -983,38 +1011,75 @@ static int reset_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tf;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
+ BLI_array_declare(uvs);
+ float **uvs = NULL;
+ int i;
/* add uvs if they don't exist yet */
if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(efa, BM_SELECT))
+ continue;
+
+ BLI_array_empty(uvs);
+ i = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ BLI_array_growone(uvs);
- tf->uv[0][0]= 0.0f;
- tf->uv[0][1]= 0.0f;
-
- tf->uv[1][0]= 1.0f;
- tf->uv[1][1]= 0.0f;
+ uvs[i++] = luv->uv;
+ }
+
+ if (i == 3) {
+ uvs[0][0] = 0.0;
+ uvs[0][1] = 0.0;
- tf->uv[2][0]= 1.0f;
- tf->uv[2][1]= 1.0f;
+ uvs[1][0] = 1.0;
+ uvs[1][1] = 0.0;
+
+ uvs[2][0] = 1.0;
+ uvs[2][1] = 1.0;
+ } else if (i == 4) {
+ uvs[0][0] = 0.0;
+ uvs[0][1] = 0.0;
- tf->uv[3][0]= 0.0f;
- tf->uv[3][1]= 1.0f;
+ uvs[1][0] = 1.0;
+ uvs[1][1] = 0.0;
+
+ uvs[2][0] = 1.0;
+ uvs[2][1] = 1.0;
+
+ uvs[3][0] = 0.0;
+ uvs[3][1] = 1.0;
+ /*make sure we ignore 2-sided faces*/
+ } else if (i > 2) {
+ float fac = 0.0f, dfac = 1.0f / (float)efa->len;
+
+ dfac *= M_PI*2;
+
+ for (i=0; i<efa->len; i++) {
+ uvs[i][0] = sin(fac);
+ uvs[i][1] = cos(fac);
+
+ fac += dfac;
+ }
}
}
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ BLI_array_free(uvs);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -1046,55 +1111,71 @@ static void uv_sphere_project(float target[2], float source[3], float center[3],
target[0] -= 1.0f;
}
-static void uv_map_mirror(EditFace *efa, MTFace *tf)
+static void uv_map_mirror(BMEditMesh *em, BMFace *efa, MTexPoly *tf)
{
+ BMLoop *l;
+ BMIter liter;
+ MLoopUV *luv;
+ BLI_array_declare(uvs);
+ float **uvs = NULL;
float dx;
- int nverts, i, mi;
+ int i, mi;
- nverts= (efa->v4)? 4: 3;
+ i = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ BLI_array_growone(uvs);
+
+ uvs[i] = luv->uv;
+ i++;
+ }
mi = 0;
- for(i=1; i<nverts; i++)
- if(tf->uv[i][0] > tf->uv[mi][0])
+ for(i=1; i<efa->len; i++)
+ if(uvs[i][0] > uvs[mi][0])
mi = i;
- for(i=0; i<nverts; i++) {
+ for(i=0; i<efa->len; i++) {
if(i != mi) {
- dx = tf->uv[mi][0] - tf->uv[i][0];
- if(dx > 0.5) tf->uv[i][0] += 1.0;
+ dx = uvs[mi][0] - uvs[i][0];
+ if(dx > 0.5) uvs[i][0] += 1.0;
}
}
+
+ BLI_array_free(uvs);
}
static int sphere_project_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tf;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
float center[3], rotmat[4][4];
/* add uvs if they don't exist yet */
if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
uv_map_transform(C, op, center, rotmat);
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(efa, BM_SELECT))
+ continue;
- uv_sphere_project(tf->uv[0], efa->v1->co, center, rotmat);
- uv_sphere_project(tf->uv[1], efa->v2->co, center, rotmat);
- uv_sphere_project(tf->uv[2], efa->v3->co, center, rotmat);
- if(efa->v4)
- uv_sphere_project(tf->uv[3], efa->v4->co, center, rotmat);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- uv_map_mirror(efa, tf);
+ uv_sphere_project(luv->uv, l->v->co, center, rotmat);
}
+
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ uv_map_mirror(em, efa, tf);
}
uv_map_clip_correct(em, op);
@@ -1102,7 +1183,6 @@ static int sphere_project_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -1142,31 +1222,33 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tf;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
float center[3], rotmat[4][4];
/* add uvs if they don't exist yet */
if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
uv_map_transform(C, op, center, rotmat);
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- uv_cylinder_project(tf->uv[0], efa->v1->co, center, rotmat);
- uv_cylinder_project(tf->uv[1], efa->v2->co, center, rotmat);
- uv_cylinder_project(tf->uv[2], efa->v3->co, center, rotmat);
- if(efa->v4)
- uv_cylinder_project(tf->uv[3], efa->v4->co, center, rotmat);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if (!BM_TestHFlag(efa, BM_SELECT))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
- uv_map_mirror(efa, tf);
+ uv_cylinder_project(luv->uv, l->v->co, center, rotmat);
}
+
+ uv_map_mirror(em, efa, tf);
}
uv_map_clip_correct(em, op);
@@ -1174,7 +1256,6 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -1200,15 +1281,17 @@ static int cube_project_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
- EditFace *efa;
- MTFace *tf;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
float no[3], cube_size, *loc, dx, dy;
int cox, coy;
/* add uvs if they don't exist yet */
if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
@@ -1218,41 +1301,38 @@ static int cube_project_exec(bContext *C, wmOperator *op)
/* choose x,y,z axis for projection depending on the largest normal
* component, but clusters all together around the center of map. */
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- normal_tri_v3( no,efa->v1->co, efa->v2->co, efa->v3->co);
-
- no[0]= fabs(no[0]);
- no[1]= fabs(no[1]);
- no[2]= fabs(no[2]);
-
- cox=0; coy= 1;
- if(no[2]>=no[0] && no[2]>=no[1]);
- else if(no[1]>=no[0] && no[1]>=no[2]) coy= 2;
- else { cox= 1; coy= 2; }
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ int first=1;
+
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ if (!BM_TestHFlag(efa, BM_SELECT))
+ continue;
+
+ VECCOPY(no, efa->no);
+
+ no[0]= fabs(no[0]);
+ no[1]= fabs(no[1]);
+ no[2]= fabs(no[2]);
+
+ cox=0; coy= 1;
+ if(no[2]>=no[0] && no[2]>=no[1]);
+ else if(no[1]>=no[0] && no[1]>=no[2]) coy= 2;
+ else { cox= 1; coy= 2; }
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ luv->uv[0] = 0.5+0.5*cube_size*(loc[cox] + l->v->co[cox]);
+ luv->uv[1] = 0.5+0.5*cube_size*(loc[coy] + l->v->co[coy]);
- tf->uv[0][0]= 0.5+0.5*cube_size*(loc[cox] + efa->v1->co[cox]);
- tf->uv[0][1]= 0.5+0.5*cube_size*(loc[coy] + efa->v1->co[coy]);
- dx = floor(tf->uv[0][0]);
- dy = floor(tf->uv[0][1]);
- tf->uv[0][0] -= dx;
- tf->uv[0][1] -= dy;
- tf->uv[1][0]= 0.5+0.5*cube_size*(loc[cox] + efa->v2->co[cox]);
- tf->uv[1][1]= 0.5+0.5*cube_size*(loc[coy] + efa->v2->co[coy]);
- tf->uv[1][0] -= dx;
- tf->uv[1][1] -= dy;
- tf->uv[2][0]= 0.5+0.5*cube_size*(loc[cox] + efa->v3->co[cox]);
- tf->uv[2][1]= 0.5+0.5*cube_size*(loc[coy] + efa->v3->co[coy]);
- tf->uv[2][0] -= dx;
- tf->uv[2][1] -= dy;
-
- if(efa->v4) {
- tf->uv[3][0]= 0.5+0.5*cube_size*(loc[cox] + efa->v4->co[cox]);
- tf->uv[3][1]= 0.5+0.5*cube_size*(loc[coy] + efa->v4->co[coy]);
- tf->uv[3][0] -= dx;
- tf->uv[3][1] -= dy;
+ if (first) {
+ dx = floor(luv->uv[0]);
+ dy = floor(luv->uv[1]);
+ first = 0;
}
+
+ luv->uv[0] -= dx;
+ luv->uv[1] -= dy;
}
}
@@ -1261,7 +1341,6 @@ static int cube_project_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index f563d8cbe92..1d50c0586a0 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -163,7 +163,7 @@ void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[][4], int *winsize
void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp);
void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[][4]);
-void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy);
+void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float power);
int GPU_lamp_shadow_layer(GPULamp *lamp);
#ifdef __cplusplus
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index d8de851624c..7d45640da63 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -293,9 +293,9 @@ GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
/*object->legacy = 1;*/
memset(numverts,0,sizeof(int)*MAX_MATERIALS);
- mface = dm->getFaceArray(dm);
+ mface = dm->getTessFaceArray(dm);
- numfaces= dm->getNumFaces(dm);
+ numfaces= dm->getNumTessFaces(dm);
for( i=0; i < numfaces; i++ ) {
if( mface[i].v4 )
numverts[mface[i].mat_nr] += 6; /* split every quad into two triangles */
@@ -869,9 +869,9 @@ static void GPU_buffer_copy_vertex(DerivedMesh *dm, float *varray, int *index, i
DEBUG_VBO("GPU_buffer_copy_vertex\n");
mvert = dm->getVertArray(dm);
- mface = dm->getFaceArray(dm);
+ mface = dm->getTessFaceArray(dm);
- numfaces= dm->getNumFaces(dm);
+ numfaces= dm->getNumTessFaces(dm);
for( i=0; i < numfaces; i++ ) {
start = index[redir[mface[i].mat_nr]];
if( mface[i].v4 )
@@ -913,13 +913,13 @@ static void GPU_buffer_copy_normal(DerivedMesh *dm, float *varray, int *index, i
int start;
float norm[3];
- float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
+ float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
MVert *mvert = dm->getVertArray(dm);
- MFace *mface = dm->getFaceArray(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
DEBUG_VBO("GPU_buffer_copy_normal\n");
- numfaces= dm->getNumFaces(dm);
+ numfaces= dm->getNumTessFaces(dm);
for( i=0; i < numfaces; i++ ) {
const int smoothnormal = (mface[i].flag & ME_SMOOTH);
@@ -983,7 +983,7 @@ static void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int *
DEBUG_VBO("GPU_buffer_copy_uv\n");
- mface = dm->getFaceArray(dm);
+ mface = dm->getTessFaceArray(dm);
mtface = DM_get_face_data_layer(dm, CD_MTFACE);
if( mtface == 0 ) {
@@ -991,7 +991,7 @@ static void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int *
return;
}
- numfaces= dm->getNumFaces(dm);
+ numfaces= dm->getNumTessFaces(dm);
for( i=0; i < numfaces; i++ ) {
start = index[redir[mface[i].mat_nr]];
if( mface[i].v4 )
@@ -1027,11 +1027,11 @@ static void GPU_buffer_copy_color3( DerivedMesh *dm, float *varray_, int *index,
int i, numfaces;
unsigned char *varray = (unsigned char *)varray_;
unsigned char *mcol = (unsigned char *)user;
- MFace *mface = dm->getFaceArray(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
DEBUG_VBO("GPU_buffer_copy_color3\n");
- numfaces= dm->getNumFaces(dm);
+ numfaces= dm->getNumTessFaces(dm);
for( i=0; i < numfaces; i++ ) {
int start = index[redir[mface[i].mat_nr]];
if( mface[i].v4 )
@@ -1057,11 +1057,11 @@ static void GPU_buffer_copy_color4( DerivedMesh *dm, float *varray_, int *index,
int i, numfaces;
unsigned char *varray = (unsigned char *)varray_;
unsigned char *mcol = (unsigned char *)user;
- MFace *mface = dm->getFaceArray(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
DEBUG_VBO("GPU_buffer_copy_color4\n");
- numfaces= dm->getNumFaces(dm);
+ numfaces= dm->getNumTessFaces(dm);
for( i=0; i < numfaces; i++ ) {
int start = index[redir[mface[i].mat_nr]];
if( mface[i].v4 )
@@ -1101,7 +1101,7 @@ static GPUBuffer *GPU_buffer_color( DerivedMesh *dm )
dm->drawObject->colType = CD_MCOL;
}
- numfaces= dm->getNumFaces(dm);
+ numfaces= dm->getNumTessFaces(dm);
colors = MEM_mallocN(numfaces*12*sizeof(unsigned char), "GPU_buffer_color");
for( i=0; i < numfaces*4; i++ ) {
colors[i*3] = mcol[i].b;
@@ -1151,7 +1151,7 @@ static void GPU_buffer_copy_uvedge(DerivedMesh *dm, float *varray, int *UNUSED(i
if(tf) {
for(i = 0; i < dm->numFaceData; i++, tf++) {
MFace mf;
- dm->getFace(dm,i,&mf);
+ dm->getTessFace(dm,i,&mf);
VECCOPY2D(&varray[j],tf->uv[0]);
VECCOPY2D(&varray[j+2],tf->uv[1]);
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index c909d83d307..e1ca64388ae 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -526,7 +526,7 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int
}
/* scale if not a power of two */
- if (!mipmap && (!is_pow2_limit(rectw) || !is_pow2_limit(recth))) {
+ if ((!is_pow2_limit(rectw) || !is_pow2_limit(recth))) {
rectw= smaller_pow2_limit(rectw);
recth= smaller_pow2_limit(recth);
@@ -1235,7 +1235,7 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[][4
Base *base;
Lamp *la;
int count;
- float position[4], direction[4], energy[4];
+ float position[4], direction[4], energy[4], power;
/* disable all lights */
for(count=0; count<8; count++)
@@ -1276,8 +1276,8 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[][4
glLightfv(GL_LIGHT0+count, GL_POSITION, position);
glLightf(GL_LIGHT0+count, GL_CONSTANT_ATTENUATION, 1.0);
- glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1/la->dist);
- glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2/(la->dist*la->dist));
+ glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, 0.0f/la->dist);
+ glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, 1.0f/(la->dist*la->dist));
if(la->type==LA_SPOT) {
/* spot lamp */
@@ -1289,6 +1289,8 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[][4
else
glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, 180.0);
}
+
+ power= (ELEM(la->type, LA_SUN, LA_HEMI))? la->energy*M_PI: la->energy*M_PI; //XXX la->power
/* setup energy */
mul_v3_v3fl(energy, &la->r, la->energy);
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 732cfed47d1..675c73da960 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -104,8 +104,8 @@ struct GPULamp {
int type, mode, lay, hide;
- float dynenergy, dyncol[3];
- float energy, col[3];
+ float dynpower, dyncol[3];
+ float power, col[3];
float co[3], vec[3];
float dynco[3], dynvec[3];
@@ -114,7 +114,7 @@ struct GPULamp {
float dynimat[4][4];
float spotsi, spotbl, k;
- float dist, att1, att2;
+ float dist;
float bias, d, clipend;
int size;
@@ -256,11 +256,11 @@ void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double tim
lamp= nlink->data;
if(!lamp->hide && (lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay))) {
- lamp->dynenergy = lamp->energy;
+ lamp->dynpower = lamp->power;
VECCOPY(lamp->dyncol, lamp->col);
}
else {
- lamp->dynenergy = 0.0f;
+ lamp->dynpower = 0.0f;
lamp->dyncol[0]= lamp->dyncol[1]= lamp->dyncol[2] = 0.0f;
}
}
@@ -395,9 +395,6 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode
case LA_FALLOFF_INVSQUARE:
GPU_link(mat, "lamp_falloff_invsquare", GPU_uniform(&lamp->dist), *dist, &visifac);
break;
- case LA_FALLOFF_SLIDERS:
- GPU_link(mat, "lamp_falloff_sliders", GPU_uniform(&lamp->dist), GPU_uniform(&lamp->att1), GPU_uniform(&lamp->att2), *dist, &visifac);
- break;
case LA_FALLOFF_CURVE:
{
float *array;
@@ -524,9 +521,6 @@ static void add_to_diffuse(GPUMaterial *mat, Material *ma, GPUShadeInput *shi, G
else {
/* input */
switch(ma->rampin_col) {
- case MA_RAMP_IN_ENERGY:
- GPU_link(mat, "ramp_rgbtobw", rgb, &fac);
- break;
case MA_RAMP_IN_SHADER:
fac= is;
break;
@@ -577,9 +571,6 @@ static void do_specular_ramp(GPUShadeInput *shi, GPUNodeLink *is, GPUNodeLink *t
/* input */
switch(ma->rampin_spec) {
- case MA_RAMP_IN_ENERGY:
- fac = t;
- break;
case MA_RAMP_IN_SHADER:
fac = is;
break;
@@ -679,7 +670,7 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
if(lamp->mode & LA_ONLYSHADOW) {
GPU_link(mat, "shade_only_shadow", i, shadfac,
- GPU_dynamic_uniform(&lamp->dynenergy), &shadfac);
+ GPU_dynamic_uniform(&lamp->dynpower), &shadfac);
if(!(lamp->mode & LA_NO_DIFF))
GPU_link(mat, "shade_only_shadow_diffuse", shadfac, shi->rgb,
@@ -1259,10 +1250,10 @@ void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi)
void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
{
GPUMaterial *mat= shi->gpumat;
- GPUNodeLink *emit, *ulinfac, *ulogfac, *mistfac;
+ GPUNodeLink *emit, *mistfac;
Material *ma= shi->mat;
World *world= mat->scene->world;
- float linfac, logfac, misttype;
+ float misttype;
memset(shr, 0, sizeof(*shr));
@@ -1300,20 +1291,6 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
shr->alpha = shi->alpha;
if(world) {
- /* exposure correction */
- if(world->exp!=0.0f || world->range!=1.0f) {
- linfac= 1.0 + pow((2.0*world->exp + 0.5), -10);
- logfac= log((linfac-1.0)/linfac)/world->range;
-
- GPU_link(mat, "set_value", GPU_uniform(&linfac), &ulinfac);
- GPU_link(mat, "set_value", GPU_uniform(&logfac), &ulogfac);
-
- GPU_link(mat, "shade_exposure_correct", shr->combined,
- ulinfac, ulogfac, &shr->combined);
- GPU_link(mat, "shade_exposure_correct", shr->spec,
- ulinfac, ulogfac, &shr->spec);
- }
-
/* ambient color */
if(world->ambr!=0.0f || world->ambg!=0.0f || world->ambb!=0.0f) {
if(GPU_link_changed(shi->amb) || ma->amb != 0.0f)
@@ -1442,14 +1419,14 @@ void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[][4])
invert_m4_m4(lamp->imat, mat);
}
-void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy)
+void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float power)
{
- lamp->energy = energy;
- if(lamp->mode & LA_NEG) lamp->energy= -lamp->energy;
+ lamp->power = power;
+ if(lamp->mode & LA_NEG) lamp->power= -lamp->power;
- lamp->col[0]= r* lamp->energy;
- lamp->col[1]= g* lamp->energy;
- lamp->col[2]= b* lamp->energy;
+ lamp->col[0]= r* lamp->power;
+ lamp->col[1]= g* lamp->power;
+ lamp->col[2]= b* lamp->power;
}
static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *la, GPULamp *lamp)
@@ -1465,12 +1442,12 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l
lamp->mode = la->mode;
lamp->type = la->type;
- lamp->energy = la->energy;
- if(lamp->mode & LA_NEG) lamp->energy= -lamp->energy;
+ lamp->power= (ELEM(la->type, LA_SUN, LA_HEMI))? la->energy*M_PI: la->energy*M_PI; //XXX la->power;
+ if(lamp->mode & LA_NEG) lamp->power= -lamp->power;
- lamp->col[0]= la->r*lamp->energy;
- lamp->col[1]= la->g*lamp->energy;
- lamp->col[2]= la->b*lamp->energy;
+ lamp->col[0]= la->r*lamp->power;
+ lamp->col[1]= la->g*lamp->power;
+ lamp->col[2]= la->b*lamp->power;
GPU_lamp_update(lamp, ob->lay, (ob->restrictflag & OB_RESTRICT_RENDER), ob->obmat);
@@ -1484,8 +1461,6 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l
lamp->dist= la->dist;
lamp->falloff_type= la->falloff_type;
- lamp->att1= la->att1;
- lamp->att2= la->att2;
lamp->curfalloff= la->curfalloff;
/* initshadowbuf */
diff --git a/source/blender/gpu/intern/gpu_shader_material.glsl b/source/blender/gpu/intern/gpu_shader_material.glsl
index 03883fb4f57..f296dc3a67e 100644
--- a/source/blender/gpu/intern/gpu_shader_material.glsl
+++ b/source/blender/gpu/intern/gpu_shader_material.glsl
@@ -1741,11 +1741,6 @@ void test_shadowbuf(vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, flo
}
}
-void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outcol)
-{
- outcol = linfac*(1.0 - exp(col*logfac));
-}
-
void shade_mist_factor(vec3 co, float miststa, float mistdist, float misttype, float misi, out float outfac)
{
float fac, zcor;
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index 30ff9769fb5..e392a05cc54 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -1124,14 +1124,12 @@ static IK_Scene* convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan)
KDL::Frame tip(iTaSC::F_identity);
Vector3 *fl = bone->bone_mat;
- KDL::Rotation brot(
- fl[0][0], fl[1][0], fl[2][0],
- fl[0][1], fl[1][1], fl[2][1],
- fl[0][2], fl[1][2], fl[2][2]);
- KDL::Vector bpos(bone->head[0], bone->head[1], bone->head[2]);
- bpos = bpos*scale;
- KDL::Frame head(brot, bpos);
-
+ KDL::Frame head(KDL::Rotation(
+ fl[0][0], fl[1][0], fl[2][0],
+ fl[0][1], fl[1][1], fl[2][1],
+ fl[0][2], fl[1][2], fl[2][2]),
+ KDL::Vector(bone->head[0], bone->head[1], bone->head[2])*scale);
+
// rest pose length of the bone taking scaling into account
length= bone->length*scale;
parent = (a > 0) ? ikscene->channels[tree->parent[a]].tail : root;
diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h
index 3b5a1865832..8a556c4b87a 100644
--- a/source/blender/makesdna/DNA_color_types.h
+++ b/source/blender/makesdna/DNA_color_types.h
@@ -51,6 +51,8 @@ typedef struct CurveMapPoint {
#define CUMA_SELECT 1
#define CUMA_VECTOR 2
+struct CurveMapPoint;
+
typedef struct CurveMap {
short totpoint, flag;
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index cdfcf465c6c..eec2c8259ef 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -47,7 +47,7 @@ typedef struct CustomDataLayer {
int active_rnd; /* number of the layer to render*/
int active_clone; /* number of the layer to render*/
int active_mask; /* number of the layer to render*/
- char pad[4];
+ int uid; /*shape keyblock unique id reference*/
char name[32]; /* layer name */
void *data; /* layer data */
} CustomDataLayer;
@@ -61,6 +61,7 @@ typedef struct CustomDataExternal {
* layers, each with a data type (e.g. MTFace, MDeformVert, etc.). */
typedef struct CustomData {
CustomDataLayer *layers; /* CustomDataLayers, ordered by type */
+ int typemap[100]; /* maps types to indices of first layer of that type */
int totlayer, maxlayer; /* number of layers, size of layers array */
int totsize, pad; /* in editmode, total size of all data layers */
void *pool; /* Bmesh: Memory pool for allocation of blocks */
@@ -75,24 +76,31 @@ typedef struct CustomData {
#define CD_MFACE 4
#define CD_MTFACE 5
#define CD_MCOL 6
-#define CD_ORIGINDEX 7
+#define CD_ORIGINDEX 7
#define CD_NORMAL 8
#define CD_FLAGS 9
#define CD_PROP_FLT 10
#define CD_PROP_INT 11
#define CD_PROP_STR 12
-#define CD_ORIGSPACE 13 /* for modifier stack face location mapping */
+#define CD_ORIGSPACE 13 /* for modifier stack face location mapping */
#define CD_ORCO 14
#define CD_MTEXPOLY 15
#define CD_MLOOPUV 16
#define CD_MLOOPCOL 17
#define CD_TANGENT 18
#define CD_MDISPS 19
-#define CD_WEIGHT_MCOL 20 /* for displaying weightpaint colors */
-#define CD_ID_MCOL 21
-#define CD_TEXTURE_MCOL 22
+#define CD_WEIGHT_MCOL 20 /* for displaying weightpaint colors */
+#define CD_MPOLY 21
+#define CD_MLOOP 22
#define CD_CLOTH_ORCO 23
-#define CD_NUMTYPES 24
+#define CD_ID_MCOL 24
+#define CD_TEXTURE_MCOL 25
+#define CD_SHAPE_KEYINDEX 26
+#define CD_SHAPEKEY 27
+#define CD_BWEIGHT 28
+#define CD_CREASE 29
+#define CD_WEIGHT_MLOOPCOL 30
+#define CD_NUMTYPES 31
/* Bits for CustomDataMask */
#define CD_MASK_MVERT (1 << CD_MVERT)
@@ -116,8 +124,18 @@ typedef struct CustomData {
#define CD_MASK_TANGENT (1 << CD_TANGENT)
#define CD_MASK_MDISPS (1 << CD_MDISPS)
#define CD_MASK_WEIGHT_MCOL (1 << CD_WEIGHT_MCOL)
+#define CD_MASK_MPOLY (1 << CD_MPOLY)
+#define CD_MASK_MLOOP (1 << CD_MLOOP)
+#define CD_MASK_WEIGHT_MLOOPCOL (1 << CD_WEIGHT_MLOOPCOL)
+#define CD_MASK_SHAPE_KEYINDEX (1 << CD_SHAPE_KEYINDEX)
+#define CD_MASK_SHAPEKEY (1 << CD_SHAPEKEY)
#define CD_MASK_CLOTH_ORCO (1 << CD_CLOTH_ORCO)
+/* derivedmesh wants CustomDataMask for weightpaint too, is not customdata though */
+#define CD_MASK_WEIGHTPAINT (1 << CD_WEIGHTPAINT)
+#define CD_MASK_BWEIGHT (1 << CD_BWEIGHT)
+#define CD_MASK_CREASE (1 << CD_CREASE)
+
/* CustomData.flag */
/* indicates layer should not be copied by CustomData_from_template or
diff --git a/source/blender/makesdna/DNA_key_types.h b/source/blender/makesdna/DNA_key_types.h
index 2d5960aa309..71b631e3d5e 100644
--- a/source/blender/makesdna/DNA_key_types.h
+++ b/source/blender/makesdna/DNA_key_types.h
@@ -45,7 +45,7 @@ typedef struct KeyBlock {
float pos;
float curval;
short type, adrcode, relative, flag; /* relative == 0 means first key is reference */
- int totelem, pad2;
+ int totelem, pad;
void *data;
float *weights;
@@ -54,6 +54,8 @@ typedef struct KeyBlock {
float slidermin;
float slidermax;
+
+ int uid, pad2;
} KeyBlock;
@@ -73,6 +75,9 @@ typedef struct Key {
short type, totkey;
short slurph, flag;
+
+ /*can never be 0, this is used for detecting old data*/
+ int uidgen, pad; /*current free uid for keyblocks*/
} Key;
/* **************** KEY ********************* */
@@ -93,6 +98,6 @@ typedef struct Key {
#define KEYBLOCK_MUTE (1<<0)
#define KEYBLOCK_SEL (1<<1)
#define KEYBLOCK_LOCKED (1<<2)
-
+#define KEYBLOCK_MISSING (1<<3) /*temporary flag*/
#endif
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index bd2a6a996b5..ec30a01c8e2 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -48,6 +48,11 @@ struct MCol;
struct MSticky;
struct Mesh;
struct OcInfo;
+struct MPoly;
+struct MTexPoly;
+struct MLoop;
+struct MLoopUV;
+struct MLoopCol;
struct Multires;
struct PartialVisibility;
struct EditMesh;
@@ -64,23 +69,35 @@ typedef struct Mesh {
struct Ipo *ipo; // XXX depreceated... old animation system
struct Key *key;
struct Material **mat;
-
- struct MFace *mface; /* array of mesh object mode faces */
- struct MTFace *mtface; /* store face UV's and texture here */
+
+ /*new face structures*/
+ struct MPoly *mpoly;
+ struct MTexPoly *mtpoly;
+ struct MLoop *mloop;
+ struct MLoopUV *mloopuv;
+ struct MLoopCol *mloopcol;
+
+ /*mface stores the tesselation (triangulation) of the mesh,
+ real faces are now stored in nface.*/
+ struct MFace *mface; /* array of mesh object mode faces for tesselation */
+ struct MTFace *mtface; /* store tesselation face UV's and texture here */
struct TFace *tface; /* depecrated, use mtface */
struct MVert *mvert; /* array of verts */
struct MEdge *medge; /* array of edges */
struct MDeformVert *dvert; /* deformgroup vertices */
- struct MCol *mcol; /* array of colors, this must be the number of faces * 4 */
+
+ /* array of colors for the tesselated faces, must be number of tesselated
+ faces * 4 in length */
+ struct MCol *mcol;
struct MSticky *msticky;
struct Mesh *texcomesh;
struct MSelect *mselect;
- struct EditMesh *edit_mesh; /* not saved in file! */
+ struct BMEditMesh *edit_btmesh; /* not saved in file! */
- struct CustomData vdata, edata, fdata;
+ struct CustomData vdata, edata, fdata, pdata, ldata;
- int totvert, totedge, totface, totselect;
+ int totvert, totedge, totface, totpoly, totloop, totselect;
/* the last selected vertex/edge/face are used for the active face however
* this means the active face must always be selected, this is to keep track
@@ -161,6 +178,8 @@ typedef struct TFace {
#define ME_DRAWEXTRA_FACEAREA (1 << 11)
#define ME_DRAWEXTRA_FACEANG (1 << 12)
+#define ME_DRAW_PINS (1 << 13)
+
/* old global flags:
#define G_DRAWEDGES (1 << 18)
#define G_DRAWFACES (1 << 7)
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index e3510b3a25a..6acbaf3cc45 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -39,6 +39,7 @@
struct Bone;
struct Image;
+/*tesselation face, see MLoop/MPoly for the real face data*/
typedef struct MFace {
unsigned int v1, v2, v3, v4;
short mat_nr;
@@ -68,13 +69,29 @@ typedef struct MVert {
char flag, bweight;
} MVert;
-/* at the moment alpha is abused for vertex painting
+/* tesselation vertex color data.
+ * at the moment alpha is abused for vertex painting
* and not used for transperency, note that red and blue are swapped */
typedef struct MCol {
char a, r, g, b;
} MCol;
-/*bmesh custom data stuff*/
+/*new face structure, replaces MFace, which is now
+ only used for storing tesselations.*/
+typedef struct MPoly {
+ /*offset into loop array and number of loops in the face*/
+ int loopstart, totloop;
+ short mat_nr;
+ short flag;
+} MPoly;
+
+/*the e here is because we want to move away from
+ relying on edge hashes.*/
+typedef struct MLoop {
+ int v; /*vertex index*/
+ int e; /*edge index*/
+} MLoop;
+
typedef struct MTexPoly{
struct Image *tpage;
char flag, transp;
@@ -83,12 +100,19 @@ typedef struct MTexPoly{
typedef struct MLoopUV{
float uv[2];
+ int flag;
}MLoopUV;
+/*mloopuv->flag*/
+#define MLOOPUV_EDGESEL 1
+#define MLOOPUV_VERTSEL 2
+#define MLOOPUV_PINNED 4
+
+/* at the moment alpha is abused for vertex painting
+ * and not used for transperency, note that red and blue are swapped */
typedef struct MLoopCol{
char a, r, g, b;
- int pad; /*waste!*/
-}MLoopCol;
+} MLoopCol;
typedef struct MSticky {
float co[2];
@@ -99,6 +123,7 @@ typedef struct MSelect {
int type;
} MSelect;
+/*tesselation uv face data*/
typedef struct MTFace {
float uv[4][2];
struct Image *tpage;
@@ -188,6 +213,7 @@ typedef struct PartialVisibility {
#define ME_SPHERETEST 2
#define ME_VERT_TMP_TAG 4
#define ME_HIDE 16
+#define ME_PIN 64
#define ME_VERT_MERGED (1<<6)
#define ME_VERT_PBVH_UPDATE (1<<7)
@@ -221,7 +247,9 @@ typedef struct PartialVisibility {
/* flag (mface) */
#define ME_SMOOTH 1
#define ME_FACE_SEL 2
- /* flag ME_HIDE==16 is used here too */
+/* flag ME_HIDE==16 is used here too */
+#define ME_DRAW_ACT 4
+
/* mselect->type */
#define ME_VSEl 0
#define ME_ESEl 1
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 8c0e065e27f..5b4fc2e554f 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -131,7 +131,7 @@ typedef struct Object {
/* materials */
struct Material **mat; /* material slots */
- char *matbits; /* 1 if material linked to object */
+ char *matbits; /* a bitfield, with each bit 1 if corrusponding material linked to object */
int totcol; /* copy of mesh or curve or meta */
int actcol; /* currently selected material in the UI */
@@ -403,6 +403,7 @@ extern Object workob;
#define OB_BOUND_POLYT 5
/* #define OB_BOUND_DYN_MESH 6 */ /*UNUSED*/
#define OB_BOUND_CAPSULE 7
+#define OB_BOUND_CAPSULE 7
/* **************** BASE ********************* */
@@ -423,7 +424,7 @@ extern Object workob;
/* an initial attempt as making selection more specific! */
-#define BA_DESELECT 0
+#define BA_DESELECT 0
#define BA_SELECT 1
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index c512b73c773..d66f612155a 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -236,6 +236,9 @@ typedef struct ThemeSpace {
char hpad[7];
char preview_back[4];
+
+ char pin[4];
+ int pin_opac;
} ThemeSpace;
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 958c9cffc84..1325272d94f 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -193,6 +193,7 @@ typedef struct wmWindow {
ListBase subwindows; /* opengl stuff for sub windows, see notes in wm_subwindow.c */
ListBase gesture; /* gesture stuff */
+ double lasttime;
} wmWindow;
/* should be somthing like DNA_EXCLUDE
diff --git a/source/blender/makesdna/intern/SConscript b/source/blender/makesdna/intern/SConscript
index e51ee53e078..23a71ae104e 100644
--- a/source/blender/makesdna/intern/SConscript
+++ b/source/blender/makesdna/intern/SConscript
@@ -18,7 +18,11 @@ dna = env.Clone()
makesdna_tool.Append(CCFLAGS = '-DBASE_HEADER="\\"source/blender/makesdna/\\"" ')
makesdna_tool.Append (CPPPATH = ['#/intern/guardedalloc',
+<<<<<<< .working
+ '../../makesdna', '../', '../../bmesh'])
+=======
'../../makesdna', '../../blenloader'])
+>>>>>>> .merge-right.r35190
if env['OURPLATFORM'] == 'linuxcross':
USE_WINE = True # when cross compiling on linux 64bit this is useful
@@ -49,6 +53,7 @@ targetdir = normpath(root_build_dir + '/makesdna')
if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
targetdir = '#' + targetdir
+ #root_build_dir = "#"
makesdna = makesdna_tool.Program (target = targetdir, source = source_files, LIBS=['bf_intern_guardedalloc', 'bf_blenlib'])
@@ -56,16 +61,28 @@ dna_dict = dna.Dictionary()
dna.Depends ('dna.c', makesdna)
dna.Depends ('dna.c', header_files)
+ap = os.path.abspath
+
if env['OURPLATFORM'] != 'linuxcross':
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw'):
dna.Command ('dna.c', '', "\"" + root_build_dir+os.sep+"makesdna\" $TARGET")
else:
dna.Command ('dna.c', '', "\"" + root_build_dir+os.sep+"makesdna\" $TARGET")
else:
+<<<<<<< .working
+ if USE_WINE:
+ dna.Command ('dna.c', '', 'wine ' + ap(root_build_dir+os.sep+"makesdna $TARGET"))
+ else:
+ if env['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw'):
+ dna.Command ('dna.c', '', "\"" + root_build_dir+os.sep+"makesdna\" $TARGET")
+ else:
+ dna.Command ('dna.c', '', root_build_dir+os.sep+"makesdna $TARGET")
+=======
if USE_WINE:
dna.Command ('dna.c', '', 'wine ' + root_build_dir+os.sep+"makesdna $TARGET")
else:
dna.Command ('dna.c', '', root_build_dir+os.sep+"makesdna.exe $TARGET")
+>>>>>>> .merge-right.r35190
obj = ['intern/dna.c', 'intern/dna_genfile.c']
Return ('obj')
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 50083a3472c..711d7a08687 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -983,6 +983,8 @@ int make_structDNA(char *baseDirectory, FILE *file)
dna_write(file, str, 4);
len= nr_names;
dna_write(file, &len, 4);
+ printf("LEEEN %d\n", len);
+
/* calculate size of datablock with strings */
cp= names[nr_names-1];
diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript
index c116659e4d8..7f41fb758dd 100644
--- a/source/blender/makesrna/SConscript
+++ b/source/blender/makesrna/SConscript
@@ -8,7 +8,7 @@ objs += o
incs = '#/intern/guardedalloc #/intern/memutil #/intern/audaspace/intern ../blenkernel ../blenlib ../makesdna intern .'
incs += ' ../windowmanager ../editors/include ../gpu ../imbuf ../ikplugin ../blenfont ../blenloader'
-incs += ' ../render/extern/include'
+incs += ' ../render/extern/include ../bmesh'
defs = []
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index cc8b3f20c9b..0b54d181a78 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -132,6 +132,7 @@ blender_include_dirs(
../../blenkernel
../../blenloader
../../blenlib
+ ../../bmesh
../../blenfont
../../gpu
../../imbuf
diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript
index cacbaccfc0e..2abed91ec02 100644
--- a/source/blender/makesrna/intern/SConscript
+++ b/source/blender/makesrna/intern/SConscript
@@ -32,7 +32,7 @@ defs = []
incs = '#/intern/guardedalloc ../../blenlib ../../blenkernel ../../blenloader'
incs += ' ../../imbuf ../../makesdna ../../makesrna ../../ikplugin'
incs += ' ../../windowmanager ../../editors/include ../../blenfont'
-incs += ' ../../render/extern/include'
+incs += ' ../../render/extern/include ../../bmesh'
incs += ' #/intern/audaspace/intern '
if env['WITH_BF_OPENEXR']:
@@ -147,7 +147,11 @@ rna.Depends (generated_files, makesrna)
# this seems bad, how to retrieve it from scons?
build_dir = root_build_dir + os.sep +'source' + os.sep + 'blender' + os.sep + 'makesrna' + os.sep + 'intern' + os.sep
+<<<<<<< .working
+
+=======
+>>>>>>> .merge-right.r35190
if env['OURPLATFORM'] != 'linuxcross':
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw'):
rna.Command (generated_files, '', "\"" + root_build_dir+os.sep+"makesrna.exe\" \"" + build_dir )
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 2b4acabb7b6..247b87d7bc4 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -1583,6 +1583,7 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
fprintf(f, "\t_retdata= _data;\n");
else {
const char *data_str;
+
if (cptr || (flag & PROP_DYNAMIC)) {
ptrstr= "**";
valstr= "*";
diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c
index 4498cc6ec86..91a5659f9aa 100644
--- a/source/blender/makesrna/intern/rna_animviz.c
+++ b/source/blender/makesrna/intern/rna_animviz.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: rna_animviz.c 25824 2010-01-08 02:54:33Z gsrb3d $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 3d516440731..9570d817726 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -2038,7 +2038,7 @@ void RNA_def_constraint(BlenderRNA *brna)
/* flags */
prop= RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_OFF);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CONSTRAINT_OFF);
RNA_def_property_ui_text(prop, "Disable", "Enable/Disable Constraint");
prop= RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index a4dee9eb345..72f74f5a3e9 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -44,7 +44,7 @@
#include "ED_keyframing.h"
#include "ED_keyframes_edit.h"
-
+
EnumPropertyItem fmodifier_type_items[] = {
{FMODIFIER_TYPE_NULL, "NULL", 0, "Invalid", ""},
{FMODIFIER_TYPE_GENERATOR, "GENERATOR", 0, "Generator", ""},
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 8431b223d30..c858c25afe1 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: rna_image_api.c 23507 2009-09-27 09:19:29Z kazanbas $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 259fa1cd782..9b3f4209edd 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: rna_main_api.c 21094 2009-06-23 00:09:26Z gsrb3d $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index e0bf025f9dc..f667f72906b 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -1,4 +1,4 @@
-/*
+/**
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
@@ -10,7 +10,7 @@
*
* 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
+ * 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
@@ -22,9 +22,14 @@
* ***** END GPL LICENSE BLOCK *****
*/
+/*note: the original vertex color stuff is now just used for
+ getting info on the layers themselves, accessing the data is
+ done through the (not yet written) mpoly interfaces.*/
+
#include <stdlib.h>
#include "RNA_define.h"
+#include "RNA_types.h"
#include "rna_internal.h"
@@ -33,8 +38,6 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
-#include "WM_types.h"
-
#ifdef RNA_RUNTIME
#include "DNA_scene_types.h"
@@ -46,9 +49,8 @@
#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
-
-
-#include "ED_mesh.h" /* XXX Bad level call */
+#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -59,7 +61,7 @@ static void rna_Mesh_update_data(Main *bmain, Scene *scene, PointerRNA *ptr)
/* cheating way for importers to avoid slow updates */
if(id->us > 0) {
- DAG_id_tag_update(id, 0);
+ DAG_id_tag_update(id, OB_RECALC_DATA);
WM_main_add_notifier(NC_GEOM|ND_DATA, id);
}
}
@@ -229,55 +231,12 @@ static void rna_MeshColor_color4_set(PointerRNA *ptr, const float *values)
(&mcol[3].r)[0]= (char)(CLAMPIS(values[2]*255.0f, 0, 255));
}
-static void rna_Mesh_texspace_set(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- Mesh *me= (Mesh*)ptr->data;
-
- if (me->texflag & AUTOSPACE)
- tex_space_mesh(me);
-}
-
-
static int rna_Mesh_texspace_editable(PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->data;
return (me->texflag & AUTOSPACE)? 0: PROP_EDITABLE;
}
-static void rna_Mesh_texspace_loc_get(PointerRNA *ptr, float *values)
-{
- Mesh *me= (Mesh *)ptr->data;
-
- if (!me->bb)
- tex_space_mesh(me);
-
- copy_v3_v3(values, me->loc);
-}
-
-static void rna_Mesh_texspace_loc_set(PointerRNA *ptr, const float *values)
-{
- Mesh *me= (Mesh *)ptr->data;
-
- copy_v3_v3(me->loc, values);
-}
-
-static void rna_Mesh_texspace_size_get(PointerRNA *ptr, float *values)
-{
- Mesh *me= (Mesh *)ptr->data;
-
- if (!me->bb)
- tex_space_mesh(me);
-
- copy_v3_v3(values, me->size);
-}
-
-static void rna_Mesh_texspace_size_set(PointerRNA *ptr, const float *values)
-{
- Mesh *me= (Mesh *)ptr->data;
-
- copy_v3_v3(me->size, values);
-}
-
static void rna_MeshVertex_groups_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->id.data;
@@ -299,15 +258,20 @@ static void rna_MeshFace_material_index_range(PointerRNA *ptr, int *min, int *ma
*max= me->totcol-1;
}
-static CustomData *rna_mesh_fdata(Mesh *me)
+static CustomData *rna_mesh_pdata(Mesh *me)
{
- return (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata;
+ return (me->edit_btmesh)? &me->edit_btmesh->bm->pdata: &me->pdata;
+}
+
+static CustomData *rna_mesh_ldata(Mesh *me)
+{
+ return (me->edit_btmesh)? &me->edit_btmesh->bm->ldata: &me->ldata;
}
static int rna_CustomDataLayer_length(PointerRNA *ptr, int type)
{
Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
CustomDataLayer *layer;
int i, length= 0;
@@ -321,7 +285,7 @@ static int rna_CustomDataLayer_length(PointerRNA *ptr, int type)
static int rna_CustomDataLayer_active_get(PointerRNA *ptr, int type, int render)
{
Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
int n= ((CustomDataLayer*)ptr->data) - fdata->layers;
if(render) return (n == CustomData_get_render_layer_index(fdata, type));
@@ -331,7 +295,7 @@ static int rna_CustomDataLayer_active_get(PointerRNA *ptr, int type, int render)
static int rna_CustomDataLayer_clone_get(PointerRNA *ptr, int type, int render)
{
Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
int n= ((CustomDataLayer*)ptr->data) - fdata->layers;
return (n == CustomData_get_clone_layer_index(fdata, type));
@@ -340,7 +304,7 @@ static int rna_CustomDataLayer_clone_get(PointerRNA *ptr, int type, int render)
static void rna_CustomDataLayer_active_set(PointerRNA *ptr, int value, int type, int render)
{
Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
int n= ((CustomDataLayer*)ptr->data) - fdata->layers;
if(value == 0)
@@ -353,7 +317,7 @@ static void rna_CustomDataLayer_active_set(PointerRNA *ptr, int value, int type,
static void rna_CustomDataLayer_clone_set(PointerRNA *ptr, int value, int type, int render)
{
Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
int n= ((CustomDataLayer*)ptr->data) - fdata->layers;
if(value == 0)
@@ -365,26 +329,26 @@ static void rna_CustomDataLayer_clone_set(PointerRNA *ptr, int value, int type,
static int rna_uv_texture_check(CollectionPropertyIterator *iter, void *data)
{
CustomDataLayer *layer= (CustomDataLayer*)data;
- return (layer->type != CD_MTFACE);
+ return (layer->type != CD_MTEXPOLY);
}
static void rna_Mesh_uv_textures_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
rna_iterator_array_begin(iter, (void*)fdata->layers, sizeof(CustomDataLayer), fdata->totlayer, 0, rna_uv_texture_check);
}
static int rna_Mesh_uv_textures_length(PointerRNA *ptr)
{
- return rna_CustomDataLayer_length(ptr, CD_MTFACE);
+ return rna_CustomDataLayer_length(ptr, CD_MTEXPOLY);
}
static PointerRNA rna_Mesh_active_uv_texture_get(PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
- int index= CustomData_get_active_layer_index(fdata, CD_MTFACE);
+ CustomData *fdata= rna_mesh_pdata(me);
+ int index= CustomData_get_active_layer_index(fdata, CD_MTEXPOLY);
CustomDataLayer *cdl= (index == -1)? NULL: &fdata->layers[index];
return rna_pointer_inherit_refine(ptr, &RNA_MeshTextureFaceLayer, cdl);
@@ -392,34 +356,42 @@ static PointerRNA rna_Mesh_active_uv_texture_get(PointerRNA *ptr)
static PointerRNA rna_Mesh_uv_texture_clone_get(PointerRNA *ptr)
{
+ PointerRNA pnull = {0,};
+#if 0
Mesh *me= (Mesh*)ptr->data;
CustomData *fdata= rna_mesh_fdata(me);
int index= CustomData_get_clone_layer_index(fdata, CD_MTFACE);
CustomDataLayer *cdl= (index == -1)? NULL: &fdata->layers[index];
return rna_pointer_inherit_refine(ptr, &RNA_MeshTextureFaceLayer, cdl);
+#endif
+ return pnull;
}
static PointerRNA rna_Mesh_uv_texture_stencil_get(PointerRNA *ptr)
{
+ PointerRNA pnull = {0,};
+#if 0
Mesh *me= (Mesh*)ptr->data;
CustomData *fdata= rna_mesh_fdata(me);
int index= CustomData_get_stencil_layer_index(fdata, CD_MTFACE);
CustomDataLayer *cdl= (index == -1)? NULL: &fdata->layers[index];
return rna_pointer_inherit_refine(ptr, &RNA_MeshTextureFaceLayer, cdl);
+#endif
+ return pnull;
}
static void rna_Mesh_active_uv_texture_set(PointerRNA *ptr, PointerRNA value)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
CustomDataLayer *cdl;
int a;
for(cdl=fdata->layers, a=0; a<fdata->totlayer; cdl++, a++) {
if(value.data == cdl) {
- CustomData_set_layer_active_index(fdata, CD_MTFACE, a);
+ CustomData_set_layer_active_index(fdata, CD_MTEXPOLY, a);
mesh_update_customdata_pointers(me);
return;
}
@@ -428,6 +400,7 @@ static void rna_Mesh_active_uv_texture_set(PointerRNA *ptr, PointerRNA value)
static void rna_Mesh_uv_texture_clone_set(PointerRNA *ptr, PointerRNA value)
{
+#if 0
Mesh *me= (Mesh*)ptr->data;
CustomData *fdata= rna_mesh_fdata(me);
CustomDataLayer *cdl;
@@ -439,10 +412,13 @@ static void rna_Mesh_uv_texture_clone_set(PointerRNA *ptr, PointerRNA value)
return;
}
}
+#endif
+ return;
}
static void rna_Mesh_uv_texture_stencil_set(PointerRNA *ptr, PointerRNA value)
{
+#if 0
Mesh *me= (Mesh*)ptr->data;
CustomData *fdata= rna_mesh_fdata(me);
CustomDataLayer *cdl;
@@ -454,146 +430,85 @@ static void rna_Mesh_uv_texture_stencil_set(PointerRNA *ptr, PointerRNA value)
return;
}
}
+#endif
+ return;
}
static int rna_Mesh_active_uv_texture_index_get(PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
- return CustomData_get_active_layer(fdata, CD_MTFACE);
+ CustomData *fdata= rna_mesh_pdata(me);
+ return CustomData_get_active_layer(fdata, CD_MTEXPOLY);
}
static int rna_Mesh_uv_texture_clone_index_get(PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
- return CustomData_get_clone_layer(fdata, CD_MTFACE);
+ CustomData *fdata= rna_mesh_pdata(me);
+ return CustomData_get_clone_layer(fdata, CD_MTEXPOLY);
}
static int rna_Mesh_uv_texture_stencil_index_get(PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
- return CustomData_get_stencil_layer(fdata, CD_MTFACE);
+ CustomData *fdata= rna_mesh_pdata(me);
+ return CustomData_get_stencil_layer(fdata, CD_MTEXPOLY);
}
static void rna_Mesh_active_uv_texture_index_set(PointerRNA *ptr, int value)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
- CustomData_set_layer_active(fdata, CD_MTFACE, value);
+ CustomData_set_layer_active(fdata, CD_MTEXPOLY, value);
mesh_update_customdata_pointers(me);
}
static void rna_Mesh_uv_texture_clone_index_set(PointerRNA *ptr, int value)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
- CustomData_set_layer_clone(fdata, CD_MTFACE, value);
+ CustomData_set_layer_clone(fdata, CD_MTEXPOLY, value);
}
static void rna_Mesh_uv_texture_stencil_index_set(PointerRNA *ptr, int value)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
- CustomData_set_layer_stencil(fdata, CD_MTFACE, value);
+ CustomData_set_layer_stencil(fdata, CD_MTEXPOLY, value);
}
static void rna_Mesh_active_uv_texture_index_range(PointerRNA *ptr, int *min, int *max)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *pdata= rna_mesh_pdata(me);
*min= 0;
- *max= CustomData_number_of_layers(fdata, CD_MTFACE)-1;
+ *max= CustomData_number_of_layers(pdata, CD_MTEXPOLY)-1;
*max= MAX2(0, *max);
}
-static PointerRNA rna_Mesh_active_mtface_get(PointerRNA *ptr)
-{
- Mesh *me= (Mesh*)ptr->data;
- EditMesh *em= BKE_mesh_get_editmesh(me);
- MTFace *tf;
-
- if (em && EM_texFaceCheck(em))
- {
- tf = EM_get_active_mtface(em, NULL, NULL, 1);
-
- return rna_pointer_inherit_refine(ptr, &RNA_MeshTextureFace, tf);
- }
-
- return rna_pointer_inherit_refine(ptr, &RNA_MeshTextureFace, NULL);
-}
-
static void rna_MeshTextureFace_uv1_get(PointerRNA *ptr, float *values)
{
- MTFace *mtface= (MTFace*)ptr->data;
+ MLoopUV *mloopuv= (MLoopUV*)ptr->data;
- values[0]= mtface->uv[0][0];
- values[1]= mtface->uv[0][1];
+ values[0]= mloopuv->uv[0];
+ values[1]= mloopuv->uv[1];
}
static void rna_MeshTextureFace_uv1_set(PointerRNA *ptr, const float *values)
{
- MTFace *mtface= (MTFace*)ptr->data;
-
- mtface->uv[0][0]= values[0];
- mtface->uv[0][1]= values[1];
-}
-
-static void rna_MeshTextureFace_uv2_get(PointerRNA *ptr, float *values)
-{
- MTFace *mtface= (MTFace*)ptr->data;
-
- values[0]= mtface->uv[1][0];
- values[1]= mtface->uv[1][1];
-}
-
-static void rna_MeshTextureFace_uv2_set(PointerRNA *ptr, const float *values)
-{
- MTFace *mtface= (MTFace*)ptr->data;
-
- mtface->uv[1][0]= values[0];
- mtface->uv[1][1]= values[1];
-}
-
-static void rna_MeshTextureFace_uv3_get(PointerRNA *ptr, float *values)
-{
- MTFace *mtface= (MTFace*)ptr->data;
-
- values[0]= mtface->uv[2][0];
- values[1]= mtface->uv[2][1];
-}
-
-static void rna_MeshTextureFace_uv3_set(PointerRNA *ptr, const float *values)
-{
- MTFace *mtface= (MTFace*)ptr->data;
-
- mtface->uv[2][0]= values[0];
- mtface->uv[2][1]= values[1];
-}
-
-static void rna_MeshTextureFace_uv4_get(PointerRNA *ptr, float *values)
-{
- MTFace *mtface= (MTFace*)ptr->data;
-
- values[0]= mtface->uv[3][0];
- values[1]= mtface->uv[3][1];
-}
-
-static void rna_MeshTextureFace_uv4_set(PointerRNA *ptr, const float *values)
-{
- MTFace *mtface= (MTFace*)ptr->data;
-
- mtface->uv[3][0]= values[0];
- mtface->uv[3][1]= values[1];
+ MLoopUV *mloopuv= (MLoopUV*)ptr->data;
+
+ mloopuv->uv[0] = values[0];
+ mloopuv->uv[1] = values[1];
}
static int rna_CustomDataData_numverts(PointerRNA *ptr, int type)
{
+ /*BMESH_TODO
Mesh *me= (Mesh*)ptr->id.data;
CustomData *fdata= rna_mesh_fdata(me);
CustomDataLayer *cdl;
@@ -607,53 +522,53 @@ static int rna_CustomDataData_numverts(PointerRNA *ptr, int type)
}
}
+ return 0;*/
return 0;
}
static int rna_MeshTextureFace_uv_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
{
- length[0]= rna_CustomDataData_numverts(ptr, CD_MTFACE);
- length[1]= 2;
- return length[0]*length[1];
+ //return rna_CustomDataData_numverts(ptr, CD_MTFACE) * 2;
+ return 0; //BMESH_TODO
}
static void rna_MeshTextureFace_uv_get(PointerRNA *ptr, float *values)
{
- MTFace *mtface= (MTFace*)ptr->data;
- int totvert= rna_CustomDataData_numverts(ptr, CD_MTFACE);
+ //MTFace *mtface= (MTFace*)ptr->data;
+ //int totvert= rna_CustomDataData_numverts(ptr, CD_MTFACE);
- memcpy(values, mtface->uv, totvert * 2 * sizeof(float));
+ //memcpy(values, mtface->uv, totvert * 2 * sizeof(float));
}
static void rna_MeshTextureFace_uv_set(PointerRNA *ptr, const float *values)
{
- MTFace *mtface= (MTFace*)ptr->data;
- int totvert= rna_CustomDataData_numverts(ptr, CD_MTFACE);
+ //MTFace *mtface= (MTFace*)ptr->data;
+ //int totvert= rna_CustomDataData_numverts(ptr, CD_MTFACE);
- memcpy(mtface->uv, values, totvert * 2 * sizeof(float));
+ //memcpy(mtface->uv, values, totvert * 2 * sizeof(float));
}
static void rna_MeshTextureFaceLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->id.data;
CustomDataLayer *layer= (CustomDataLayer*)ptr->data;
- rna_iterator_array_begin(iter, layer->data, sizeof(MTFace), (me->edit_mesh)? 0: me->totface, 0, NULL);
+ rna_iterator_array_begin(iter, layer->data, sizeof(MTexPoly), me->totpoly, 0, NULL);
}
static int rna_MeshTextureFaceLayer_data_length(PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->id.data;
- return (me->edit_mesh)? 0: me->totface;
+ return me->totpoly;
}
static int rna_MeshTextureFaceLayer_active_render_get(PointerRNA *ptr)
{
- return rna_CustomDataLayer_active_get(ptr, CD_MTFACE, 1);
+ return rna_CustomDataLayer_active_get(ptr, CD_MTEXPOLY, 1);
}
static int rna_MeshTextureFaceLayer_active_get(PointerRNA *ptr)
{
- return rna_CustomDataLayer_active_get(ptr, CD_MTFACE, 0);
+ return rna_CustomDataLayer_active_get(ptr, CD_MTEXPOLY, 0);
}
static int rna_MeshTextureFaceLayer_clone_get(PointerRNA *ptr)
@@ -663,12 +578,12 @@ static int rna_MeshTextureFaceLayer_clone_get(PointerRNA *ptr)
static void rna_MeshTextureFaceLayer_active_render_set(PointerRNA *ptr, int value)
{
- rna_CustomDataLayer_active_set(ptr, value, CD_MTFACE, 1);
+ rna_CustomDataLayer_active_set(ptr, value, CD_MTEXPOLY, 1);
}
static void rna_MeshTextureFaceLayer_active_set(PointerRNA *ptr, int value)
{
- rna_CustomDataLayer_active_set(ptr, value, CD_MTFACE, 0);
+ rna_CustomDataLayer_active_set(ptr, value, CD_MTEXPOLY, 0);
}
static void rna_MeshTextureFaceLayer_clone_set(PointerRNA *ptr, int value)
@@ -679,36 +594,36 @@ static void rna_MeshTextureFaceLayer_clone_set(PointerRNA *ptr, int value)
static void rna_MeshTextureFaceLayer_name_set(PointerRNA *ptr, const char *value)
{
Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
CustomDataLayer *cdl= (CustomDataLayer*)ptr->data;
BLI_strncpy(cdl->name, value, sizeof(cdl->name));
- CustomData_set_layer_unique_name(fdata, cdl - fdata->layers);
+ CustomData_set_layer_unique_name(&me->pdata, cdl - rna_mesh_pdata(me)->layers);
}
static int rna_vertex_color_check(CollectionPropertyIterator *iter, void *data)
{
CustomDataLayer *layer= (CustomDataLayer*)data;
- return (layer->type != CD_MCOL);
+ return (layer->type != CD_MLOOPCOL);
}
static void rna_Mesh_vertex_colors_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
- rna_iterator_array_begin(iter, (void*)fdata->layers, sizeof(CustomDataLayer), fdata->totlayer, 0, rna_vertex_color_check);
+ CustomData *ldata= rna_mesh_ldata(me);
+ rna_iterator_array_begin(iter, (void*)ldata->layers, sizeof(CustomDataLayer), ldata->totlayer, 0, rna_vertex_color_check);
}
static int rna_Mesh_vertex_colors_length(PointerRNA *ptr)
{
- return rna_CustomDataLayer_length(ptr, CD_MCOL);
+ return rna_CustomDataLayer_length(ptr, CD_MLOOPCOL);
}
static PointerRNA rna_Mesh_active_vertex_color_get(PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
- int index= CustomData_get_active_layer_index(fdata, CD_MCOL);
- CustomDataLayer *cdl= (index == -1)? NULL: &fdata->layers[index];
+ CustomData *ldata= rna_mesh_ldata(me);
+ int index= CustomData_get_active_layer_index(ldata, CD_MLOOPCOL);
+ CustomDataLayer *cdl= (index == -1)? NULL: &ldata->layers[index];
return rna_pointer_inherit_refine(ptr, &RNA_MeshColorLayer, cdl);
}
@@ -716,42 +631,47 @@ static PointerRNA rna_Mesh_active_vertex_color_get(PointerRNA *ptr)
static void rna_Mesh_active_vertex_color_set(PointerRNA *ptr, PointerRNA value)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *ldata= rna_mesh_ldata(me), *fdata;
CustomDataLayer *cdl;
- int a;
+ int a, b, c;
+
+ b = 0;
+ for(cdl=ldata->layers, a=0; a<ldata->totlayer; cdl++, a++) {
+ if (cdl->type == CD_MLOOPCOL)
+ b++;
- for(cdl=fdata->layers, a=0; a<fdata->totlayer; cdl++, a++) {
if(value.data == cdl) {
- CustomData_set_layer_active_index(fdata, CD_MCOL, a);
- mesh_update_customdata_pointers(me);
- return;
+ CustomData_set_layer_active_index(ldata, CD_MLOOPCOL, a);
+ break;
}
}
+
+ mesh_update_customdata_pointers(me);
}
static int rna_Mesh_active_vertex_color_index_get(PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
- return CustomData_get_active_layer(fdata, CD_MCOL);
+ CustomData *ldata= rna_mesh_ldata(me);
+ return CustomData_get_active_layer(ldata, CD_MLOOPCOL);
}
static void rna_Mesh_active_vertex_color_index_set(PointerRNA *ptr, int value)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *ldata= rna_mesh_ldata(me);
- CustomData_set_layer_active(fdata, CD_MCOL, value);
+ CustomData_set_layer_active(ldata, CD_MLOOPCOL, value);
mesh_update_customdata_pointers(me);
}
static void rna_Mesh_active_vertex_color_index_range(PointerRNA *ptr, int *min, int *max)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *ldata= rna_mesh_ldata(me);
*min= 0;
- *max= CustomData_number_of_layers(fdata, CD_MCOL)-1;
+ *max= CustomData_number_of_layers(ldata, CD_MLOOPCOL)-1;
*max= MAX2(0, *max);
}
@@ -759,55 +679,55 @@ static void rna_MeshColorLayer_data_begin(CollectionPropertyIterator *iter, Poin
{
Mesh *me= (Mesh*)ptr->id.data;
CustomDataLayer *layer= (CustomDataLayer*)ptr->data;
- rna_iterator_array_begin(iter, layer->data, sizeof(MCol)*4, (me->edit_mesh)? 0: me->totface, 0, NULL);
+ rna_iterator_array_begin(iter, layer->data, sizeof(CD_MLOOPCOL), me->totloop, 0, NULL);
}
static int rna_MeshColorLayer_data_length(PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->id.data;
- return (me->edit_mesh)? 0: me->totface;
+ return me->totloop;
}
static int rna_MeshColorLayer_active_render_get(PointerRNA *ptr)
{
- return rna_CustomDataLayer_active_get(ptr, CD_MCOL, 1);
+ return rna_CustomDataLayer_active_get(ptr, CD_MLOOPCOL, 1);
}
static int rna_MeshColorLayer_active_get(PointerRNA *ptr)
{
- return rna_CustomDataLayer_active_get(ptr, CD_MCOL, 0);
+ return rna_CustomDataLayer_active_get(ptr, CD_MLOOPCOL, 0);
}
static void rna_MeshColorLayer_active_render_set(PointerRNA *ptr, int value)
{
- rna_CustomDataLayer_active_set(ptr, value, CD_MCOL, 1);
+ rna_CustomDataLayer_active_set(ptr, value, CD_MLOOPCOL, 1);
}
static void rna_MeshColorLayer_active_set(PointerRNA *ptr, int value)
{
- rna_CustomDataLayer_active_set(ptr, value, CD_MCOL, 0);
+ rna_CustomDataLayer_active_set(ptr, value, CD_MLOOPCOL, 0);
}
static void rna_MeshColorLayer_name_set(PointerRNA *ptr, const char *value)
{
Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
CustomDataLayer *cdl= (CustomDataLayer*)ptr->data;
BLI_strncpy(cdl->name, value, sizeof(cdl->name));
- CustomData_set_layer_unique_name(fdata, cdl - fdata->layers);
+ CustomData_set_layer_unique_name(&me->ldata, cdl - rna_mesh_pdata(me)->layers);
}
static void rna_MeshFloatPropertyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->id.data;
CustomDataLayer *layer= (CustomDataLayer*)ptr->data;
- rna_iterator_array_begin(iter, layer->data, sizeof(MFloatProperty), (me->edit_mesh)? 0: me->totface, 0, NULL);
+ rna_iterator_array_begin(iter, layer->data, sizeof(MFloatProperty), me->totface, 0, NULL);
}
static int rna_MeshFloatPropertyLayer_data_length(PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->id.data;
- return (me->edit_mesh)? 0: me->totface;
+ return me->totface;
}
static int rna_float_layer_check(CollectionPropertyIterator *iter, void *data)
@@ -819,7 +739,7 @@ static int rna_float_layer_check(CollectionPropertyIterator *iter, void *data)
static void rna_Mesh_float_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
rna_iterator_array_begin(iter, (void*)fdata->layers, sizeof(CustomDataLayer), fdata->totlayer, 0, rna_float_layer_check);
}
@@ -838,19 +758,19 @@ static void rna_MeshIntPropertyLayer_data_begin(CollectionPropertyIterator *iter
{
Mesh *me= (Mesh*)ptr->id.data;
CustomDataLayer *layer= (CustomDataLayer*)ptr->data;
- rna_iterator_array_begin(iter, layer->data, sizeof(MIntProperty), (me->edit_mesh)? 0: me->totface, 0, NULL);
+ rna_iterator_array_begin(iter, layer->data, sizeof(MIntProperty), me->totface, 0, NULL);
}
static int rna_MeshIntPropertyLayer_data_length(PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->id.data;
- return (me->edit_mesh)? 0: me->totface;
+ return me->totface;
}
static void rna_Mesh_int_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
rna_iterator_array_begin(iter, (void*)fdata->layers, sizeof(CustomDataLayer), fdata->totlayer, 0, rna_int_layer_check);
}
@@ -869,19 +789,19 @@ static void rna_MeshStringPropertyLayer_data_begin(CollectionPropertyIterator *i
{
Mesh *me= (Mesh*)ptr->id.data;
CustomDataLayer *layer= (CustomDataLayer*)ptr->data;
- rna_iterator_array_begin(iter, layer->data, sizeof(MStringProperty), (me->edit_mesh)? 0: me->totface, 0, NULL);
+ rna_iterator_array_begin(iter, layer->data, sizeof(MStringProperty), me->totface, 0, NULL);
}
static int rna_MeshStringPropertyLayer_data_length(PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->id.data;
- return (me->edit_mesh)? 0: me->totface;
+ return me->totface;
}
static void rna_Mesh_string_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
rna_iterator_array_begin(iter, (void*)fdata->layers, sizeof(CustomDataLayer), fdata->totlayer, 0, rna_string_layer_check);
}
@@ -892,7 +812,7 @@ static int rna_Mesh_string_layers_length(PointerRNA *ptr)
static void rna_TextureFace_image_set(PointerRNA *ptr, PointerRNA value)
{
- MTFace *tf= (MTFace*)ptr->data;
+ MTexPoly *tf= (MTexPoly*)ptr->data;
ID *id= value.data;
if(id) {
@@ -961,46 +881,27 @@ static char *rna_VertexGroupElement_path(PointerRNA *ptr)
MDeformVert *dvert;
int a, b;
- /* sanity check: make sure that mesh pointer is valid */
- if (me == NULL)
- return NULL;
- else if (GS(me->id.name) != ID_ME) {
- /* if object pointer, try to resolve the object's data to mesh pointer */
- if (GS(me->id.name) == ID_OB) {
- Object *ob = (Object *)me;
-
- if (ob->type == OB_MESH)
- me = (Mesh *)ob->data;
- else
- return NULL; /* nothing can be done */
- }
- else
- return NULL; /* nothing can be done */
- }
-
- for(a=0, dvert=me->dvert; a<me->totvert; a++, dvert++) {
- for(b=0; b<dvert->totweight; b++) {
+ for(a=0, dvert=me->dvert; a<me->totvert; a++, dvert++)
+ for(b=0; b<dvert->totweight; b++)
if(dw == &dvert->dw[b])
- return BLI_sprintfN("vertices[%d].groups[%d]", a, b);
- }
- }
+ return BLI_sprintfN("verts[%d].groups[%d]", a, b);
return NULL;
}
static char *rna_MeshFace_path(PointerRNA *ptr)
{
- return BLI_sprintfN("faces[%d]", (int)((MFace*)ptr->data - ((Mesh*)ptr->id.data)->mface));
+ return BLI_sprintfN("faces[%d]", (MFace*)ptr->data - ((Mesh*)ptr->id.data)->mface);
}
static char *rna_MeshEdge_path(PointerRNA *ptr)
{
- return BLI_sprintfN("edges[%d]", (int)((MEdge*)ptr->data - ((Mesh*)ptr->id.data)->medge));
+ return BLI_sprintfN("edges[%d]", (MEdge*)ptr->data - ((Mesh*)ptr->id.data)->medge);
}
static char *rna_MeshVertex_path(PointerRNA *ptr)
{
- return BLI_sprintfN("vertices[%d]", (int)((MVert*)ptr->data - ((Mesh*)ptr->id.data)->mvert));
+ return BLI_sprintfN("verts[%d]", (MVert*)ptr->data - ((Mesh*)ptr->id.data)->mvert);
}
static char *rna_MeshTextureFaceLayer_path(PointerRNA *ptr)
@@ -1011,7 +912,7 @@ static char *rna_MeshTextureFaceLayer_path(PointerRNA *ptr)
static char *rna_CustomDataData_path(PointerRNA *ptr, char *collection, int type)
{
Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *fdata= rna_mesh_pdata(me);
CustomDataLayer *cdl;
int a, b;
@@ -1028,7 +929,7 @@ static char *rna_CustomDataData_path(PointerRNA *ptr, char *collection, int type
static char *rna_MeshTextureFace_path(PointerRNA *ptr)
{
- return rna_CustomDataData_path(ptr, "uv_textures", CD_MTFACE);
+ return rna_CustomDataData_path(ptr, "uv_textures", CD_MTEXPOLY);
}
static char *rna_MeshColorLayer_path(PointerRNA *ptr)
@@ -1038,12 +939,12 @@ static char *rna_MeshColorLayer_path(PointerRNA *ptr)
static char *rna_MeshColor_path(PointerRNA *ptr)
{
- return rna_CustomDataData_path(ptr, "vertex_colors", CD_MCOL);
+ return rna_CustomDataData_path(ptr, "vertex_colors", CD_MLOOPCOL);
}
static char *rna_MeshSticky_path(PointerRNA *ptr)
{
- return BLI_sprintfN("sticky[%d]", (int)((MSticky*)ptr->data - ((Mesh*)ptr->id.data)->msticky));
+ return BLI_sprintfN("sticky[%d]", (MSticky*)ptr->data - ((Mesh*)ptr->id.data)->msticky);
}
static char *rna_MeshIntPropertyLayer_path(PointerRNA *ptr)
@@ -1079,43 +980,43 @@ static char *rna_MeshStringProperty_path(PointerRNA *ptr)
static int rna_Mesh_tot_vert_get(PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->id.data;
- return me->edit_mesh ? me->edit_mesh->totvertsel : 0;
+ return me->edit_btmesh ? me->edit_btmesh->bm->totvertsel : 0;
}
static int rna_Mesh_tot_edge_get(PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->id.data;
- return me->edit_mesh ? me->edit_mesh->totedgesel: 0;
+ return me->edit_btmesh ? me->edit_btmesh->bm->totedgesel: 0;
}
static int rna_Mesh_tot_face_get(PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->id.data;
- return me->edit_mesh ? me->edit_mesh->totfacesel : 0;
+ return me->edit_btmesh ? me->edit_btmesh->bm->totfacesel : 0;
}
static CustomDataLayer *rna_Mesh_vertex_color_new(struct Mesh *me, struct bContext *C, const char *name)
{
- CustomData *fdata;
+ CustomData *ldata;
CustomDataLayer *cdl= NULL;
int index;
if(ED_mesh_color_add(C, NULL, NULL, me, name, FALSE)) {
- fdata= rna_mesh_fdata(me);
- index= CustomData_get_named_layer_index(fdata, CD_MCOL, name);
- cdl= (index == -1)? NULL: &fdata->layers[index];
+ ldata= rna_mesh_ldata(me);
+ index= CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, name);
+ cdl= (index == -1)? NULL: &ldata->layers[index];
}
return cdl;
}
static CustomDataLayer *rna_Mesh_uv_texture_new(struct Mesh *me, struct bContext *C, const char *name)
{
- CustomData *fdata;
+ CustomData *pdata;
CustomDataLayer *cdl= NULL;
int index;
- if(ED_mesh_uv_texture_add(C, me, name, FALSE)) {
- fdata= rna_mesh_fdata(me);
- index= CustomData_get_named_layer_index(fdata, CD_MTFACE, name);
- cdl= (index == -1)? NULL: &fdata->layers[index];
+ if(ED_mesh_uv_texture_add(C, NULL, NULL, me, name, FALSE)) {
+ pdata= rna_mesh_pdata(me);
+ index= CustomData_get_named_layer_index(pdata, CD_MTEXPOLY, name);
+ cdl= (index == -1)? NULL: &pdata->layers[index];
}
return cdl;
}
@@ -1320,7 +1221,7 @@ static void rna_def_mface(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Index", "Index number of the vertex");
}
-static void rna_def_mtface(BlenderRNA *brna)
+static void rna_def_mtexpoly(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
@@ -1330,7 +1231,7 @@ static void rna_def_mtface(BlenderRNA *brna)
{TF_ALPHA, "ALPHA", 0, "Alpha", "Render polygon transparent, depending on alpha channel of the texture"},
{TF_CLIP, "CLIPALPHA", 0, "Clip Alpha", "Use the images alpha values clipped with no blending (binary alpha)"},
{0, NULL, 0, NULL, NULL}};
- const int uv_dim[]= {4, 2};
+ int uv_dim[]= {4, 2};
srna= RNA_def_struct(brna, "MeshTextureFaceLayer", NULL);
RNA_def_struct_ui_text(srna, "Mesh Texture Face Layer", "Layer of texture faces in a Mesh datablock");
@@ -1367,7 +1268,7 @@ static void rna_def_mtface(BlenderRNA *brna)
RNA_def_property_collection_funcs(prop, "rna_MeshTextureFaceLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshTextureFaceLayer_data_length", 0, 0);
srna= RNA_def_struct(brna, "MeshTextureFace", NULL);
- RNA_def_struct_sdna(srna, "MTFace");
+ RNA_def_struct_sdna(srna, "MTexPoly");
RNA_def_struct_ui_text(srna, "Mesh Texture Face", "UV mapping, texturing and game engine data for a face");
RNA_def_struct_path_func(srna, "rna_MeshTextureFace_path");
RNA_def_struct_ui_icon(srna, ICON_FACESEL_HLT);
@@ -1406,7 +1307,7 @@ static void rna_def_mtface(BlenderRNA *brna)
prop= RNA_def_property(srna, "use_twoside", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", TF_TWOSIDE);
- RNA_def_property_ui_text(prop, "Two-side", "Render face two-sided");
+ RNA_def_property_ui_text(prop, "Twoside", "Render face twosided");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop= RNA_def_property(srna, "use_object_color", PROP_BOOLEAN, PROP_NONE);
@@ -1451,36 +1352,13 @@ static void rna_def_mtface(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "UV Selected", "");
RNA_def_property_update(prop, 0, "rna_Mesh_update_select");
+#if 0
prop= RNA_def_property(srna, "pin_uv", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "unwrap", TF_PIN1);
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "UV Pinned", "");
RNA_def_property_update(prop, 0, "rna_Mesh_update_select");
- prop= RNA_def_property(srna, "uv1", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_array(prop, 2);
- RNA_def_property_float_funcs(prop, "rna_MeshTextureFace_uv1_get", "rna_MeshTextureFace_uv1_set", NULL);
- RNA_def_property_ui_text(prop, "UV 1", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop= RNA_def_property(srna, "uv2", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_array(prop, 2);
- RNA_def_property_float_funcs(prop, "rna_MeshTextureFace_uv2_get", "rna_MeshTextureFace_uv2_set", NULL);
- RNA_def_property_ui_text(prop, "UV 2", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop= RNA_def_property(srna, "uv3", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_array(prop, 2);
- RNA_def_property_float_funcs(prop, "rna_MeshTextureFace_uv3_get", "rna_MeshTextureFace_uv3_set", NULL);
- RNA_def_property_ui_text(prop, "UV 3", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop= RNA_def_property(srna, "uv4", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_array(prop, 2);
- RNA_def_property_float_funcs(prop, "rna_MeshTextureFace_uv4_get", "rna_MeshTextureFace_uv4_set", NULL);
- RNA_def_property_ui_text(prop, "UV 4", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
prop= RNA_def_property(srna, "uv", PROP_FLOAT, PROP_NONE);
RNA_def_property_multi_array(prop, 2, uv_dim);
RNA_def_property_flag(prop, PROP_DYNAMIC);
@@ -1493,7 +1371,7 @@ static void rna_def_mtface(BlenderRNA *brna)
RNA_def_property_multi_array(prop, 2, uv_dim);
RNA_def_property_float_sdna(prop, NULL, "uv");
RNA_def_property_ui_text(prop, "UV", "Fixed size UV coordinates array");
-
+#endif
}
static void rna_def_msticky(BlenderRNA *brna)
@@ -1511,7 +1389,7 @@ static void rna_def_msticky(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
}
-static void rna_def_mcol(BlenderRNA *brna)
+static void rna_def_mloopcol(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
@@ -1537,6 +1415,7 @@ static void rna_def_mcol(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "active_rnd", 0);
RNA_def_property_boolean_funcs(prop, "rna_MeshColorLayer_active_render_get", "rna_MeshColorLayer_active_render_set");
RNA_def_property_ui_text(prop, "Active Render", "Sets the layer as active for rendering");
+
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop= RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
@@ -1549,32 +1428,6 @@ static void rna_def_mcol(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Mesh Vertex Color", "Vertex colors for a face in a Mesh");
RNA_def_struct_path_func(srna, "rna_MeshColor_path");
- prop= RNA_def_property(srna, "color1", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_funcs(prop, "rna_MeshColor_color1_get", "rna_MeshColor_color1_set", NULL);
- RNA_def_property_ui_text(prop, "Color 1", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop= RNA_def_property(srna, "color2", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_funcs(prop, "rna_MeshColor_color2_get", "rna_MeshColor_color2_set", NULL);
- RNA_def_property_ui_text(prop, "Color 2", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop= RNA_def_property(srna, "color3", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_funcs(prop, "rna_MeshColor_color3_get", "rna_MeshColor_color3_set", NULL);
- RNA_def_property_ui_text(prop, "Color 3", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop= RNA_def_property(srna, "color4", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_funcs(prop, "rna_MeshColor_color4_get", "rna_MeshColor_color4_set", NULL);
- RNA_def_property_ui_text(prop, "Color 4", "");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
}
@@ -1662,6 +1515,43 @@ static void rna_def_mproperties(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
}
+void rna_def_texmat_common(StructRNA *srna, const char *texspace_editable)
+{
+ PropertyRNA *prop;
+
+ /* texture space */
+ prop= RNA_def_property(srna, "auto_texspace", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "texflag", AUTOSPACE);
+ RNA_def_property_ui_text(prop, "Auto Texture Space", "Adjusts active object's texture space automatically when transforming object");
+
+ prop= RNA_def_property(srna, "texspace_loc", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_float_sdna(prop, NULL, "loc");
+ RNA_def_property_ui_text(prop, "Texure Space Location", "Texture space location");
+ RNA_def_property_editable_func(prop, texspace_editable);
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
+ prop= RNA_def_property(srna, "texspace_size", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "size");
+ RNA_def_property_ui_text(prop, "Texture Space Size", "Texture space size");
+ RNA_def_property_editable_func(prop, texspace_editable);
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
+ /* not supported yet
+ prop= RNA_def_property(srna, "texspace_rot", PROP_FLOAT, PROP_EULER);
+ RNA_def_property_float(prop, NULL, "rot");
+ RNA_def_property_ui_text(prop, "Texture Space Rotation", "Texture space rotation");
+ RNA_def_property_editable_func(prop, texspace_editable);
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");*/
+
+ /* materials */
+ prop= RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");
+ RNA_def_property_struct_type(prop, "Material");
+ RNA_def_property_ui_text(prop, "Materials", "");
+}
+
+
+/* scene.objects */
/* mesh.vertices */
static void rna_def_mesh_vertices(BlenderRNA *brna, PropertyRNA *cprop)
{
@@ -1669,7 +1559,7 @@ static void rna_def_mesh_vertices(BlenderRNA *brna, PropertyRNA *cprop)
// PropertyRNA *prop;
FunctionRNA *func;
-// PropertyRNA *parm;
+ PropertyRNA *parm;
RNA_def_property_srna(cprop, "MeshVertices");
srna= RNA_def_struct(brna, "MeshVertices", NULL);
@@ -1678,7 +1568,7 @@ static void rna_def_mesh_vertices(BlenderRNA *brna, PropertyRNA *cprop)
func= RNA_def_function(srna, "add", "ED_mesh_vertices_add");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of vertices to add.", 0, INT_MAX);
+ parm= RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of vertices to add.", 0, INT_MAX);
}
/* mesh.edges */
@@ -1688,7 +1578,7 @@ static void rna_def_mesh_edges(BlenderRNA *brna, PropertyRNA *cprop)
// PropertyRNA *prop;
FunctionRNA *func;
-// PropertyRNA *parm;
+ PropertyRNA *parm;
RNA_def_property_srna(cprop, "MeshEdges");
srna= RNA_def_struct(brna, "MeshEdges", NULL);
@@ -1697,7 +1587,7 @@ static void rna_def_mesh_edges(BlenderRNA *brna, PropertyRNA *cprop)
func= RNA_def_function(srna, "add", "ED_mesh_edges_add");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of vertices to add.", 0, INT_MAX);
+ parm= RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of vertices to add.", 0, INT_MAX);
}
/* mesh.faces */
@@ -1707,7 +1597,7 @@ static void rna_def_mesh_faces(BlenderRNA *brna, PropertyRNA *cprop)
PropertyRNA *prop;
FunctionRNA *func;
- /*PropertyRNA *parm;*/
+ PropertyRNA *parm;
RNA_def_property_srna(cprop, "MeshFaces");
srna= RNA_def_struct(brna, "MeshFaces", NULL);
@@ -1718,15 +1608,9 @@ static void rna_def_mesh_faces(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_int_sdna(prop, NULL, "act_face");
RNA_def_property_ui_text(prop, "Active Face", "The active face for this mesh");
- prop= RNA_def_property(srna, "active_tface", PROP_POINTER, PROP_UNSIGNED);
- RNA_def_property_struct_type(prop, "MeshTextureFace");
- RNA_def_property_pointer_funcs(prop, "rna_Mesh_active_mtface_get", NULL, NULL, NULL);
- RNA_def_property_ui_text(prop, "Active Texture Face", "Active Texture Face");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
func= RNA_def_function(srna, "add", "ED_mesh_faces_add");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of vertices to add.", 0, INT_MAX);
+ parm= RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of vertices to add.", 0, INT_MAX);
}
/* mesh.vertex_colors */
@@ -1746,7 +1630,7 @@ static void rna_def_vertex_colors(BlenderRNA *brna, PropertyRNA *cprop)
func= RNA_def_function(srna, "new", "rna_Mesh_vertex_color_new");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func, "Add a vertex color layer to Mesh.");
- RNA_def_string(func, "name", "Col", 0, "", "Vertex color name.");
+ parm= RNA_def_string(func, "name", "UVTex", 0, "", "UV Texture name.");
parm= RNA_def_pointer(func, "layer", "MeshColorLayer", "", "The newly created layer.");
RNA_def_function_return(func, parm);
@@ -1787,7 +1671,7 @@ static void rna_def_uv_textures(BlenderRNA *brna, PropertyRNA *cprop)
func= RNA_def_function(srna, "new", "rna_Mesh_uv_texture_new");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func, "Add a UV texture layer to Mesh.");
- RNA_def_string(func, "name", "UVTex", 0, "", "UV Texture name.");
+ parm= RNA_def_string(func, "name", "UVTex", 0, "", "UV Texture name.");
parm= RNA_def_pointer(func, "layer", "MeshTextureFaceLayer", "", "The newly created layer.");
RNA_def_function_return(func, parm);
@@ -1847,11 +1731,11 @@ static void rna_def_mesh(BlenderRNA *brna)
prop= RNA_def_property(srna, "texture_mesh", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "texcomesh");
RNA_def_property_flag(prop, PROP_EDITABLE|PROP_ID_SELF_CHECK);
- RNA_def_property_ui_text(prop, "Texture Mesh", "Use another mesh for texture indices (vertex indices must be aligned)");
+ RNA_def_property_ui_text(prop, "Texture Mesh", "Use another mesh for texture indicies (vertex indicies must be aligned)");
/* UV textures */
prop= RNA_def_property(srna, "uv_textures", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer");
+ RNA_def_property_collection_sdna(prop, NULL, "pdata.layers", "pdata.totlayer");
RNA_def_property_collection_funcs(prop, "rna_Mesh_uv_textures_begin", 0, 0, 0, "rna_Mesh_uv_textures_length", 0, 0);
RNA_def_property_struct_type(prop, "MeshTextureFaceLayer");
RNA_def_property_ui_text(prop, "UV Textures", "");
@@ -1880,26 +1764,26 @@ static void rna_def_mesh(BlenderRNA *brna)
/* Vertex colors */
prop= RNA_def_property(srna, "vertex_colors", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer");
+ RNA_def_property_collection_sdna(prop, NULL, "ldata.layers", "ldata.totlayer");
RNA_def_property_collection_funcs(prop, "rna_Mesh_vertex_colors_begin", 0, 0, 0, "rna_Mesh_vertex_colors_length", 0, 0);
RNA_def_property_struct_type(prop, "MeshColorLayer");
RNA_def_property_ui_text(prop, "Vertex Colors", "");
rna_def_vertex_colors(brna, prop);
prop= RNA_def_property(srna, "layers_float", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer");
+ RNA_def_property_collection_sdna(prop, NULL, "pdata.layers", "pdata.totlayer");
RNA_def_property_collection_funcs(prop, "rna_Mesh_float_layers_begin", 0, 0, 0, "rna_Mesh_float_layers_length", 0, 0);
RNA_def_property_struct_type(prop, "MeshFloatPropertyLayer");
RNA_def_property_ui_text(prop, "Float Property Layers", "");
prop= RNA_def_property(srna, "layers_int", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer");
+ RNA_def_property_collection_sdna(prop, NULL, "pdata.layers", "pdata.totlayer");
RNA_def_property_collection_funcs(prop, "rna_Mesh_int_layers_begin", 0, 0, 0, "rna_Mesh_int_layers_length", 0, 0);
RNA_def_property_struct_type(prop, "MeshIntPropertyLayer");
RNA_def_property_ui_text(prop, "Int Property Layers", "");
prop= RNA_def_property(srna, "layers_string", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer");
+ RNA_def_property_collection_sdna(prop, NULL, "pdata.layers", "pdata.totlayer");
RNA_def_property_collection_funcs(prop, "rna_Mesh_string_layers_begin", 0, 0, 0, "rna_Mesh_string_layers_length", 0, 0);
RNA_def_property_struct_type(prop, "MeshStringPropertyLayer");
RNA_def_property_ui_text(prop, "String Property Layers", "");
@@ -1931,21 +1815,14 @@ static void rna_def_mesh(BlenderRNA *brna)
prop= RNA_def_property(srna, "use_auto_texspace", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "texflag", AUTOSPACE);
RNA_def_property_ui_text(prop, "Auto Texture Space", "Adjusts active object's texture space automatically when transforming object");
- RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_Mesh_texspace_set");
- prop= RNA_def_property(srna, "texspace_location", PROP_FLOAT, PROP_TRANSLATION);
+ /*prop= RNA_def_property(srna, "texspace_location", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Texture Space Location", "Texture space location");
RNA_def_property_editable_func(prop, "rna_Mesh_texspace_editable");
RNA_def_property_float_funcs(prop, "rna_Mesh_texspace_loc_get", "rna_Mesh_texspace_loc_set", NULL);
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop= RNA_def_property(srna, "texspace_size", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Texture Space Size", "Texture space size");
- RNA_def_property_editable_func(prop, "rna_Mesh_texspace_editable");
- RNA_def_property_float_funcs(prop, "rna_Mesh_texspace_size_get", "rna_Mesh_texspace_size_set", NULL);
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+ */
/* not supported yet
prop= RNA_def_property(srna, "texspace_rot", PROP_FLOAT, PROP_EULER);
@@ -1953,25 +1830,17 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Texture Space Rotation", "Texture space rotation");
RNA_def_property_editable_func(prop, texspace_editable);
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");*/
-
- /* materials */
- prop= RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");
- RNA_def_property_struct_type(prop, "Material");
- RNA_def_property_ui_text(prop, "Materials", "");
- RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */
/* Mesh Draw Options for Edit Mode*/
prop= RNA_def_property(srna, "show_edges", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEDGES);
- RNA_def_property_ui_text(prop, "Draw Edges", "Displays selected edges using highlights in the 3D view and UV editor");
+ RNA_def_property_ui_text(prop, "Draw Edges", "Displays selected edges using hilights in the 3D view and UV editor");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop= RNA_def_property(srna, "show_all_edges", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_ALLEDGES);
RNA_def_property_ui_text(prop, "All Edges", "Displays all edges for wireframe in all view modes in the 3D view");
- RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, NULL);
prop= RNA_def_property(srna, "show_faces", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWFACES);
@@ -2007,15 +1876,15 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWSHARP);
RNA_def_property_ui_text(prop, "Draw Sharp", "Displays sharp edges, used with the EdgeSplit modifier");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
+
prop= RNA_def_property(srna, "show_extra_edge_length", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEXTRA_EDGELEN);
RNA_def_property_ui_text(prop, "Edge Length", "Displays selected edge lengths, Using global values when set in the transform panel");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
- prop= RNA_def_property(srna, "show_extra_face_angle", PROP_BOOLEAN, PROP_NONE);
+ prop= RNA_def_property(srna, "show_extra_edge_angle", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEXTRA_FACEANG);
- RNA_def_property_ui_text(prop, "Faces Angles", "Displays the angles in the selected edges in degrees, Using global values when set in the transform panel");
+ RNA_def_property_ui_text(prop, "Edge Angles", "Displays the angles in the selected edges in degrees, Using global values when set in the transform panel");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop= RNA_def_property(srna, "show_extra_face_area", PROP_BOOLEAN, PROP_NONE);
@@ -2023,6 +1892,10 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Face Area", "Displays the area of selected faces, Using global values when set in the transform panel");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+ prop= RNA_def_property(srna, "draw_pins", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAW_PINS);
+ RNA_def_property_ui_text(prop, "Draw Pins", "Displays pinned mesh elements");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
/* editflag */
prop= RNA_def_property(srna, "use_mirror_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_X);
@@ -2067,6 +1940,7 @@ static void rna_def_mesh(BlenderRNA *brna)
/* pointers */
rna_def_animdata_common(srna);
+ rna_def_texmat_common(srna, "rna_Mesh_texspace_editable");
RNA_api_mesh(srna);
}
@@ -2078,9 +1952,9 @@ void RNA_def_mesh(BlenderRNA *brna)
rna_def_mvert_group(brna);
rna_def_medge(brna);
rna_def_mface(brna);
- rna_def_mtface(brna);
+ rna_def_mtexpoly(brna);
rna_def_msticky(brna);
- rna_def_mcol(brna);
+ rna_def_mloopcol(brna);
rna_def_mproperties(brna);
}
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
index ed28e648507..f6c9405dc78 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: rna_mesh_api.c 21283 2009-07-01 12:19:00Z blendix $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
@@ -37,7 +37,15 @@
#include "ED_mesh.h"
#ifdef RNA_RUNTIME
-
+const char *rna_Mesh_unit_test_compare(struct Mesh *mesh, bContext *C, struct Mesh *mesh2)
+{
+ char *ret = mesh_cmp(mesh, mesh2, FLT_EPSILON*60);
+
+ if (!ret)
+ ret = "Same";
+
+ return ret;
+}
#else
@@ -58,6 +66,13 @@ void RNA_api_mesh(StructRNA *srna)
RNA_def_boolean(func, "calc_edges", 0, "Calculate Edges", "Force recalculation of edges.");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ func= RNA_def_function(srna, "unit_test_compare", "rna_Mesh_unit_test_compare");
+ parm= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to compare to");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ /* return value */
+ parm= RNA_def_string(func, "result", "nothing", 64, "Return value", "String description of result of comparison");
+ RNA_def_function_return(func, parm);
+
func= RNA_def_function(srna, "validate", "BKE_mesh_validate");
RNA_def_function_ui_description(func, "validate geometry, return True when the mesh has had invalid geometry corrected/removed.");
parm= RNA_def_boolean(func, "verbose", 0, "Verbose", "Output information about the errors found");
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 3c77ab63821..03e5b744bc5 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1250,8 +1250,8 @@ static void rna_def_modifier_edgesplit(BlenderRNA *brna)
// XXX, convert to radians.
prop= RNA_def_property(srna, "split_angle", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0, 180);
- RNA_def_property_ui_range(prop, 0, 180, 100, 2);
+ RNA_def_property_range(prop, 0, 90);
+ RNA_def_property_ui_range(prop, 0, 90, 100, 2);
RNA_def_property_ui_text(prop, "Split Angle", "Angle above which to split edges");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index 0bf8ba7a56c..d63fd39a728 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: rna_nla.c 21537 2009-07-11 22:22:53Z gsrb3d $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 2784a904753..48054604a25 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -43,6 +43,7 @@
#include "DNA_scene_types.h"
#include "DNA_meta_types.h"
+#include "BKE_tessmesh.h"
#include "BKE_group.h" /* needed for object_in_group() */
#include "BLO_sys_types.h" /* needed for intptr_t used in ED_mesh.h */
@@ -222,8 +223,8 @@ void rna_Object_active_shape_update(Main *bmain, Scene *scene, PointerRNA *ptr)
/* exit/enter editmode to get new shape */
switch(ob->type) {
case OB_MESH:
- load_editMesh(scene, ob);
- make_editMesh(scene, ob);
+ EDBM_LoadEditBMesh(scene, ob);
+ EDBM_MakeEditBMesh(scene->toolsettings, scene, ob);
break;
case OB_CURVE:
case OB_SURF:
@@ -576,8 +577,8 @@ static void rna_Object_active_material_index_set(PointerRNA *ptr, int value)
if(ob->type==OB_MESH) {
Mesh *me= ob->data;
- if(me->edit_mesh)
- me->edit_mesh->mat_nr= value;
+ if(me->edit_btmesh)
+ me->edit_btmesh->mat_nr= value;
}
}
@@ -1593,6 +1594,7 @@ static void rna_def_object_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
func= RNA_def_function(srna, "remove", "rna_Object_modifier_remove");
RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove an existing modifier from the object.");
+
/* target to remove*/
parm= RNA_def_pointer(func, "modifier", "Modifier", "", "Modifier to remove.");
RNA_def_property_flag(parm, PROP_REQUIRED|PROP_NEVER_NULL);
diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c
index 667335e99e6..b1daf8adcde 100644
--- a/source/blender/makesrna/intern/rna_pose_api.c
+++ b/source/blender/makesrna/intern/rna_pose_api.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: rna_pose_api.c 23425 2009-09-22 19:09:04Z gsrb3d $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 92bcdfd1a7f..a8e8cbcc153 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -35,6 +35,8 @@
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
+#include "BKE_tessmesh.h"
+
/* Include for Bake Options */
#include "RE_pipeline.h"
@@ -837,9 +839,9 @@ static void rna_Scene_editmesh_select_mode_set(PointerRNA *ptr, const int *value
if(scene->basact) {
Mesh *me= get_mesh(scene->basact->object);
- if(me && me->edit_mesh && me->edit_mesh->selectmode != flag) {
- me->edit_mesh->selectmode= flag;
- EM_selectmode_set(me->edit_mesh);
+ if(me && me->edit_btmesh && me->edit_btmesh->selectmode != flag) {
+ me->edit_btmesh->selectmode= flag;
+ EDBM_selectmode_set(me->edit_btmesh);
}
}
}
@@ -851,7 +853,7 @@ static void rna_Scene_editmesh_select_mode_update(Main *bmain, Scene *scene, Poi
if(scene->basact) {
me= get_mesh(scene->basact->object);
- if(me && me->edit_mesh==NULL)
+ if(me && me->edit_btmesh==NULL)
me= NULL;
}
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 76300496108..1376786469a 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -966,6 +966,16 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Current Frame", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop= RNA_def_property(srna, "pin", PROP_INT, PROP_COLOR);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Pin", "");
+ RNA_def_property_update(prop, NC_WINDOW, NULL);
+
+ prop= RNA_def_property(srna, "pin_opac", PROP_INT, PROP_PERCENTAGE);
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pin Face Opacity", "");
+ RNA_def_property_update(prop, NC_WINDOW, NULL);
}
static void rna_def_userdef_theme_space_graph(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index 2c332beed0e..8c0be26d3a8 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: rna_wm_api.c 21094 2009-06-23 00:09:26Z gsrb3d $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/makesrna/rna_cleanup/rna_properties.txt b/source/blender/makesrna/rna_cleanup/rna_properties.txt
index 030fecec20e..a60bb61d6b1 100644
--- a/source/blender/makesrna/rna_cleanup/rna_properties.txt
+++ b/source/blender/makesrna/rna_cleanup/rna_properties.txt
@@ -1 +1,4609 @@
+<<<<<<< .working
+ NOTE * CLASS.FROM -> TO: TYPE "DESCRIPTION"
+#+ * ActionGroup.channels -> channels: collection, "(read-only) F-Curves in this group"
+#+ * ActionGroup.custom_color -> custom_color: int "Index of custom color set"
+#+ * ActionGroup.lock -> lock: boolean "Action Group is locked"
+#+ * ActionGroup.name -> name: string "NO DESCRIPTION"
+#+ * ActionGroup.select -> select: boolean "Action Group is selected"
+#ActionGroup.show_expanded -> show_expanded: boolean "Action Group is expanded"
+#+ * Actuator.name -> name: string "NO DESCRIPTION"
+#Actuator.pin -> pin: boolean "Display when not linked to a visible states controller"
+#Actuator.show_expanded -> show_expanded: boolean "Set actuator expanded in the user interface"
+#+ * Actuator.type -> type: enum "NO DESCRIPTION"
+#+ * Actuator|ActionActuator.action -> action: pointer "NO DESCRIPTION"
+#Actuator|ActionActuator.frame_blend_in -> frame_blend_in: int "Number of frames of motion blending"
+#+ * Actuator|ActionActuator.frame_end -> frame_end: int "NO DESCRIPTION"
+#+ * Actuator|ActionActuator.frame_property -> frame_property: string "Assign the actions current frame number to this property"
+#+ * Actuator|ActionActuator.frame_start -> frame_start: int "NO DESCRIPTION"
+#Actuator|ActionActuator.play_mode -> play_mode: enum "Action playback type"
+#+ * Actuator|ActionActuator.priority -> priority: int "Execution priority - lower numbers will override actions with higher numbers. With 2 or more actions at once, the overriding channels must be lower in the stack"
+#+ * Actuator|ActionActuator.property -> property: string "Use this property to define the Action position"
+#Actuator|ActionActuator.use_continue_last_frame -> use_continue_last_frame: boolean "Restore last frame when switching on/off, otherwise play from the start each time"
+#+ * Actuator|ArmatureActuator.bone -> bone: string "Bone on which the constraint is defined"
+#+ * Actuator|ArmatureActuator.constraint -> constraint: string "Name of the constraint you want to control"
+#+ * Actuator|ArmatureActuator.mode -> mode: enum "NO DESCRIPTION"
+#+ * Actuator|ArmatureActuator.secondary_target -> secondary_target: pointer "Set weight of this constraint"
+#+ * Actuator|ArmatureActuator.target -> target: pointer "Set this object as the target of the constraint"
+#+ * Actuator|ArmatureActuator.weight -> weight: float "Set weight of this constraint"
+#+ * Actuator|CameraActuator.axis -> axis: enum "Specify the axis the Camera will try to get behind"
+#+ * Actuator|CameraActuator.height -> height: float "NO DESCRIPTION"
+#+ * Actuator|CameraActuator.max -> max: float "NO DESCRIPTION"
+#+ * Actuator|CameraActuator.min -> min: float "NO DESCRIPTION"
+#+ * Actuator|CameraActuator.object -> object: pointer "Look at this Object"
+#Actuator|ConstraintActuator.angle_max -> angle_max: float "Maximum angle (in degree) allowed with target direction. No correction is done if angle with target direction is between min and max"
+#Actuator|ConstraintActuator.angle_min -> angle_min: float "Minimum angle (in degree) to maintain with target direction. No correction is done if angle with target direction is between min and max"
+#+ * Actuator|ConstraintActuator.damping -> damping: int "Damping factor: time constant (in frame) of low pass filter"
+#+ * Actuator|ConstraintActuator.damping_rotation -> damping_rotation: int "Use a different damping for orientation"
+#+ * Actuator|ConstraintActuator.direction -> direction: enum "Set the direction of the ray"
+#+ * Actuator|ConstraintActuator.direction_axis -> direction_axis: enum "Select the axis to be aligned along the reference direction"
+#+ * Actuator|ConstraintActuator.distance -> distance: float "Set the maximum length of ray"
+#+ * Actuator|ConstraintActuator.fh_damping -> fh_damping: float "Damping factor of the Fh spring force"
+#+ * Actuator|ConstraintActuator.fh_height -> fh_height: float "Height of the Fh area"
+#+ * Actuator|ConstraintActuator.limit -> limit: enum "NO DESCRIPTION"
+#+ * Actuator|ConstraintActuator.limit_max -> limit_max: float "NO DESCRIPTION"
+#+ * Actuator|ConstraintActuator.limit_min -> limit_min: float "NO DESCRIPTION"
+#+ * Actuator|ConstraintActuator.material -> material: string "Ray detects only Objects with this material"
+#+ * Actuator|ConstraintActuator.mode -> mode: enum "The type of the constraint"
+#+ * Actuator|ConstraintActuator.property -> property: string "Ray detect only Objects with this property"
+#+ * Actuator|ConstraintActuator.range -> range: float "Set the maximum length of ray"
+#Actuator|ConstraintActuator.rotation_max -> rotation_max: float[3] "Reference Direction"
+#+ * Actuator|ConstraintActuator.spring -> spring: float "Spring force within the Fh area"
+#+ * Actuator|ConstraintActuator.time -> time: int "Maximum activation time in frame, 0 for unlimited"
+#Actuator|ConstraintActuator.use_fh_normal -> use_fh_normal: boolean "Add a horizontal spring force on slopes"
+#Actuator|ConstraintActuator.use_fh_paralel_axis -> use_fh_paralel_axis: boolean "Keep object axis parallel to normal"
+#Actuator|ConstraintActuator.use_force_distance -> use_force_distance: boolean "Force distance of object to point of impact of ray"
+#Actuator|ConstraintActuator.use_local -> use_local: boolean "Set ray along objects axis or global axis"
+#Actuator|ConstraintActuator.use_material_detect -> use_material_detect: boolean "Detect material instead of property"
+#Actuator|ConstraintActuator.use_normal -> use_normal: boolean "Set object axis along (local axis) or parallel (global axis) to the normal at hit position"
+#Actuator|ConstraintActuator.use_persistent -> use_persistent: boolean "Persistent actuator: stays active even if ray does not reach target"
+#+ * Actuator|EditObjectActuator.angular_velocity -> angular_velocity: float[3] "Angular velocity upon creation"
+#+ * Actuator|EditObjectActuator.dynamic_operation -> dynamic_operation: enum "NO DESCRIPTION"
+#+ * Actuator|EditObjectActuator.linear_velocity -> linear_velocity: float[3] "Velocity upon creation"
+#+ * Actuator|EditObjectActuator.mass -> mass: float "The mass of the object"
+#+ * Actuator|EditObjectActuator.mesh -> mesh: pointer "Replace the existing, when left blank Phys will remake the existing physics mesh"
+#+ * Actuator|EditObjectActuator.mode -> mode: enum "The mode of the actuator"
+#+ * Actuator|EditObjectActuator.object -> object: pointer "Add this Object and all its children (cant be on an visible layer)"
+#+ * Actuator|EditObjectActuator.time -> time: int "Duration the new Object lives or the track takes"
+#+ * Actuator|EditObjectActuator.track_object -> track_object: pointer "Track to this Object"
+#Actuator|EditObjectActuator.use_3d_tracking -> use_3d_tracking: boolean "Enable 3D tracking"
+#Actuator|EditObjectActuator.use_local_angular_velocity -> use_local_angular_velocity: boolean "Apply the rotation locally"
+#Actuator|EditObjectActuator.use_local_linear_velocity -> use_local_linear_velocity: boolean "Apply the transformation locally"
+#Actuator|EditObjectActuator.use_replace_display_mesh -> use_replace_display_mesh: boolean "Replace the display mesh"
+#Actuator|EditObjectActuator.use_replace_physics_mesh -> use_replace_physics_mesh: boolean "Replace the physics mesh (triangle bounds only - compound shapes not supported)"
+#Actuator|FCurveActuator.apply_to_children -> apply_to_children: boolean "Update F-Curve on all children Objects as well"
+#Actuator|FCurveActuator.frame_end -> frame_end: int "NO DESCRIPTION"
+#Actuator|FCurveActuator.frame_property -> frame_property: string "Assign the actions current frame number to this property"
+#Actuator|FCurveActuator.frame_start -> frame_start: int "NO DESCRIPTION"
+#Actuator|FCurveActuator.play_type -> play_type: enum "Specify the way you want to play the animation"
+#Actuator|FCurveActuator.property -> property: string "Use this property to define the F-Curve position"
+#Actuator|FCurveActuator.use_additive -> use_additive: boolean "F-Curve is added to the current loc/rot/scale in global or local coordinate according to Local flag"
+#Actuator|FCurveActuator.use_force -> use_force: boolean "Apply F-Curve as a global or local force depending on the local option (dynamic objects only)"
+#Actuator|FCurveActuator.use_local -> use_local: boolean "Let the F-Curve act in local coordinates, used in Force and Add mode"
+#+ * Actuator|Filter2DActuator.filter_pass -> filter_pass: int "Set filter order"
+#+ * Actuator|Filter2DActuator.glsl_shader -> glsl_shader: pointer "NO DESCRIPTION"
+#+ * Actuator|Filter2DActuator.mode -> mode: enum "NO DESCRIPTION"
+#+ * Actuator|Filter2DActuator.motion_blur_factor -> motion_blur_factor: float "Set motion blur factor"
+#Actuator|Filter2DActuator.use_motion_blur -> use_motion_blur: boolean "Enable/Disable Motion Blur"
+#+ * Actuator|GameActuator.filename -> filename: string "Load this blend file, use the // prefix for a path relative to the current blend file"
+#+ * Actuator|GameActuator.mode -> mode: enum "NO DESCRIPTION"
+#+ * Actuator|MessageActuator.body_message -> body_message: string "Optional message body Text"
+#+ * Actuator|MessageActuator.body_property -> body_property: string "The message body will be set by the Property Value"
+#+ * Actuator|MessageActuator.body_type -> body_type: enum "Toggle message type: either Text or a PropertyName"
+#+ * Actuator|MessageActuator.subject -> subject: string "Optional message subject. This is what can be filtered on"
+#+ * Actuator|MessageActuator.to_property -> to_property: string "Optional send message to objects with this name only, or empty to broadcast"
+#+ * Actuator|ObjectActuator.angular_velocity -> angular_velocity: float[3] "Sets the angular velocity"
+#+ * Actuator|ObjectActuator.damping -> damping: int "Number of frames to reach the target velocity"
+#+ * Actuator|ObjectActuator.derivate_coefficient -> derivate_coefficient: float "Not required, high values can cause instability"
+#+ * Actuator|ObjectActuator.force -> force: float[3] "Sets the force"
+#+ * Actuator|ObjectActuator.force_max_x -> force_max_x: float "Set the upper limit for force"
+#+ * Actuator|ObjectActuator.force_max_y -> force_max_y: float "Set the upper limit for force"
+#+ * Actuator|ObjectActuator.force_max_z -> force_max_z: float "Set the upper limit for force"
+#+ * Actuator|ObjectActuator.force_min_x -> force_min_x: float "Set the lower limit for force"
+#+ * Actuator|ObjectActuator.force_min_y -> force_min_y: float "Set the lower limit for force"
+#+ * Actuator|ObjectActuator.force_min_z -> force_min_z: float "Set the lower limit for force"
+#+ * Actuator|ObjectActuator.integral_coefficient -> integral_coefficient: float "Low value (0.01) for slow response, high value (0.5) for fast response"
+#+ * Actuator|ObjectActuator.linear_velocity -> linear_velocity: float[3] "Sets the linear velocity (in Servo mode it sets the target relative linear velocity, it will be achieved by automatic application of force. Null velocity is a valid target)"
+#+ * Actuator|ObjectActuator.mode -> mode: enum "Specify the motion system"
+#Actuator|ObjectActuator.offset_location -> offset_location: float[3] "Sets the location"
+#Actuator|ObjectActuator.offset_rotation -> offset_rotation: float[3] "Sets the rotation"
+#+ * Actuator|ObjectActuator.proportional_coefficient -> proportional_coefficient: float "Typical value is 60x integral coefficient"
+#+ * Actuator|ObjectActuator.reference_object -> reference_object: pointer "Reference object for velocity calculation, leave empty for world reference"
+#+ * Actuator|ObjectActuator.torque -> torque: float[3] "Sets the torque"
+#Actuator|ObjectActuator.use_add_linear_velocity -> use_add_linear_velocity: boolean "Toggles between ADD and SET linV"
+#Actuator|ObjectActuator.use_local_angular_velocity -> use_local_angular_velocity: boolean "Angular velocity is defined in local coordinates"
+#Actuator|ObjectActuator.use_local_force -> use_local_force: boolean "Force is defined in local coordinates"
+#Actuator|ObjectActuator.use_local_linear_velocity -> use_local_linear_velocity: boolean "Velocity is defined in local coordinates"
+#Actuator|ObjectActuator.use_local_location -> use_local_location: boolean "Location is defined in local coordinates"
+#Actuator|ObjectActuator.use_local_rotation -> use_local_rotation: boolean "Rotation is defined in local coordinates"
+#Actuator|ObjectActuator.use_local_torque -> use_local_torque: boolean "Torque is defined in local coordinates"
+#Actuator|ObjectActuator.use_servo_limit_x -> use_servo_limit_x: boolean "Set limit to force along the X axis"
+#Actuator|ObjectActuator.use_servo_limit_y -> use_servo_limit_y: boolean "Set limit to force along the Y axis"
+#Actuator|ObjectActuator.use_servo_limit_z -> use_servo_limit_z: boolean "Set limit to force along the Z axis"
+#+ * Actuator|ParentActuator.mode -> mode: enum "NO DESCRIPTION"
+#+ * Actuator|ParentActuator.object -> object: pointer "Set this object as parent"
+#Actuator|ParentActuator.use_compound -> use_compound: boolean "Add this object shape to the parent shape (only if the parent shape is already compound)"
+#Actuator|ParentActuator.use_ghost -> use_ghost: boolean "Make this object ghost while parented (only if not compound)"
+#+ * Actuator|PropertyActuator.mode -> mode: enum "NO DESCRIPTION"
+#+ * Actuator|PropertyActuator.object -> object: pointer "Copy from this Object"
+#+ * Actuator|PropertyActuator.object_property -> object_property: string "Copy this property"
+#+ * Actuator|PropertyActuator.property -> property: string "The name of the property"
+#+ * Actuator|PropertyActuator.value -> value: string "The value to use, use around strings"
+#+ * Actuator|RandomActuator.chance -> chance: float "Pick a number between 0 and 1. Success if you stay below this value"
+#+ * Actuator|RandomActuator.distribution -> distribution: enum "Choose the type of distribution"
+#+ * Actuator|RandomActuator.float_max -> float_max: float "Choose a number from a range. Upper boundary of the range"
+#+ * Actuator|RandomActuator.float_mean -> float_mean: float "A normal distribution. Mean of the distribution"
+#+ * Actuator|RandomActuator.float_min -> float_min: float "Choose a number from a range. Lower boundary of the range"
+#+ * Actuator|RandomActuator.float_value -> float_value: float "Always return this number"
+#+ * Actuator|RandomActuator.half_life_time -> half_life_time: float "Negative exponential dropoff"
+#+ * Actuator|RandomActuator.int_max -> int_max: int "Choose a number from a range. Upper boundary of the range"
+#+ * Actuator|RandomActuator.int_mean -> int_mean: float "Expected mean value of the distribution"
+#+ * Actuator|RandomActuator.int_min -> int_min: int "Choose a number from a range. Lower boundary of the range"
+#+ * Actuator|RandomActuator.int_value -> int_value: int "Always return this number"
+#+ * Actuator|RandomActuator.property -> property: string "Assign the random value to this property"
+#+ * Actuator|RandomActuator.seed -> seed: int "Initial seed of the random generator. Use Python for more freedom (choose 0 for not random)"
+#+ * Actuator|RandomActuator.standard_derivation -> standard_derivation: float "A normal distribution. Standard deviation of the distribution"
+#Actuator|RandomActuator.use_always_true -> use_always_true: boolean "Always false or always true"
+#+ * Actuator|SceneActuator.camera -> camera: pointer "Set this Camera. Leave empty to refer to self object"
+#+ * Actuator|SceneActuator.mode -> mode: enum "NO DESCRIPTION"
+#+ * Actuator|SceneActuator.scene -> scene: pointer "Set the Scene to be added/removed/paused/resumed"
+#+ * Actuator|ShapeActionActuator.action -> action: pointer "NO DESCRIPTION"
+#Actuator|ShapeActionActuator.frame_blend_in -> frame_blend_in: int "Number of frames of motion blending"
+#+ * Actuator|ShapeActionActuator.frame_end -> frame_end: int "NO DESCRIPTION"
+#+ * Actuator|ShapeActionActuator.frame_property -> frame_property: string "Assign the actions current frame number to this property"
+#+ * Actuator|ShapeActionActuator.frame_start -> frame_start: int "NO DESCRIPTION"
+#+ * Actuator|ShapeActionActuator.mode -> mode: enum "Action playback type"
+#+ * Actuator|ShapeActionActuator.priority -> priority: int "Execution priority - lower numbers will override actions with higher numbers. With 2 or more actions at once, the overriding channels must be lower in the stack"
+#+ * Actuator|ShapeActionActuator.property -> property: string "Use this property to define the Action position"
+#Actuator|ShapeActionActuator.use_continue_last_frame -> use_continue_last_frame: boolean "Restore last frame when switching on/off, otherwise play from the start each time"
+#+ * Actuator|SoundActuator.cone_inner_angle_3d -> cone_inner_angle_3d: float "The angle of the inner cone"
+#+ * Actuator|SoundActuator.cone_outer_angle_3d -> cone_outer_angle_3d: float "The angle of the outer cone"
+#+ * Actuator|SoundActuator.cone_outer_gain_3d -> cone_outer_gain_3d: float "The gain outside the outer cone. The gain in the outer cone will be interpolated between this value and the normal gain in the inner cone"
+#Actuator|SoundActuator.distance_3d_max -> distance_3d_max: float "The maximum distance at which you can hear the sound"
+#Actuator|SoundActuator.distance_3d_reference -> distance_3d_reference: float "The distance where the sound has a gain of 1.0"
+#Actuator|SoundActuator.gain_3d_max -> gain_3d_max: float "The maximum gain of the sound, no matter how near it is"
+#Actuator|SoundActuator.gain_3d_min -> gain_3d_min: float "The minimum gain of the sound, no matter how far it is away"
+#+ * Actuator|SoundActuator.mode -> mode: enum "NO DESCRIPTION"
+#+ * Actuator|SoundActuator.pitch -> pitch: float "Sets the pitch of the sound"
+#+ * Actuator|SoundActuator.rolloff_factor_3d -> rolloff_factor_3d: float "The influence factor on volume depending on distance"
+#+ * Actuator|SoundActuator.sound -> sound: pointer "NO DESCRIPTION"
+#Actuator|SoundActuator.use_sound_3d -> use_sound_3d: boolean "Enable/Disable 3D Sound"
+#+ * Actuator|SoundActuator.volume -> volume: float "Sets the initial volume of the sound"
+#+ * Actuator|StateActuator.operation -> operation: enum "Select the bit operation on object state mask"
+#Actuator|StateActuator.states -> states: boolean[30] "NO DESCRIPTION"
+#Actuator|VisibilityActuator.apply_to_children -> apply_to_children: boolean "Set all the children of this object to the same visibility/occlusion recursively"
+#Actuator|VisibilityActuator.use_occlusion -> use_occlusion: boolean "Set the object to occlude objects behind it. Initialized from the object type in physics button"
+#Actuator|VisibilityActuator.use_visible -> use_visible: boolean "Set the objects visible. Initialized from the objects render restriction toggle (access in the outliner)"
+#+ * Addon.module -> module: string "Module name"
+#+ * AnimData.action -> action: pointer "Active Action for this datablock"
+#AnimData.action_blend_type -> action_blend_type: enum "Method used for combining Active Actions result with result of NLA stack"
+#+ * AnimData.action_extrapolation -> action_extrapolation: enum "Action to take for gaps past the Active Actions range (when evaluating with NLA)"
+#+ * AnimData.action_influence -> action_influence: float "Amount the Active Action contributes to the result of the NLA stack"
+#+ * AnimData.drivers -> drivers: collection, "(read-only) The Drivers/Expressions for this datablock"
+#+ * AnimData.nla_tracks -> nla_tracks: collection, "(read-only) NLA Tracks (i.e. Animation Layers)"
+#AnimData.use_nla -> use_nla: boolean "NLA stack is evaluated when evaluating this block"
+#AnimViz.motion_path -> motion_path: pointer, "(read-only) Motion Path settings for visualisation"
+#AnimViz.onion_skin_frames -> onion_skin_frames: pointer, "(read-only) Onion Skinning (ghosting) settings for visualisation"
+#+ * AnimVizMotionPaths.bake_location -> bake_location: enum "When calculating Bone Paths, use Head or Tips"
+#AnimVizMotionPaths.frame_after -> frame_after: int "Number of frames to show after the current frame (only for Around Current Frame Onion-skinning method)"
+#AnimVizMotionPaths.frame_before -> frame_before: int "Number of frames to show before the current frame (only for Around Current Frame Onion-skinning method)"
+#+ * AnimVizMotionPaths.frame_end -> frame_end: int "End frame of range of paths to display/calculate (not for Around Current Frame Onion-skinning method)"
+#+ * AnimVizMotionPaths.frame_start -> frame_start: int "Starting frame of range of paths to display/calculate (not for Around Current Frame Onion-skinning method)"
+#+ * AnimVizMotionPaths.frame_step -> frame_step: int "Number of frames between paths shown (not for On Keyframes Onion-skinning method)"
+#+ * AnimVizMotionPaths.show_frame_numbers -> show_frame_numbers: boolean "Show frame numbers on Motion Paths"
+#AnimVizMotionPaths.show_keyframe_action_all -> show_keyframe_action_all: boolean "For bone motion paths, search whole Action for keyframes instead of in group with matching name only (is slower)"
+#AnimVizMotionPaths.show_keyframe_highlight -> show_keyframe_highlight: boolean "Emphasize position of keyframes on Motion Paths"
+#+ * AnimVizMotionPaths.show_keyframe_numbers -> show_keyframe_numbers: boolean "Show frame numbers of Keyframes on Motion Paths"
+#+ * AnimVizMotionPaths.type -> type: enum "Type of range to show for Motion Paths"
+#AnimVizOnionSkinning.frame_after -> frame_after: int "Number of frames to show after the current frame (only for Around Current Frame Onion-skinning method)"
+#AnimVizOnionSkinning.frame_before -> frame_before: int "Number of frames to show before the current frame (only for Around Current Frame Onion-skinning method)"
+#+ * AnimVizOnionSkinning.frame_end -> frame_end: int "End frame of range of Ghosts to display (not for Around Current Frame Onion-skinning method)"
+#+ * AnimVizOnionSkinning.frame_start -> frame_start: int "Starting frame of range of Ghosts to display (not for Around Current Frame Onion-skinning method)"
+#+ * AnimVizOnionSkinning.frame_step -> frame_step: int "Number of frames between ghosts shown (not for On Keyframes Onion-skinning method)"
+#AnimVizOnionSkinning.show_only_selected -> show_only_selected: boolean "For Pose-Mode drawing, only draw ghosts for selected bones"
+#+ * AnimVizOnionSkinning.type -> type: enum "Method used for determining what ghosts get drawn"
+#MAKE PROPERTY OF A COLLECTION * Area.active_space -> active_space: pointer, "(read-only) Space currently being displayed in this area"
+#+ * Area.regions -> regions: collection, "(read-only) Regions this area is subdivided in"
+#+ * Area.show_menus -> show_menus: boolean "Show menus in the header"
+#+ * Area.spaces -> spaces: collection, "(read-only) Spaces contained in this area, the first space is active"
+#+ * Area.type -> type: enum "Space type"
+#+ * ArmatureBones.active -> active: pointer "Armatures active bone"
+#+ * ArmatureEditBones.active -> active: pointer "Armatures active edit bone"
+#+ * BackgroundImage.image -> image: pointer "Image displayed and edited in this space"
+#+ * BackgroundImage.image_user -> image_user: pointer, "(read-only) Parameters defining which layer, pass and frame of the image is displayed"
+#+ * BackgroundImage.offset_x -> offset_x: float "Offsets image horizontally from the world origin"
+#+ * BackgroundImage.offset_y -> offset_y: float "Offsets image vertically from the world origin"
+#+ * BackgroundImage.show_expanded -> show_expanded: boolean "Show the expanded in the user interface"
+#+ * BackgroundImage.size -> size: float "Scaling factor for the background image"
+#+ * BackgroundImage.transparency -> transparency: float "Amount to blend the image against the background color"
+#+ * BackgroundImage.view_axis -> view_axis: enum "The axis to display the image on"
+#+ * BezierSplinePoint.co -> co: float[3] "Coordinates of the control point"
+#BezierSplinePoint.handle_left -> handle_left: float[3] "Coordinates of the first handle"
+#BezierSplinePoint.handle_left_type -> handle_left_type: enum "Handle types"
+#BezierSplinePoint.handle_right -> handle_right: float[3] "Coordinates of the second handle"
+#BezierSplinePoint.handle_right_type -> handle_right_type: enum "Handle types"
+#+ * BezierSplinePoint.hide -> hide: boolean "Visibility status"
+#+ * BezierSplinePoint.radius -> radius: float, "(read-only) Radius for bevelling"
+#+ * BezierSplinePoint.select_control_point -> select_control_point: boolean "Control point selection status"
+#+ * BezierSplinePoint.select_left_handle -> select_left_handle: boolean "Handle 1 selection status"
+#+ * BezierSplinePoint.select_right_handle -> select_right_handle: boolean "Handle 2 selection status"
+#+ * BezierSplinePoint.tilt -> tilt: float "Tilt in 3D View"
+#+ * BezierSplinePoint.weight -> weight: float "Softbody goal weight"
+#+ * BlenderRNA.structs -> structs: collection, "(read-only)"
+#+ * BoidRule.name -> name: string "Boid rule name"
+#+ * BoidRule.type -> type: enum, "(read-only)"
+#BoidRule.use_in_air -> use_in_air: boolean "Use rule when boid is flying"
+#BoidRule.use_on_land -> use_on_land: boolean "Use rule when boid is on land"
+#+ * BoidRule|BoidRuleAverageSpeed.level -> level: float "How much velocitys z-component is kept constant"
+#+ * BoidRule|BoidRuleAverageSpeed.speed -> speed: float "Percentage of maximum speed"
+#+ * BoidRule|BoidRuleAverageSpeed.wander -> wander: float "How fast velocitys direction is randomized"
+#+ * BoidRule|BoidRuleAvoid.fear_factor -> fear_factor: float "Avoid object if danger from it is above this threshold"
+#+ * BoidRule|BoidRuleAvoid.object -> object: pointer "Object to avoid"
+#BoidRule|BoidRuleAvoid.use_predict -> use_predict: boolean "Predict target movement"
+#+ * BoidRule|BoidRuleAvoidCollision.look_ahead -> look_ahead: float "Time to look ahead in seconds"
+#BoidRule|BoidRuleAvoidCollision.use_avoid -> use_avoid: boolean "Avoid collision with other boids"
+#BoidRule|BoidRuleAvoidCollision.use_avoid_collision -> use_avoid_collision: boolean "Avoid collision with deflector objects"
+#+ * BoidRule|BoidRuleFight.distance -> distance: float "Attack boids at max this distance"
+#+ * BoidRule|BoidRuleFight.flee_distance -> flee_distance: float "Flee to this distance"
+#+ * BoidRule|BoidRuleFollowLeader.distance -> distance: float "Distance behind leader to follow"
+#+ * BoidRule|BoidRuleFollowLeader.object -> object: pointer "Follow this object instead of a boid"
+#BoidRule|BoidRuleFollowLeader.queue_count -> queue_count: int "How many boids in a line"
+#BoidRule|BoidRuleFollowLeader.use_line -> use_line: boolean "Follow leader in a line"
+#+ * BoidRule|BoidRuleGoal.object -> object: pointer "Goal object"
+#BoidRule|BoidRuleGoal.use_predict -> use_predict: boolean "Predict target movement"
+#+ * BoidSettings.accuracy -> accuracy: float "Accuracy of attack"
+#+ * BoidSettings.active_boid_state -> active_boid_state: pointer, "(read-only)"
+#+ * BoidSettings.active_boid_state_index -> active_boid_state_index: int "NO DESCRIPTION"
+#+ * BoidSettings.aggression -> aggression: float "Boid will fight this times stronger enemy"
+#BoidSettings.air_acc_max -> air_acc_max: float "Maximum acceleration in air (relative to maximum speed)"
+#BoidSettings.air_ave_max -> air_ave_max: float "Maximum angular velocity in air (relative to 180 degrees)"
+#+ * BoidSettings.air_personal_space -> air_personal_space: float "Radius of boids personal space in air (% of particle size)"
+#BoidSettings.air_speed_max -> air_speed_max: float "Maximum speed in air"
+#BoidSettings.air_speed_min -> air_speed_min: float "Minimum speed in air (relative to maximum speed)"
+#BoidSettings.bank -> bank: float "Amount of rotation around velocity vector on turns"
+#+ * BoidSettings.health -> health: float "Initial boid health when born"
+#+ * BoidSettings.height -> height: float "Boid height relative to particle size"
+#BoidSettings.land_acc_max -> land_acc_max: float "Maximum acceleration on land (relative to maximum speed)"
+#BoidSettings.land_ave_max -> land_ave_max: float "Maximum angular velocity on land (relative to 180 degrees)"
+#+ * BoidSettings.land_jump_speed -> land_jump_speed: float "Maximum speed for jumping"
+#+ * BoidSettings.land_personal_space -> land_personal_space: float "Radius of boids personal space on land (% of particle size)"
+#BoidSettings.land_smooth -> land_smooth: float "How smoothly the boids land"
+#BoidSettings.land_speed_max -> land_speed_max: float "Maximum speed on land"
+#+ * BoidSettings.land_stick_force -> land_stick_force: float "How strong a force must be to start effecting a boid on land"
+#+ * BoidSettings.range -> range: float "The maximum distance from which a boid can attack"
+#+ * BoidSettings.states -> states: collection, "(read-only)"
+#+ * BoidSettings.strength -> strength: float "Maximum caused damage on attack per second"
+#BoidSettings.use_climb -> use_climb: boolean "Allow boids to climb goal objects"
+#BoidSettings.use_flight -> use_flight: boolean "Allow boids to move in air"
+#BoidSettings.use_land -> use_land: boolean "Allow boids to move on land"
+#+ * BoidState.active_boid_rule -> active_boid_rule: pointer, "(read-only)"
+#+ * BoidState.active_boid_rule_index -> active_boid_rule_index: int "NO DESCRIPTION"
+#+ * BoidState.falloff -> falloff: float "NO DESCRIPTION"
+#+ * BoidState.name -> name: string "Boid state name"
+#BoidState.rule_fuzzy -> rule_fuzzy: float "NO DESCRIPTION"
+#+ * BoidState.rules -> rules: collection, "(read-only)"
+#+ * BoidState.ruleset_type -> ruleset_type: enum "How the rules in the list are evaluated"
+#+ * BoidState.volume -> volume: float "NO DESCRIPTION"
+#+ * Bone.bbone_in -> bbone_in: float "Length of first Bezier Handle (for B-Bones only)"
+#+ * Bone.bbone_out -> bbone_out: float "Length of second Bezier Handle (for B-Bones only)"
+#+ * Bone.bbone_segments -> bbone_segments: int "Number of subdivisions of bone (for B-Bones only)"
+#+ * Bone.children -> children: collection, "(read-only) Bones which are children of this bone"
+#+ * Bone.envelope_distance -> envelope_distance: float "Bone deformation distance (for Envelope deform only)"
+#+ * Bone.envelope_weight -> envelope_weight: float "Bone deformation weight (for Envelope deform only)"
+#+ * Bone.head -> head: float[3] "Location of head end of the bone relative to its parent"
+#+ * Bone.head_local -> head_local: float[3] "Location of head end of the bone relative to armature"
+#+ * Bone.head_radius -> head_radius: float "Radius of head of bone (for Envelope deform only)"
+#+ * Bone.hide -> hide: boolean "Bone is not visible when it is not in Edit Mode (i.e. in Object or Pose Modes)"
+#+ * Bone.hide_select -> hide_select: boolean "Bone is able to be selected"
+#Bone.layers -> layers: boolean[32] "Layers bone exists in"
+#+ * Bone.matrix -> matrix: float[9] "3x3 bone matrix"
+#+ * Bone.matrix_local -> matrix_local: float[16] "4x4 bone matrix relative to armature"
+#+ * Bone.name -> name: string "NO DESCRIPTION"
+#+ * Bone.parent -> parent: pointer, "(read-only) Parent bone (in same Armature)"
+#+ * Bone.select -> select: boolean "NO DESCRIPTION"
+#Bone.show_wire -> show_wire: boolean "Bone is always drawn as Wireframe regardless of viewport draw mode. Useful for non-obstructive custom bone shapes"
+#+ * Bone.tail -> tail: float[3] "Location of tail end of the bone"
+#+ * Bone.tail_local -> tail_local: float[3] "Location of tail end of the bone relative to armature"
+#+ * Bone.tail_radius -> tail_radius: float "Radius of tail of bone (for Envelope deform only)"
+#Bone.use_connect -> use_connect: boolean, "(read-only) When bone has a parent, bones head is struck to the parents tail"
+#Bone.use_cyclic_offset -> use_cyclic_offset: boolean "When bone doesnt have a parent, it receives cyclic offset effects"
+#Bone.use_deform -> use_deform: boolean "Bone does not deform any geometry"
+#Bone.use_envelope_multiply -> use_envelope_multiply: boolean "When deforming bone, multiply effects of Vertex Group weights with Envelope influence"
+#Bone.use_hinge -> use_hinge: boolean "Bone inherits rotation or scale from parent bone"
+#Bone.use_inherit_scale -> use_inherit_scale: boolean "Bone inherits scaling from parent bone"
+#Bone.use_local_location -> use_local_location: boolean "Bone location is set in local space"
+#+ * BoneGroup.color_set -> color_set: enum "Custom color set to use"
+#+ * BoneGroup.colors -> colors: pointer, "(read-only) Copy of the colors associated with the groups color set"
+#+ * BoneGroup.name -> name: string "NO DESCRIPTION"
+#BoneGroups.active -> active: pointer "Active bone group for this pose"
+#+ * ClothCollisionSettings.collision_quality -> collision_quality: int "How many collision iterations should be done. (higher is better quality but slower)"
+#ClothCollisionSettings.distance_min -> distance_min: float "Minimum distance between collision objects before collision response takes in"
+#+ * ClothCollisionSettings.friction -> friction: float "Friction force if a collision happened. (higher = less movement)"
+#+ * ClothCollisionSettings.group -> group: pointer "Limit colliders to this Group"
+#+ * ClothCollisionSettings.self_collision_quality -> self_collision_quality: int "How many self collision iterations should be done. (higher is better quality but slower)"
+#ClothCollisionSettings.self_distance_min -> self_distance_min: float "0.5 means no distance at all, 1.0 is maximum distance"
+#+ * ClothCollisionSettings.self_friction -> self_friction: float "Friction/damping with self contact"
+#ClothCollisionSettings.use_collision -> use_collision: boolean "Enable collisions with other objects"
+#ClothCollisionSettings.use_self_collision -> use_self_collision: boolean "Enable self collisions"
+#+ * ClothSettings.air_damping -> air_damping: float "Air has normally some thickness which slows falling things down"
+#+ * ClothSettings.bending_stiffness -> bending_stiffness: float "Wrinkle coefficient. (higher = less smaller but more big wrinkles)"
+#+ * ClothSettings.bending_stiffness_max -> bending_stiffness_max: float "Maximum bending stiffness value"
+#+ * ClothSettings.bending_vertex_group -> bending_vertex_group: string "Vertex group for fine control over bending stiffness"
+#+ * ClothSettings.collider_friction -> collider_friction: float "NO DESCRIPTION"
+#+ * ClothSettings.effector_weights -> effector_weights: pointer, "(read-only)"
+#+ * ClothSettings.goal_default -> goal_default: float "Default Goal (vertex target position) value, when no Vertex Group used"
+#+ * ClothSettings.goal_friction -> goal_friction: float "Goal (vertex target position) friction"
+#+ * ClothSettings.goal_max -> goal_max: float "Goal maximum, vertex group weights are scaled to match this range"
+#+ * ClothSettings.goal_min -> goal_min: float "Goal minimum, vertex group weights are scaled to match this range"
+#+ * ClothSettings.goal_spring -> goal_spring: float "Goal (vertex target position) spring stiffness"
+#+ * ClothSettings.gravity -> gravity: float[3] "Gravity or external force vector"
+#+ * ClothSettings.internal_friction -> internal_friction: float "NO DESCRIPTION"
+#+ * ClothSettings.mass -> mass: float "Mass of cloth material"
+#+ * ClothSettings.mass_vertex_group -> mass_vertex_group: string "Vertex Group for pinning of vertices"
+#+ * ClothSettings.pin_stiffness -> pin_stiffness: float "Pin (vertex target position) spring stiffness"
+#+ * ClothSettings.pre_roll -> pre_roll: int "Simulation starts on this frame"
+#+ * ClothSettings.quality -> quality: int "Quality of the simulation in steps per frame. (higher is better quality but slower)"
+#+ * ClothSettings.rest_shape_key -> rest_shape_key: pointer "Shape key to use the rest spring lengths from"
+#+ * ClothSettings.spring_damping -> spring_damping: float "Damping of cloth velocity. (higher = more smooth, less jiggling)"
+#+ * ClothSettings.structural_stiffness -> structural_stiffness: float "Overall stiffness of structure"
+#+ * ClothSettings.structural_stiffness_max -> structural_stiffness_max: float "Maximum structural stiffness value"
+#+ * ClothSettings.structural_stiffness_vertex_group -> structural_stiffness_vertex_group: string "Vertex group for fine control over structural stiffness"
+#ClothSettings.use_pin_cloth -> use_pin_cloth: boolean "Enable pinning of cloth vertices to other objects/positions"
+#ClothSettings.use_stiffness_scale -> use_stiffness_scale: boolean "If enabled, stiffness can be scaled along a weight painted vertex group"
+#+ * CollisionSettings.absorption -> absorption: float "How much of effector force gets lost during collision with this object (in percent)"
+#+ * CollisionSettings.damping -> damping: float "Amount of damping during collision"
+#+ * CollisionSettings.damping_factor -> damping_factor: float "Amount of damping during particle collision"
+#CollisionSettings.damping_random -> damping_random: float "Random variation of damping"
+#+ * CollisionSettings.friction_factor -> friction_factor: float "Amount of friction during particle collision"
+#CollisionSettings.friction_random -> friction_random: float "Random variation of friction"
+#+ * CollisionSettings.permeability -> permeability: float "Chance that the particle will pass through the mesh"
+#+ * CollisionSettings.stickness -> stickness: float "Amount of stickness to surface collision"
+#CollisionSettings.thickness_inner -> thickness_inner: float "Inner face thickness"
+#CollisionSettings.thickness_outer -> thickness_outer: float "Outer face thickness"
+#+ * CollisionSettings.use -> use: boolean "Enable this objects as a collider for physics systems"
+#CollisionSettings.use_particle_kill -> use_particle_kill: boolean "Kill collided particles"
+#+ * ColorRamp.elements -> elements: collection, "(read-only)"
+#+ * ColorRamp.interpolation -> interpolation: enum "NO DESCRIPTION"
+#+ * ColorRampElement.color -> color: float[4] "NO DESCRIPTION"
+#+ * ColorRampElement.position -> position: float "NO DESCRIPTION"
+#ConsoleLine.body -> body: string "Text in the line"
+#+ * ConsoleLine.current_character -> current_character: int "NO DESCRIPTION"
+#+ * Constraint.active -> active: boolean "Constraint is the one being edited"
+#Constraint.error_location -> error_location: float, "(read-only) Amount of residual error in Blender space unit for constraints that work on position"
+#Constraint.error_rotation -> error_rotation: float, "(read-only) Amount of residual error in radiant for constraints that work on orientation"
+#+ * Constraint.influence -> influence: float "Amount of influence constraint will have on the final solution"
+#Constraint.is_proxy_local -> is_proxy_local: boolean "Constraint was added in this proxy instance (i.e. did not belong to source Armature)"
+#Constraint.is_valid -> is_valid: boolean, "(read-only) Constraint has invalid settings and will not be evaluated"
+#+ * Constraint.mute -> mute: boolean "Enable/Disable Constraint"
+#+ * Constraint.name -> name: string "Constraint name"
+#+ * Constraint.owner_space -> owner_space: enum "Space that owner is evaluated in"
+#Constraint.show_expanded -> show_expanded: boolean "Constraints panel is expanded in UI"
+#+ * Constraint.target_space -> target_space: enum "Space that target is evaluated in"
+#+ * Constraint.type -> type: enum, "(read-only)"
+#+ * ConstraintTarget.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * ConstraintTarget.target -> target: pointer "Target Object"
+#+ * Constraint|ActionConstraint.action -> action: pointer "NO DESCRIPTION"
+#+ * Constraint|ActionConstraint.frame_end -> frame_end: int "Last frame of the Action to use"
+#+ * Constraint|ActionConstraint.frame_start -> frame_start: int "First frame of the Action to use"
+#Constraint|ActionConstraint.max -> max: float "Maximum value for target channel range"
+#Constraint|ActionConstraint.min -> min: float "Minimum value for target channel range"
+#+ * Constraint|ActionConstraint.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * Constraint|ActionConstraint.target -> target: pointer "Target Object"
+#+ * Constraint|ActionConstraint.transform_channel -> transform_channel: enum "Transformation channel from the target that is used to key the Action"
+#+ * Constraint|ChildOfConstraint.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * Constraint|ChildOfConstraint.target -> target: pointer "Target Object"
+#+ * Constraint|ChildOfConstraint.use_location_x -> use_location_x: boolean "Use X Location of Parent"
+#+ * Constraint|ChildOfConstraint.use_location_y -> use_location_y: boolean "Use Y Location of Parent"
+#+ * Constraint|ChildOfConstraint.use_location_z -> use_location_z: boolean "Use Z Location of Parent"
+#+ * Constraint|ChildOfConstraint.use_rotation_x -> use_rotation_x: boolean "Use X Rotation of Parent"
+#+ * Constraint|ChildOfConstraint.use_rotation_y -> use_rotation_y: boolean "Use Y Rotation of Parent"
+#+ * Constraint|ChildOfConstraint.use_rotation_z -> use_rotation_z: boolean "Use Z Rotation of Parent"
+#+ * Constraint|ChildOfConstraint.use_scale_x -> use_scale_x: boolean "Use X Scale of Parent"
+#+ * Constraint|ChildOfConstraint.use_scale_y -> use_scale_y: boolean "Use Y Scale of Parent"
+#+ * Constraint|ChildOfConstraint.use_scale_z -> use_scale_z: boolean "Use Z Scale of Parent"
+#+ * Constraint|ClampToConstraint.main_axis -> main_axis: enum "Main axis of movement"
+#+ * Constraint|ClampToConstraint.target -> target: pointer "Target Object"
+#Constraint|ClampToConstraint.use_cyclic -> use_cyclic: boolean "Treat curve as cyclic curve (no clamping to curve bounding box"
+#+ * Constraint|CopyLocationConstraint.head_tail -> head_tail: float "Target along length of bone: Head=0, Tail=1"
+#+ * Constraint|CopyLocationConstraint.invert_x -> invert_x: boolean "Invert the X location"
+#+ * Constraint|CopyLocationConstraint.invert_y -> invert_y: boolean "Invert the Y location"
+#+ * Constraint|CopyLocationConstraint.invert_z -> invert_z: boolean "Invert the Z location"
+#+ * Constraint|CopyLocationConstraint.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * Constraint|CopyLocationConstraint.target -> target: pointer "Target Object"
+#+ * Constraint|CopyLocationConstraint.use_offset -> use_offset: boolean "Add original location into copied location"
+#+ * Constraint|CopyLocationConstraint.use_x -> use_x: boolean "Copy the targets X location"
+#+ * Constraint|CopyLocationConstraint.use_y -> use_y: boolean "Copy the targets Y location"
+#+ * Constraint|CopyLocationConstraint.use_z -> use_z: boolean "Copy the targets Z location"
+#+ * Constraint|CopyRotationConstraint.invert_x -> invert_x: boolean "Invert the X rotation"
+#+ * Constraint|CopyRotationConstraint.invert_y -> invert_y: boolean "Invert the Y rotation"
+#+ * Constraint|CopyRotationConstraint.invert_z -> invert_z: boolean "Invert the Z rotation"
+#+ * Constraint|CopyRotationConstraint.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * Constraint|CopyRotationConstraint.target -> target: pointer "Target Object"
+#+ * Constraint|CopyRotationConstraint.use_offset -> use_offset: boolean "Add original rotation into copied rotation"
+#+ * Constraint|CopyRotationConstraint.use_x -> use_x: boolean "Copy the targets X rotation"
+#+ * Constraint|CopyRotationConstraint.use_y -> use_y: boolean "Copy the targets Y rotation"
+#+ * Constraint|CopyRotationConstraint.use_z -> use_z: boolean "Copy the targets Z rotation"
+#+ * Constraint|CopyScaleConstraint.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * Constraint|CopyScaleConstraint.target -> target: pointer "Target Object"
+#+ * Constraint|CopyScaleConstraint.use_offset -> use_offset: boolean "Add original scale into copied scale"
+#+ * Constraint|CopyScaleConstraint.use_x -> use_x: boolean "Copy the targets X scale"
+#+ * Constraint|CopyScaleConstraint.use_y -> use_y: boolean "Copy the targets Y scale"
+#+ * Constraint|CopyScaleConstraint.use_z -> use_z: boolean "Copy the targets Z scale"
+#+ * Constraint|CopyTransformsConstraint.head_tail -> head_tail: float "Target along length of bone: Head=0, Tail=1"
+#+ * Constraint|CopyTransformsConstraint.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * Constraint|CopyTransformsConstraint.target -> target: pointer "Target Object"
+#+ * Constraint|DampedTrackConstraint.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * Constraint|DampedTrackConstraint.target -> target: pointer "Target Object"
+#Constraint|DampedTrackConstraint.track_axis -> track_axis: enum "Axis that points to the target object"
+#+ * Constraint|FloorConstraint.floor_location -> floor_location: enum "Location of target that object will not pass through"
+#+ * Constraint|FloorConstraint.offset -> offset: float "Offset of floor from object origin"
+#+ * Constraint|FloorConstraint.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * Constraint|FloorConstraint.target -> target: pointer "Target Object"
+#+ * Constraint|FloorConstraint.use_rotation -> use_rotation: boolean "Use the targets rotation to determine floor"
+#Constraint|FloorConstraint.use_sticky -> use_sticky: boolean "Immobilize object while constrained"
+#Constraint|FollowPathConstraint.forward_axis -> forward_axis: enum "Axis that points forward along the path"
+#+ * Constraint|FollowPathConstraint.offset -> offset: int "Offset from the position corresponding to the time frame"
+#+ * Constraint|FollowPathConstraint.offset_factor -> offset_factor: float "Percentage value defining target position along length of bone"
+#+ * Constraint|FollowPathConstraint.target -> target: pointer "Target Object"
+#Constraint|FollowPathConstraint.up_axis -> up_axis: enum "Axis that points upward"
+#+ * Constraint|FollowPathConstraint.use_curve_follow -> use_curve_follow: boolean "Object will follow the heading and banking of the curve"
+#+ * Constraint|FollowPathConstraint.use_curve_radius -> use_curve_radius: boolean "Objects scale by the curve radius"
+#Constraint|FollowPathConstraint.use_fixed_location -> use_fixed_location: boolean "Object will stay locked to a single point somewhere along the length of the curve regardless of time"
+#Constraint|KinematicConstraint.chain_count -> chain_count: int "How many bones are included in the IK effect - 0 uses all bones"
+#+ * Constraint|KinematicConstraint.distance -> distance: float "Radius of limiting sphere"
+#+ * Constraint|KinematicConstraint.ik_type -> ik_type: enum "NO DESCRIPTION"
+#+ * Constraint|KinematicConstraint.iterations -> iterations: int "Maximum number of solving iterations"
+#+ * Constraint|KinematicConstraint.limit_mode -> limit_mode: enum "Distances in relation to sphere of influence to allow"
+#Constraint|KinematicConstraint.lock_location_x -> lock_location_x: boolean "Constraint position along X axis"
+#Constraint|KinematicConstraint.lock_location_y -> lock_location_y: boolean "Constraint position along Y axis"
+#Constraint|KinematicConstraint.lock_location_z -> lock_location_z: boolean "Constraint position along Z axis"
+#Constraint|KinematicConstraint.lock_rotation_x -> lock_rotation_x: boolean "Constraint rotation along X axis"
+#Constraint|KinematicConstraint.lock_rotation_y -> lock_rotation_y: boolean "Constraint rotation along Y axis"
+#Constraint|KinematicConstraint.lock_rotation_z -> lock_rotation_z: boolean "Constraint rotation along Z axis"
+#+ * Constraint|KinematicConstraint.orient_weight -> orient_weight: float "For Tree-IK: Weight of orientation control for this target"
+#+ * Constraint|KinematicConstraint.pole_angle -> pole_angle: float "Pole rotation offset"
+#+ * Constraint|KinematicConstraint.pole_subtarget -> pole_subtarget: string "NO DESCRIPTION"
+#+ * Constraint|KinematicConstraint.pole_target -> pole_target: pointer "Object for pole rotation"
+#Constraint|KinematicConstraint.reference_axis -> reference_axis: enum "Constraint axis Lock options relative to Bone or Target reference"
+#+ * Constraint|KinematicConstraint.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * Constraint|KinematicConstraint.target -> target: pointer "Target Object"
+#Constraint|KinematicConstraint.use_location -> use_location: boolean "Chain follows position of target"
+#+ * Constraint|KinematicConstraint.use_rotation -> use_rotation: boolean "Chain follows rotation of target"
+#+ * Constraint|KinematicConstraint.use_stretch -> use_stretch: boolean "Enable IK Stretching"
+#+ * Constraint|KinematicConstraint.use_tail -> use_tail: boolean "Include bones tail as last element in chain"
+#+ * Constraint|KinematicConstraint.use_target -> use_target: boolean "Disable for targetless IK"
+#+ * Constraint|KinematicConstraint.weight -> weight: float "For Tree-IK: Weight of position control for this target"
+#+ * Constraint|LimitDistanceConstraint.distance -> distance: float "Radius of limiting sphere"
+#+ * Constraint|LimitDistanceConstraint.limit_mode -> limit_mode: enum "Distances in relation to sphere of influence to allow"
+#+ * Constraint|LimitDistanceConstraint.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * Constraint|LimitDistanceConstraint.target -> target: pointer "Target Object"
+#Constraint|LimitLocationConstraint.max_x -> max_x: float "Highest X value to allow"
+#Constraint|LimitLocationConstraint.max_y -> max_y: float "Highest Y value to allow"
+#Constraint|LimitLocationConstraint.max_z -> max_z: float "Highest Z value to allow"
+#Constraint|LimitLocationConstraint.min_x -> min_x: float "Lowest X value to allow"
+#Constraint|LimitLocationConstraint.min_y -> min_y: float "Lowest Y value to allow"
+#Constraint|LimitLocationConstraint.min_z -> min_z: float "Lowest Z value to allow"
+#Constraint|LimitLocationConstraint.use_max_x -> use_max_x: boolean "Use the maximum X value"
+#Constraint|LimitLocationConstraint.use_max_y -> use_max_y: boolean "Use the maximum Y value"
+#Constraint|LimitLocationConstraint.use_max_z -> use_max_z: boolean "Use the maximum Z value"
+#Constraint|LimitLocationConstraint.use_min_x -> use_min_x: boolean "Use the minimum X value"
+#Constraint|LimitLocationConstraint.use_min_y -> use_min_y: boolean "Use the minimum Y value"
+#Constraint|LimitLocationConstraint.use_min_z -> use_min_z: boolean "Use the minimum Z value"
+#Constraint|LimitLocationConstraint.use_transform_limit -> use_transform_limit: boolean "Transforms are affected by this constraint as well"
+#Constraint|LimitRotationConstraint.max_x -> max_x: float "Highest X value to allow"
+#Constraint|LimitRotationConstraint.max_y -> max_y: float "Highest Y value to allow"
+#Constraint|LimitRotationConstraint.max_z -> max_z: float "Highest Z value to allow"
+#Constraint|LimitRotationConstraint.min_x -> min_x: float "Lowest X value to allow"
+#Constraint|LimitRotationConstraint.min_y -> min_y: float "Lowest Y value to allow"
+#Constraint|LimitRotationConstraint.min_z -> min_z: float "Lowest Z value to allow"
+#+ * Constraint|LimitRotationConstraint.use_limit_x -> use_limit_x: boolean "Use the minimum X value"
+#+ * Constraint|LimitRotationConstraint.use_limit_y -> use_limit_y: boolean "Use the minimum Y value"
+#+ * Constraint|LimitRotationConstraint.use_limit_z -> use_limit_z: boolean "Use the minimum Z value"
+#Constraint|LimitRotationConstraint.use_transform_limit -> use_transform_limit: boolean "Transforms are affected by this constraint as well"
+#Constraint|LimitScaleConstraint.max_x -> max_x: float "Highest X value to allow"
+#Constraint|LimitScaleConstraint.max_y -> max_y: float "Highest Y value to allow"
+#Constraint|LimitScaleConstraint.max_z -> max_z: float "Highest Z value to allow"
+#Constraint|LimitScaleConstraint.min_x -> min_x: float "Lowest X value to allow"
+#Constraint|LimitScaleConstraint.min_y -> min_y: float "Lowest Y value to allow"
+#Constraint|LimitScaleConstraint.min_z -> min_z: float "Lowest Z value to allow"
+#Constraint|LimitScaleConstraint.use_max_x -> use_max_x: boolean "Use the maximum X value"
+#Constraint|LimitScaleConstraint.use_max_y -> use_max_y: boolean "Use the maximum Y value"
+#Constraint|LimitScaleConstraint.use_max_z -> use_max_z: boolean "Use the maximum Z value"
+#Constraint|LimitScaleConstraint.use_min_x -> use_min_x: boolean "Use the minimum X value"
+#Constraint|LimitScaleConstraint.use_min_y -> use_min_y: boolean "Use the minimum Y value"
+#Constraint|LimitScaleConstraint.use_min_z -> use_min_z: boolean "Use the minimum Z value"
+#Constraint|LimitScaleConstraint.use_transform_limit -> use_transform_limit: boolean "Transforms are affected by this constraint as well"
+#Constraint|LockedTrackConstraint.lock_axis -> lock_axis: enum "Axis that points upward"
+#+ * Constraint|LockedTrackConstraint.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * Constraint|LockedTrackConstraint.target -> target: pointer "Target Object"
+#Constraint|LockedTrackConstraint.track_axis -> track_axis: enum "Axis that points to the target object"
+#Constraint|MaintainVolumeConstraint.free_axis -> free_axis: enum "The free scaling axis of the object"
+#+ * Constraint|MaintainVolumeConstraint.volume -> volume: float "Volume of the bone at rest"
+#+ * Constraint|PivotConstraint.head_tail -> head_tail: float "Target along length of bone: Head=0, Tail=1"
+#+ * Constraint|PivotConstraint.offset -> offset: float[3] "Offset of pivot from target (when set), or from owners location (when Fixed Position is off), or the absolute pivot point"
+#Constraint|PivotConstraint.rotation_range -> rotation_range: enum "Rotation range on which pivoting should occur"
+#+ * Constraint|PivotConstraint.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * Constraint|PivotConstraint.target -> target: pointer "Target Object, defining the position of the pivot when defined"
+#Constraint|PivotConstraint.use_relative_location -> use_relative_location: boolean "Offset will be an absolute point in space instead of relative to the target"
+#Constraint|PythonConstraint.has_script_error -> has_script_error: boolean, "(read-only) The linked Python script has thrown an error"
+#Constraint|PythonConstraint.target_count -> target_count: int "Usually only 1-3 are needed"
+#+ * Constraint|PythonConstraint.targets -> targets: collection, "(read-only) Target Objects"
+#+ * Constraint|PythonConstraint.text -> text: pointer "The text object that contains the Python script"
+#+ * Constraint|PythonConstraint.use_targets -> use_targets: boolean "Use the targets indicated in the constraint panel"
+#+ * Constraint|RigidBodyJointConstraint.axis_x -> axis_x: float "Rotate pivot on X axis in degrees"
+#+ * Constraint|RigidBodyJointConstraint.axis_y -> axis_y: float "Rotate pivot on Y axis in degrees"
+#+ * Constraint|RigidBodyJointConstraint.axis_z -> axis_z: float "Rotate pivot on Z axis in degrees"
+#+ * Constraint|RigidBodyJointConstraint.child -> child: pointer "Child object"
+#+ * Constraint|RigidBodyJointConstraint.pivot_type -> pivot_type: enum "NO DESCRIPTION"
+#+ * Constraint|RigidBodyJointConstraint.pivot_x -> pivot_x: float "Offset pivot on X"
+#+ * Constraint|RigidBodyJointConstraint.pivot_y -> pivot_y: float "Offset pivot on Y"
+#+ * Constraint|RigidBodyJointConstraint.pivot_z -> pivot_z: float "Offset pivot on Z"
+#Constraint|RigidBodyJointConstraint.show_pivot -> show_pivot: boolean "Display the pivot point and rotation in 3D view"
+#+ * Constraint|RigidBodyJointConstraint.target -> target: pointer "Target Object"
+#Constraint|RigidBodyJointConstraint.use_linked_collision -> use_linked_collision: boolean "Disable collision between linked bodies"
+#+ * Constraint|ShrinkwrapConstraint.distance -> distance: float "Distance to Target"
+#+ * Constraint|ShrinkwrapConstraint.shrinkwrap_type -> shrinkwrap_type: enum "Selects type of shrinkwrap algorithm for target position"
+#+ * Constraint|ShrinkwrapConstraint.target -> target: pointer "Target Object"
+#+ * Constraint|ShrinkwrapConstraint.use_x -> use_x: boolean "Projection over X Axis"
+#+ * Constraint|ShrinkwrapConstraint.use_y -> use_y: boolean "Projection over Y Axis"
+#+ * Constraint|ShrinkwrapConstraint.use_z -> use_z: boolean "Projection over Z Axis"
+#Constraint|SplineIKConstraint.chain_count -> chain_count: int "How many bones are included in the chain"
+#+ * Constraint|SplineIKConstraint.joint_bindings -> joint_bindings: float[32] "(EXPERIENCED USERS ONLY) The relative positions of the joints along the chain as percentages"
+#+ * Constraint|SplineIKConstraint.target -> target: pointer "Curve that controls this relationship"
+#Constraint|SplineIKConstraint.use_chain_offset -> use_chain_offset: boolean "Offset the entire chain relative to the root joint"
+#+ * Constraint|SplineIKConstraint.use_curve_radius -> use_curve_radius: boolean "Average radius of the endpoints is used to tweak the X and Z Scaling of the bones, on top of XZ Scale mode"
+#Constraint|SplineIKConstraint.use_even_divisions -> use_even_divisions: boolean "Ignore the relative lengths of the bones when fitting to the curve"
+#Constraint|SplineIKConstraint.use_y_stretch -> use_y_stretch: boolean "Stretch the Y axis of the bones to fit the curve"
+#Constraint|SplineIKConstraint.xz_scale_mode -> xz_scale_mode: enum "Method used for determining the scaling of the X and Z axes of the bones"
+#+ * Constraint|StretchToConstraint.bulge -> bulge: float "Factor between volume variation and stretching"
+#+ * Constraint|StretchToConstraint.head_tail -> head_tail: float "Target along length of bone: Head=0, Tail=1"
+#+ * Constraint|StretchToConstraint.keep_axis -> keep_axis: enum "Axis to maintain during stretch"
+#Constraint|StretchToConstraint.rest_length -> rest_length: float "Length at rest position"
+#+ * Constraint|StretchToConstraint.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * Constraint|StretchToConstraint.target -> target: pointer "Target Object"
+#+ * Constraint|StretchToConstraint.volume -> volume: enum "Maintain the objects volume as it stretches"
+#+ * Constraint|TrackToConstraint.head_tail -> head_tail: float "Target along length of bone: Head=0, Tail=1"
+#+ * Constraint|TrackToConstraint.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * Constraint|TrackToConstraint.target -> target: pointer "Target Object"
+#Constraint|TrackToConstraint.track_axis -> track_axis: enum "Axis that points to the target object"
+#Constraint|TrackToConstraint.up_axis -> up_axis: enum "Axis that points upward"
+#Constraint|TrackToConstraint.use_target_z -> use_target_z: boolean "Targets Z axis, not World Z axis, will constraint the Up direction"
+#+ * Constraint|TransformConstraint.from_max_x -> from_max_x: float "Top range of X axis source motion"
+#+ * Constraint|TransformConstraint.from_max_y -> from_max_y: float "Top range of Y axis source motion"
+#+ * Constraint|TransformConstraint.from_max_z -> from_max_z: float "Top range of Z axis source motion"
+#+ * Constraint|TransformConstraint.from_min_x -> from_min_x: float "Bottom range of X axis source motion"
+#+ * Constraint|TransformConstraint.from_min_y -> from_min_y: float "Bottom range of Y axis source motion"
+#+ * Constraint|TransformConstraint.from_min_z -> from_min_z: float "Bottom range of Z axis source motion"
+#+ * Constraint|TransformConstraint.map_from -> map_from: enum "The transformation type to use from the target"
+#+ * Constraint|TransformConstraint.map_to -> map_to: enum "The transformation type to affect of the constrained object"
+#+ * Constraint|TransformConstraint.map_to_x_from -> map_to_x_from: enum "The source axis constrained objects X axis uses"
+#+ * Constraint|TransformConstraint.map_to_y_from -> map_to_y_from: enum "The source axis constrained objects Y axis uses"
+#+ * Constraint|TransformConstraint.map_to_z_from -> map_to_z_from: enum "The source axis constrained objects Z axis uses"
+#+ * Constraint|TransformConstraint.subtarget -> subtarget: string "NO DESCRIPTION"
+#+ * Constraint|TransformConstraint.target -> target: pointer "Target Object"
+#+ * Constraint|TransformConstraint.to_max_x -> to_max_x: float "Top range of X axis destination motion"
+#+ * Constraint|TransformConstraint.to_max_y -> to_max_y: float "Top range of Y axis destination motion"
+#+ * Constraint|TransformConstraint.to_max_z -> to_max_z: float "Top range of Z axis destination motion"
+#+ * Constraint|TransformConstraint.to_min_x -> to_min_x: float "Bottom range of X axis destination motion"
+#+ * Constraint|TransformConstraint.to_min_y -> to_min_y: float "Bottom range of Y axis destination motion"
+#+ * Constraint|TransformConstraint.to_min_z -> to_min_z: float "Bottom range of Z axis destination motion"
+#Constraint|TransformConstraint.use_motion_extrapolate -> use_motion_extrapolate: boolean "Extrapolate ranges"
+#+ * Context.area -> area: pointer, "(read-only)"
+#+ * Context.main -> main: pointer, "(read-only)"
+#+ * Context.mode -> mode: enum, "(read-only)"
+#+ * Context.region -> region: pointer, "(read-only)"
+#+ * Context.region_data -> region_data: pointer, "(read-only)"
+#+ * Context.scene -> scene: pointer, "(read-only)"
+#+ * Context.screen -> screen: pointer, "(read-only)"
+#+ * Context.space_data -> space_data: pointer, "(read-only)"
+#+ * Context.tool_settings -> tool_settings: pointer, "(read-only)"
+#+ * Context.user_preferences -> user_preferences: pointer, "(read-only)"
+#+ * Context.window -> window: pointer, "(read-only)"
+ + * Context.manager -> wm: pointer, "(read-only)"
+#+ * Controller.name -> name: string "NO DESCRIPTION"
+#Controller.show_expanded -> show_expanded: boolean "Set controller expanded in the user interface"
+#Controller.states -> states: int "Set Controller state index (1 to 30)"
+#+ * Controller.type -> type: enum "NO DESCRIPTION"
+#Controller.use_priority -> use_priority: boolean "Mark controller for execution before all non-marked controllers (good for startup scripts)"
+#+ * Controller|ExpressionController.expression -> expression: string "NO DESCRIPTION"
+#+ * Controller|PythonController.mode -> mode: enum "Python script type (textblock or module - faster)"
+#+ * Controller|PythonController.module -> module: string "Module name and function to run e.g. someModule.main. Internal texts and external python files can be used"
+#+ * Controller|PythonController.text -> text: pointer "Text datablock with the python script"
+#Controller|PythonController.use_debug -> use_debug: boolean "Continuously reload the module from disk for editing external modules without restarting"
+#+ * CurveMap.extend -> extend: enum, "(read-only) Extrapolate the curve or extend it horizontally"
+#+ * CurveMap.points -> points: collection, "(read-only)"
+#+ * CurveMapPoint.handle_type -> handle_type: enum, "(read-only) Curve interpolation at this point: bezier or vector"
+#+ * CurveMapPoint.location -> location: float[2], "(read-only) X/Y coordinates of the curve point"
+#+ * CurveMapPoint.select -> select: boolean "Selection state of the curve point"
+#+ * CurveMapping.black_level -> black_level: float[3] "For RGB curves, the color that black is mapped to"
+#+ * CurveMapping.clip_max_x -> clip_max_x: float "NO DESCRIPTION"
+#+ * CurveMapping.clip_max_y -> clip_max_y: float "NO DESCRIPTION"
+#+ * CurveMapping.clip_min_x -> clip_min_x: float "NO DESCRIPTION"
+#+ * CurveMapping.clip_min_y -> clip_min_y: float "NO DESCRIPTION"
+#+ * CurveMapping.curves -> curves: collection, "(read-only)"
+#CurveMapping.use_clip -> use_clip: boolean "Force the curve view to fit a defined boundary"
+#+ * CurveMapping.white_level -> white_level: float[3] "For RGB curves, the color that white is mapped to"
+#+ * CurveSplines.active -> active: pointer "Active curve spline"
+#DopeSheet.filter_group -> filter_group: pointer "Group that included Object should be a member of"
+#DopeSheet.show_armatures -> show_armatures: boolean "Include visualization of Armature related Animation data"
+#DopeSheet.show_cameras -> show_cameras: boolean "Include visualization of Camera related Animation data"
+#DopeSheet.show_curves -> show_curves: boolean "Include visualization of Curve related Animation data"
+#DopeSheet.show_expanded_summary -> show_expanded_summary: boolean "Collapse summary when shown, so all other channels get hidden. (DopeSheet Editors Only)"
+#DopeSheet.show_hidden -> show_hidden: boolean "Include channels from objects/bone that arent visible"
+#DopeSheet.show_lamps -> show_lamps: boolean "Include visualization of Lamp related Animation data"
+#DopeSheet.show_materials -> show_materials: boolean "Include visualization of Material related Animation data"
+#DopeSheet.show_meshes -> show_meshes: boolean "Include visualization of Mesh related Animation data"
+#DopeSheet.show_metaballs -> show_metaballs: boolean "Include visualization of Metaball related Animation data"
+#DopeSheet.show_missing_nla -> show_missing_nla: boolean "Include Animation Data blocks with no NLA data. (NLA Editor only)"
+#DopeSheet.show_nodes -> show_nodes: boolean "Include visualization of Node related Animation data"
+#DopeSheet.show_only_group_objects -> show_only_group_objects: boolean "Only include channels from Objects in the specified Group"
+#DopeSheet.show_only_selected -> show_only_selected: boolean "Only include channels relating to selected objects and data"
+#DopeSheet.show_particles -> show_particles: boolean "Include visualization of Particle related Animation data"
+#DopeSheet.show_scenes -> show_scenes: boolean "Include visualization of Scene related Animation data"
+#DopeSheet.show_shapekeys -> show_shapekeys: boolean "Include visualization of ShapeKey related Animation data"
+#DopeSheet.show_summary -> show_summary: boolean "Display an additional summary line. (DopeSheet Editors only)"
+#DopeSheet.show_textures -> show_textures: boolean "Include visualization of Texture related Animation data"
+#DopeSheet.show_transforms -> show_transforms: boolean "Include visualization of Object-level Animation data (mostly Transforms)"
+#DopeSheet.show_worlds -> show_worlds: boolean "Include visualization of World related Animation data"
+#+ * DopeSheet.source -> source: pointer, "(read-only) ID-Block representing source data, currently ID_SCE (for Dopesheet), and ID_SC (for Grease Pencil)"
+#+ * Driver.expression -> expression: string "Expression to use for Scripted Expression"
+#Driver.is_valid -> is_valid: boolean "Driver could not be evaluated in past, so should be skipped"
+#+ * Driver.show_debug_info -> show_debug_info: boolean "Show intermediate values for the driver calculations to allow debugging of drivers"
+#+ * Driver.type -> type: enum "Driver type"
+#+ * Driver.variables -> variables: collection, "(read-only) Properties acting as inputs for this driver"
+#+ * DriverTarget.bone_target -> bone_target: string "Name of PoseBone to use as target"
+#+ * DriverTarget.data_path -> data_path: string "RNA Path (from ID-block) to property used"
+#+ * DriverTarget.id -> id: pointer "ID-block that the specific property used can be found from (id_type property must be set first)"
+#+ * DriverTarget.id_type -> id_type: enum "Type of ID-block that can be used"
+#+ * DriverTarget.transform_type -> transform_type: enum "Driver variable type"
+#DriverTarget.use_local_space_transform -> use_local_space_transform: boolean "Use transforms in Local Space (as opposed to the worldspace default)"
+#+ * DriverVariable.name -> name: string "Name to use in scripted expressions/functions. (No spaces or dots are allowed. Also, must not start with a symbol or digit)"
+#+ * DriverVariable.targets -> targets: collection, "(read-only) Sources of input data for evaluating this variable"
+#+ * DriverVariable.type -> type: enum "Driver variable type"
+#+ * DupliObject.matrix -> matrix: float[16] "Object duplicate transformation matrix"
+#+ * DupliObject.matrix_original -> matrix_original: float[16] "The original matrix of this object before it was duplicated"
+#+ * DupliObject.object -> object: pointer, "(read-only) Object being duplicated"
+#+ * EditBone.bbone_in -> bbone_in: float "Length of first Bezier Handle (for B-Bones only)"
+#+ * EditBone.bbone_out -> bbone_out: float "Length of second Bezier Handle (for B-Bones only)"
+#+ * EditBone.bbone_segments -> bbone_segments: int "Number of subdivisions of bone (for B-Bones only)"
+#+ * EditBone.envelope_distance -> envelope_distance: float "Bone deformation distance (for Envelope deform only)"
+#+ * EditBone.envelope_weight -> envelope_weight: float "Bone deformation weight (for Envelope deform only)"
+#+ * EditBone.head -> head: float[3] "Location of head end of the bone"
+#+ * EditBone.head_radius -> head_radius: float "Radius of head of bone (for Envelope deform only)"
+#+ * EditBone.hide -> hide: boolean "Bone is not visible when in Edit Mode"
+#+ * EditBone.hide_select -> hide_select: boolean "Bone is able to be selected"
+#EditBone.layers -> layers: boolean[32] "Layers bone exists in"
+#+ * EditBone.lock -> lock: boolean "Bone is not able to be transformed when in Edit Mode"
+#+ * EditBone.matrix -> matrix: float[16], "(read-only) Read-only matrix calculated from the roll (armature space)"
+#+ * EditBone.name -> name: string "NO DESCRIPTION"
+#+ * EditBone.parent -> parent: pointer "Parent edit bone (in same Armature)"
+#+ * EditBone.roll -> roll: float "Bone rotation around head-tail axis"
+#+ * EditBone.select -> select: boolean "NO DESCRIPTION"
+#+ * EditBone.select_head -> select_head: boolean "NO DESCRIPTION"
+#+ * EditBone.select_tail -> select_tail: boolean "NO DESCRIPTION"
+#EditBone.show_wire -> show_wire: boolean "Bone is always drawn as Wireframe regardless of viewport draw mode. Useful for non-obstructive custom bone shapes"
+#+ * EditBone.tail -> tail: float[3] "Location of tail end of the bone"
+#+ * EditBone.tail_radius -> tail_radius: float "Radius of tail of bone (for Envelope deform only)"
+#EditBone.use_connect -> use_connect: boolean "When bone has a parent, bones head is struck to the parents tail"
+#EditBone.use_cyclic_offset -> use_cyclic_offset: boolean "When bone doesnt have a parent, it receives cyclic offset effects"
+#EditBone.use_deform -> use_deform: boolean "Bone does not deform any geometry"
+#EditBone.use_envelope_multiply -> use_envelope_multiply: boolean "When deforming bone, multiply effects of Vertex Group weights with Envelope influence"
+#EditBone.use_hinge -> use_hinge: boolean "Bone inherits rotation or scale from parent bone"
+#EditBone.use_inherit_scale -> use_inherit_scale: boolean "Bone inherits scaling from parent bone"
+#EditBone.use_local_location -> use_local_location: boolean "Bone location is set in local space"
+#+ * EffectorWeights.all -> all: float "All effectors weight"
+#EffectorWeights.apply_to_hair_growing -> apply_to_hair_growing: boolean "Use force fields when growing hair"
+#+ * EffectorWeights.boid -> boid: float "Boid effector weight"
+#+ * EffectorWeights.charge -> charge: float "Charge effector weight"
+#EffectorWeights.curve_guide -> curve_guide: float "Curve guide effector weight"
+#+ * EffectorWeights.drag -> drag: float "Drag effector weight"
+#+ * EffectorWeights.force -> force: float "Force effector weight"
+#+ * EffectorWeights.gravity -> gravity: float "Global gravity weight"
+#+ * EffectorWeights.group -> group: pointer "Limit effectors to this Group"
+#+ * EffectorWeights.harmonic -> harmonic: float "Harmonic effector weight"
+#+ * EffectorWeights.lennardjones -> lennardjones: float "Lennard-Jones effector weight"
+#+ * EffectorWeights.magnetic -> magnetic: float "Magnetic effector weight"
+#+ * EffectorWeights.texture -> texture: float "Texture effector weight"
+#+ * EffectorWeights.turbulence -> turbulence: float "Turbulence effector weight"
+#+ * EffectorWeights.vortex -> vortex: float "Vortex effector weight"
+#+ * EffectorWeights.wind -> wind: float "Wind effector weight"
+#+ * EnumPropertyItem.description -> description: string, "(read-only) Description of the items purpose"
+#+ * EnumPropertyItem.identifier -> identifier: string, "(read-only) Unique name used in the code and scripting"
+#+ * EnumPropertyItem.name -> name: string, "(read-only) Human readable name"
+#+ * EnumPropertyItem.value -> value: int, "(read-only) Value of the item"
+#+ * EnvironmentMap.clip_end -> clip_end: float "Objects further than this are not visible to map"
+#+ * EnvironmentMap.clip_start -> clip_start: float "Objects nearer than this are not visible to map"
+#+ * EnvironmentMap.depth -> depth: int "Number of times a map will be rendered recursively (mirror effects.)"
+#EnvironmentMap.layers_ignore -> layers_ignore: boolean[20] "Hide objects on these layers when generating the Environment Map"
+#+ * EnvironmentMap.mapping -> mapping: enum "NO DESCRIPTION"
+#+ * EnvironmentMap.resolution -> resolution: int "Pixel resolution of the rendered environment map"
+#+ * EnvironmentMap.source -> source: enum "NO DESCRIPTION"
+#+ * EnvironmentMap.viewpoint_object -> viewpoint_object: pointer "Object to use as the environment maps viewpoint location"
+#+ * EnvironmentMap.zoom -> zoom: float "NO DESCRIPTION"
+#+ * Event.ascii -> ascii: string, "(read-only) Single ASCII character for this event"
+ + * Event.alt -> is_pressed_alt: boolean, "(read-only) True when the Alt/Option key is held"
+ + * Event.oskey -> is_pressed_cmd: boolean, "(read-only) True when the Cmd key is held"
+ + * Event.ctrl -> is_pressed_ctrl: boolean, "(read-only) True when the Ctrl key is held"
+ + * Event.shift -> is_pressed_shift: boolean, "(read-only) True when the Shift key is held"
+#+ * Event.mouse_prev_x -> mouse_prev_x: int, "(read-only) The window relative vertical location of the mouse"
+#+ * Event.mouse_prev_y -> mouse_prev_y: int, "(read-only) The window relative horizontal location of the mouse"
+#+ * Event.mouse_region_x -> mouse_region_x: int, "(read-only) The region relative vertical location of the mouse"
+#+ * Event.mouse_region_y -> mouse_region_y: int, "(read-only) The region relative horizontal location of the mouse"
+#+ * Event.mouse_x -> mouse_x: int, "(read-only) The window relative vertical location of the mouse"
+#+ * Event.mouse_y -> mouse_y: int, "(read-only) The window relative horizontal location of the mouse"
+#+ * Event.type -> type: enum, "(read-only)"
+#+ * Event.value -> value: enum, "(read-only) The type of event, only applies to some"
+#+ * FCurve.array_index -> array_index: int "Index to the specific property affected by F-Curve if applicable"
+#+ * FCurve.color -> color: float[3] "Color of the F-Curve in the Graph Editor"
+#+ * FCurve.color_mode -> color_mode: enum "Method used to determine color of F-Curve in Graph Editor"
+#+ * FCurve.data_path -> data_path: string "RNA Path to property affected by F-Curve"
+#+ * FCurve.driver -> driver: pointer, "(read-only) Channel Driver (only set for Driver F-Curves)"
+#+ * FCurve.extrapolation -> extrapolation: enum "NO DESCRIPTION"
+#+ * FCurve.group -> group: pointer "Action Group that this F-Curve belongs to"
+#+ * FCurve.hide -> hide: boolean "F-Curve and its keyframes are hidden in the Graph Editor graphs"
+#+ * FCurve.is_valid -> is_valid: boolean "False when F-Curve could not be evaluated in past, so should be skipped when evaluating"
+#+ * FCurve.keyframe_points -> keyframe_points: collection, "(read-only) User-editable keyframes"
+#+ * FCurve.lock -> lock: boolean "F-Curves settings cannot be edited"
+#+ * FCurve.modifiers -> modifiers: collection, "(read-only) Modifiers affecting the shape of the F-Curve"
+#+ * FCurve.mute -> mute: boolean "F-Curve is not evaluated"
+#+ * FCurve.sampled_points -> sampled_points: collection, "(read-only) Sampled animation data"
+#+ * FCurve.select -> select: boolean "F-Curve is selected for editing"
+#+ * FCurve.use_auto_handle_clamp -> use_auto_handle_clamp: boolean "All auto-handles for F-Curve are clamped"
+#+ * FCurveModifiers.active -> active: pointer "Active F-Curve Modifier"
+#+ * FCurveSample.co -> co: float[2] "Point coordinates"
+#+ * FCurveSample.select -> select: boolean "Selection status"
+#REMOVE * FModifier.active -> active: boolean "F-Curve Modifier is the one being edited"
+#FModifier.is_valid -> is_valid: boolean, "(read-only) F-Curve Modifier has invalid settings and will not be evaluated"
+#+ * FModifier.mute -> mute: boolean "F-Curve Modifier will not be evaluated"
+#FModifier.show_expanded -> show_expanded: boolean "F-Curve Modifiers panel is expanded in UI"
+#+ * FModifier.type -> type: enum, "(read-only) F-Curve Modifier Type"
+#+ * FModifierEnvelopeControlPoint.frame -> frame: float "Frame this control-point occurs on"
+#FModifierEnvelopeControlPoint.max -> max: float "Upper bound of envelope at this control-point"
+#FModifierEnvelopeControlPoint.min -> min: float "Lower bound of envelope at this control-point"
+#FModifier|FModifierCycles.cycles_after -> cycles_after: float "Maximum number of cycles to allow after last keyframe. (0 = infinite)"
+#FModifier|FModifierCycles.cycles_before -> cycles_before: float "Maximum number of cycles to allow before first keyframe. (0 = infinite)"
+#FModifier|FModifierCycles.mode_after -> mode_after: enum "Cycling mode to use after last keyframe"
+#FModifier|FModifierCycles.mode_before -> mode_before: enum "Cycling mode to use before first keyframe"
+#+ * FModifier|FModifierEnvelope.control_points -> control_points: collection, "(read-only) Control points defining the shape of the envelope"
+#FModifier|FModifierEnvelope.default_max -> default_max: float "Upper distance from Reference Value for 1:1 default influence"
+#FModifier|FModifierEnvelope.default_min -> default_min: float "Lower distance from Reference Value for 1:1 default influence"
+#+ * FModifier|FModifierEnvelope.reference_value -> reference_value: float "Value that envelopes influence is centered around / based on"
+#+ * FModifier|FModifierFunctionGenerator.amplitude -> amplitude: float "Scale factor determining the maximum/minimum values"
+#+ * FModifier|FModifierFunctionGenerator.function_type -> function_type: enum "Type of built-in function to use"
+#+ * FModifier|FModifierFunctionGenerator.phase_multiplier -> phase_multiplier: float "Scale factor determining the speed of the function"
+#+ * FModifier|FModifierFunctionGenerator.phase_offset -> phase_offset: float "Constant factor to offset time by for function"
+#FModifier|FModifierFunctionGenerator.use_additive -> use_additive: boolean "Values generated by this modifier are applied on top of the existing values instead of overwriting them"
+#+ * FModifier|FModifierFunctionGenerator.value_offset -> value_offset: float "Constant factor to offset values by"
+#+ * FModifier|FModifierGenerator.coefficients -> coefficients: float[32] "Coefficients for x (starting from lowest power of x^0)"
+#+ * FModifier|FModifierGenerator.mode -> mode: enum "Type of generator to use"
+#+ * FModifier|FModifierGenerator.poly_order -> poly_order: int "The highest power of x for this polynomial. (number of coefficients - 1)"
+#FModifier|FModifierGenerator.use_additive -> use_additive: boolean "Values generated by this modifier are applied on top of the existing values instead of overwriting them"
+#FModifier|FModifierLimits.max_x -> max_x: float "Highest X value to allow"
+#FModifier|FModifierLimits.max_y -> max_y: float "Highest Y value to allow"
+#FModifier|FModifierLimits.min_x -> min_x: float "Lowest X value to allow"
+#FModifier|FModifierLimits.min_y -> min_y: float "Lowest Y value to allow"
+#FModifier|FModifierLimits.use_max_x -> use_max_x: boolean "Use the maximum X value"
+#FModifier|FModifierLimits.use_max_y -> use_max_y: boolean "Use the maximum Y value"
+#FModifier|FModifierLimits.use_min_x -> use_min_x: boolean "Use the minimum X value"
+#FModifier|FModifierLimits.use_min_y -> use_min_y: boolean "Use the minimum Y value"
+#FModifier|FModifierNoise.blend_type -> blend_type: enum "Method of modifying the existing F-Curve"
+#+ * FModifier|FModifierNoise.depth -> depth: int "Amount of fine level detail present in the noise"
+#+ * FModifier|FModifierNoise.phase -> phase: float "A random seed for the noise effect"
+#FModifier|FModifierNoise.scale -> scale: float "Scaling (in time) of the noise"
+#+ * FModifier|FModifierNoise.strength -> strength: float "Amplitude of the noise - the amount that it modifies the underlying curve"
+#+ * FModifier|FModifierStepped.frame_end -> frame_end: float "Frame that modifiers influence ends (if applicable)"
+#FModifier|FModifierStepped.frame_offset -> frame_offset: float "Reference number of frames before frames get held. Use to get hold for 1-3 vs 5-7 holding patterns"
+#+ * FModifier|FModifierStepped.frame_start -> frame_start: float "Frame that modifiers influence starts (if applicable)"
+#FModifier|FModifierStepped.frame_step -> frame_step: float "Number of frames to hold each value"
+#+ * FModifier|FModifierStepped.use_frame_end -> use_frame_end: boolean "Restrict modifier to only act before its end frame"
+#+ * FModifier|FModifierStepped.use_frame_start -> use_frame_start: boolean "Restrict modifier to only act after its start frame"
+#FieldSettings.apply_to_location -> apply_to_location: boolean "Effect particles location"
+#FieldSettings.apply_to_rotation -> apply_to_rotation: boolean "Effect particles dynamic rotation"
+#FieldSettings.distance_max -> distance_max: float "Maximum distance for the field to work"
+#FieldSettings.distance_min -> distance_min: float "Minimum distance for the fields fall-off"
+#+ * FieldSettings.falloff_power -> falloff_power: float "Falloff power (real gravitational falloff = 2)"
+#+ * FieldSettings.falloff_type -> falloff_type: enum "Fall-off shape"
+#+ * FieldSettings.flow -> flow: float "Convert effector force into air flow velocity"
+#+ * FieldSettings.guide_clump_amount -> guide_clump_amount: float "Amount of clumping"
+#+ * FieldSettings.guide_clump_shape -> guide_clump_shape: float "Shape of clumping"
+#+ * FieldSettings.guide_free -> guide_free: float "Guide-free time from particle lifes end"
+#+ * FieldSettings.guide_kink_amplitude -> guide_kink_amplitude: float "The amplitude of the offset"
+#+ * FieldSettings.guide_kink_axis -> guide_kink_axis: enum "Which axis to use for offset"
+#+ * FieldSettings.guide_kink_frequency -> guide_kink_frequency: float "The frequency of the offset (1/total length)"
+#+ * FieldSettings.guide_kink_shape -> guide_kink_shape: float "Adjust the offset to the beginning/end"
+#+ * FieldSettings.guide_kink_type -> guide_kink_type: enum "Type of periodic offset on the curve"
+#+ * FieldSettings.guide_minimum -> guide_minimum: float "The distance from which particles are affected fully"
+#+ * FieldSettings.harmonic_damping -> harmonic_damping: float "Damping of the harmonic force"
+#+ * FieldSettings.inflow -> inflow: float "Inwards component of the vortex force"
+#+ * FieldSettings.linear_drag -> linear_drag: float "Drag component proportional to velocity"
+#+ * FieldSettings.noise -> noise: float "Noise of the force"
+#+ * FieldSettings.quadratic_drag -> quadratic_drag: float "Drag component proportional to the square of velocity"
+#+ * FieldSettings.radial_falloff -> radial_falloff: float "Radial falloff power (real gravitational falloff = 2)"
+#FieldSettings.radial_max -> radial_max: float "Maximum radial distance for the field to work"
+#FieldSettings.radial_min -> radial_min: float "Minimum radial distance for the fields fall-off"
+#+ * FieldSettings.rest_length -> rest_length: float "Rest length of the harmonic force"
+#+ * FieldSettings.seed -> seed: int "Seed of the noise"
+#+ * FieldSettings.shape -> shape: enum "Which direction is used to calculate the effector force"
+#+ * FieldSettings.size -> size: float "Size of the noise"
+#+ * FieldSettings.strength -> strength: float "Strength of force field"
+#+ * FieldSettings.texture -> texture: pointer "Texture to use as force"
+#+ * FieldSettings.texture_mode -> texture_mode: enum "How the texture effect is calculated (RGB & Curl need a RGB texture else Gradient will be used instead)"
+#+ * FieldSettings.texture_nabla -> texture_nabla: float "Defines size of derivative offset used for calculating gradient and curl"
+#+ * FieldSettings.type -> type: enum "Type of field"
+#FieldSettings.use_2d_force -> use_2d_force: boolean "Apply force only in 2d"
+#FieldSettings.use_absorption -> use_absorption: boolean "Force gets absorbed by collision objects"
+#FieldSettings.use_global_coords -> use_global_coords: boolean "Use effector/global coordinates for turbulence"
+#FieldSettings.use_guide_path_add -> use_guide_path_add: boolean "Based on distance/falloff it adds a portion of the entire path"
+#+ * FieldSettings.use_guide_path_weight -> use_guide_path_weight: boolean "Use curve weights to influence the particle influence along the curve"
+#+ * FieldSettings.use_max_distance -> use_max_distance: boolean "Use a maximum distance for the field to work"
+#+ * FieldSettings.use_min_distance -> use_min_distance: boolean "Use a minimum distance for the fields fall-off"
+#FieldSettings.use_multiple_springs -> use_multiple_springs: boolean "Every point is effected by multiple springs"
+#FieldSettings.use_object_coords -> use_object_coords: boolean "Use object/global coordinates for texture"
+#+ * FieldSettings.use_radial_max -> use_radial_max: boolean "Use a maximum radial distance for the field to work"
+#+ * FieldSettings.use_radial_min -> use_radial_min: boolean "Use a minimum radial distance for the fields fall-off"
+#FieldSettings.use_root_coords -> use_root_coords: boolean "Texture coordinates from root particle locations"
+#+ * FieldSettings.z_direction -> z_direction: enum "Effect in full or only positive/negative Z direction"
+#+ * FileSelectParams.directory -> directory: string "Directory displayed in the file browser"
+#FileSelectParams.display_type -> display_type: enum "Display mode for the file list"
+#FileSelectParams.filename -> filename: string "Active file in the file browser"
+#FileSelectParams.show_hidden -> show_hidden: boolean "Hide hidden dot files"
+#FileSelectParams.sort_method -> sort_method: enum "NO DESCRIPTION"
+#+ * FileSelectParams.title -> title: string, "(read-only) Title for the file browser"
+#FileSelectParams.use_filter -> use_filter: boolean "Enable filtering of files"
+#FileSelectParams.use_filter_blender -> use_filter_blender: boolean "Show .blend files"
+#FileSelectParams.use_filter_folder -> use_filter_folder: boolean "Show folders"
+#FileSelectParams.use_filter_font -> use_filter_font: boolean "Show font files"
+#FileSelectParams.use_filter_image -> use_filter_image: boolean "Show image files"
+#FileSelectParams.use_filter_movie -> use_filter_movie: boolean "Show movie files"
+#FileSelectParams.use_filter_script -> use_filter_script: boolean "Show script files"
+#FileSelectParams.use_filter_sound -> use_filter_sound: boolean "Show sound files"
+#FileSelectParams.use_filter_text -> use_filter_text: boolean "Show text files"
+#+ * FluidSettings.type -> type: enum "Type of participation in the fluid simulation"
+#+ * FluidSettings|ControlFluidSettings.attraction_radius -> attraction_radius: float "Specifies the force field radius around the control object"
+#+ * FluidSettings|ControlFluidSettings.attraction_strength -> attraction_strength: float "Force strength for directional attraction towards the control object"
+#+ * FluidSettings|ControlFluidSettings.end_time -> end_time: float "Specifies time when the control particles are deactivated"
+#+ * FluidSettings|ControlFluidSettings.quality -> quality: float "Specifies the quality which is used for object sampling. (higher = better but slower)"
+#+ * FluidSettings|ControlFluidSettings.start_time -> start_time: float "Specifies time when the control particles are activated"
+#FluidSettings|ControlFluidSettings.use -> use: boolean "Object contributes to the fluid simulation"
+#FluidSettings|ControlFluidSettings.use_reverse_frames -> use_reverse_frames: boolean "Reverse control object movement"
+#+ * FluidSettings|ControlFluidSettings.velocity_radius -> velocity_radius: float "Specifies the force field radius around the control object"
+#+ * FluidSettings|ControlFluidSettings.velocity_strength -> velocity_strength: float "Force strength of how much of the control objects velocity is influencing the fluid velocity"
+#+ * FluidSettings|DomainFluidSettings.compressibility -> compressibility: float "Allowed compressibility due to gravitational force for standing fluid. (directly affects simulation step size)"
+#+ * FluidSettings|DomainFluidSettings.end_time -> end_time: float "Simulation time of the last blender frame (in seconds)"
+#FluidSettings|DomainFluidSettings.filepath -> filepath: string "Directory (and/or filename prefix) to store baked fluid simulation files in"
+#+ * FluidSettings|DomainFluidSettings.generate_particles -> generate_particles: float "Amount of particles to generate (0=off, 1=normal, >1=more)"
+#+ * FluidSettings|DomainFluidSettings.gravity -> gravity: float[3] "Gravity in X, Y and Z direction"
+#+ * FluidSettings|DomainFluidSettings.grid_levels -> grid_levels: int "Number of coarsened grids to use (-1 for automatic)"
+#+ * FluidSettings|DomainFluidSettings.memory_estimate -> memory_estimate: string, "(read-only) Estimated amount of memory needed for baking the domain"
+#+ * FluidSettings|DomainFluidSettings.partial_slip_factor -> partial_slip_factor: float "Amount of mixing between no- and free-slip, 0 is no slip and 1 is free slip"
+#+ * FluidSettings|DomainFluidSettings.preview_resolution -> preview_resolution: int "Preview resolution in X,Y and Z direction"
+#+ * FluidSettings|DomainFluidSettings.render_display_mode -> render_display_mode: enum "How to display the mesh for rendering"
+#+ * FluidSettings|DomainFluidSettings.resolution -> resolution: int "Domain resolution in X,Y and Z direction"
+#FluidSettings|DomainFluidSettings.simulation_scale -> simulation_scale: float "Size of the simulation domain in metres"
+#+ * FluidSettings|DomainFluidSettings.slip_type -> slip_type: enum "NO DESCRIPTION"
+#+ * FluidSettings|DomainFluidSettings.start_time -> start_time: float "Simulation time of the first blender frame (in seconds)"
+#FluidSettings|DomainFluidSettings.surface_smooth -> surface_smooth: float "Amount of surface smoothing. A value of 0 is off, 1 is normal smoothing and more than 1 is extra smoothing"
+#+ * FluidSettings|DomainFluidSettings.surface_subdivisions -> surface_subdivisions: int "Number of isosurface subdivisions. This is necessary for the inclusion of particles into the surface generation. Warning - can lead to longer computation times!"
+#+ * FluidSettings|DomainFluidSettings.tracer_particles -> tracer_particles: int "Number of tracer particles to generate"
+#FluidSettings|DomainFluidSettings.use_reverse_frames -> use_reverse_frames: boolean "Reverse fluid frames"
+#FluidSettings|DomainFluidSettings.use_speed_vectors -> use_speed_vectors: boolean "Generate speed vectors for vector blur"
+#FluidSettings|DomainFluidSettings.use_time_override -> use_time_override: boolean "Use a custom start and end time (in seconds) instead of the scenes timeline"
+#+ * FluidSettings|DomainFluidSettings.viewport_display_mode -> viewport_display_mode: enum "How to display the mesh in the viewport"
+#+ * FluidSettings|DomainFluidSettings.viscosity_base -> viscosity_base: float "Viscosity setting: value that is multiplied by 10 to the power of (exponent*-1)"
+#+ * FluidSettings|DomainFluidSettings.viscosity_exponent -> viscosity_exponent: int "Negative exponent for the viscosity value (to simplify entering small values e.g. 5*10^-6.)"
+#+ * FluidSettings|DomainFluidSettings.viscosity_preset -> viscosity_preset: enum "Set viscosity of the fluid to a preset value, or use manual input"
+#+ * FluidSettings|FluidFluidSettings.initial_velocity -> initial_velocity: float[3] "Initial velocity of fluid"
+#FluidSettings|FluidFluidSettings.use -> use: boolean "Object contributes to the fluid simulation"
+#FluidSettings|FluidFluidSettings.use_animated_mesh -> use_animated_mesh: boolean "Export this mesh as an animated one. Slower, only use if really necessary (e.g. armatures or parented objects), animated pos/rot/scale IPOs do not require it"
+#+ * FluidSettings|FluidFluidSettings.volume_initialization -> volume_initialization: enum "Volume initialization type"
+#+ * FluidSettings|InflowFluidSettings.inflow_velocity -> inflow_velocity: float[3] "Initial velocity of fluid"
+#FluidSettings|InflowFluidSettings.use -> use: boolean "Object contributes to the fluid simulation"
+#FluidSettings|InflowFluidSettings.use_animated_mesh -> use_animated_mesh: boolean "Export this mesh as an animated one. Slower, only use if really necessary (e.g. armatures or parented objects), animated pos/rot/scale IPOs do not require it"
+#FluidSettings|InflowFluidSettings.use_local_coords -> use_local_coords: boolean "Use local coordinates for inflow. (e.g. for rotating objects)"
+#+ * FluidSettings|InflowFluidSettings.volume_initialization -> volume_initialization: enum "Volume initialization type"
+#+ * FluidSettings|ObstacleFluidSettings.impact_factor -> impact_factor: float "This is an unphysical value for moving objects - it controls the impact an obstacle has on the fluid, =0 behaves a bit like outflow (deleting fluid), =1 is default, while >1 results in high forces. Can be used to tweak total mass"
+#+ * FluidSettings|ObstacleFluidSettings.partial_slip_factor -> partial_slip_factor: float "Amount of mixing between no- and free-slip, 0 is no slip and 1 is free slip"
+#+ * FluidSettings|ObstacleFluidSettings.slip_type -> slip_type: enum "NO DESCRIPTION"
+#FluidSettings|ObstacleFluidSettings.use -> use: boolean "Object contributes to the fluid simulation"
+#FluidSettings|ObstacleFluidSettings.use_animated_mesh -> use_animated_mesh: boolean "Export this mesh as an animated one. Slower, only use if really necessary (e.g. armatures or parented objects), animated pos/rot/scale IPOs do not require it"
+#+ * FluidSettings|ObstacleFluidSettings.volume_initialization -> volume_initialization: enum "Volume initialization type"
+#FluidSettings|OutflowFluidSettings.use -> use: boolean "Object contributes to the fluid simulation"
+#FluidSettings|OutflowFluidSettings.use_animated_mesh -> use_animated_mesh: boolean "Export this mesh as an animated one. Slower, only use if really necessary (e.g. armatures or parented objects), animated pos/rot/scale IPOs do not require it"
+#+ * FluidSettings|OutflowFluidSettings.volume_initialization -> volume_initialization: enum "Volume initialization type"
+#+ * FluidSettings|ParticleFluidSettings.alpha_influence -> alpha_influence: float "Amount of particle alpha change, inverse of size influence: 0=off (all same alpha), 1=full. (large particles get lower alphas, smaller ones higher values)"
+#FluidSettings|ParticleFluidSettings.filepath -> filepath: string "Directory (and/or filename prefix) to store and load particles from"
+#+ * FluidSettings|ParticleFluidSettings.particle_influence -> particle_influence: float "Amount of particle size scaling: 0=off (all same size), 1=full (range 0.2-2.0), >1=stronger"
+#FluidSettings|ParticleFluidSettings.show_tracer -> show_tracer: boolean "Show tracer particles"
+#FluidSettings|ParticleFluidSettings.use_drops -> use_drops: boolean "Show drop particles"
+#FluidSettings|ParticleFluidSettings.use_floats -> use_floats: boolean "Show floating foam particles"
+#+ * Function.description -> description: string, "(read-only) Description of the Functions purpose"
+#+ * Function.identifier -> identifier: string, "(read-only) Unique name used in the code and scripting"
+#Function.is_registered -> is_registered: boolean, "(read-only) Function is registered as callback as part of type registration"
+#Function.is_registered_optional -> is_registered_optional: boolean, "(read-only) Function is optionally registered as callback part of type registration"
+#+ * Function.parameters -> parameters: collection, "(read-only) Parameters for the function"
+#Function.use_self -> use_self: boolean, "(read-only) Function does not pass its self as an argument (becomes a class method in python)"
+#+ * GPencilFrame.frame_number -> frame_number: int "The frame on which this sketch appears"
+#GPencilFrame.is_edited -> is_edited: boolean "Frame is being edited (painted on)"
+#+ * GPencilFrame.select -> select: boolean "Frame is selected for editing in the DopeSheet"
+#+ * GPencilFrame.strokes -> strokes: collection, "(read-only) Freehand curves defining the sketch on this frame"
+#+ * GPencilLayer.active -> active: boolean "Set active layer for editing"
+#+ * GPencilLayer.active_frame -> active_frame: pointer, "(read-only) Frame currently being displayed for this layer"
+#GPencilLayer.alpha -> alpha: float "Layer Opacity"
+#+ * GPencilLayer.color -> color: float[3] "Color for all strokes in this layer"
+#+ * GPencilLayer.frames -> frames: collection, "(read-only) Sketches for this layer on different frames"
+#GPencilLayer.ghost_range_max -> ghost_range_max: int "Maximum number of frames on either side of the active frame to show (0 = show the first available sketch on either side)"
+#+ * GPencilLayer.hide -> hide: boolean "Set layer Visibility"
+#+ * GPencilLayer.info -> info: string "Layer name"
+#GPencilLayer.line_width -> line_width: int "Thickness of strokes (in pixels)"
+#+ * GPencilLayer.lock -> lock: boolean "Protect layer from further editing and/or frame changes"
+#GPencilLayer.lock_frame -> lock_frame: boolean "Lock current frame displayed by layer"
+#+ * GPencilLayer.select -> select: boolean "Layer is selected for editing in the DopeSheet"
+#+ * GPencilLayer.show_points -> show_points: boolean "Draw the points which make up the strokes (for debugging purposes)"
+#+ * GPencilLayer.use_onion_skinning -> use_onion_skinning: boolean "Ghost frames on either side of frame"
+#+ * GPencilStroke.points -> points: collection, "(read-only) Stroke data points"
+#+ * GPencilStrokePoint.co -> co: float[3] "NO DESCRIPTION"
+#+ * GPencilStrokePoint.pressure -> pressure: float "Pressure of tablet at point when drawing it"
+#+ * GameObjectSettings.actuators -> actuators: collection, "(read-only) Game engine actuators to act on events"
+#GameObjectSettings.collision_bounds_type -> collision_bounds_type: enum "Selects the collision type"
+#+ * GameObjectSettings.collision_margin -> collision_margin: float "Extra margin around object for collision detection, small amount required for stability"
+#+ * GameObjectSettings.controllers -> controllers: collection, "(read-only) Game engine controllers to process events, connecting sensor to actuators"
+#+ * GameObjectSettings.damping -> damping: float "General movement damping"
+#+ * GameObjectSettings.form_factor -> form_factor: float "Form factor scales the inertia tensor"
+#+ * GameObjectSettings.friction_coefficients -> friction_coefficients: float[3] "Relative friction coefficient in the in the X, Y and Z directions, when anisotropic friction is enabled"
+#GameObjectSettings.lock_location_x -> lock_location_x: boolean "Disable simulation of linear motion along the X axis"
+#GameObjectSettings.lock_location_y -> lock_location_y: boolean "Disable simulation of linear motion along the Y axis"
+#GameObjectSettings.lock_location_z -> lock_location_z: boolean "Disable simulation of linear motion along the Z axis"
+#GameObjectSettings.lock_rotation_x -> lock_rotation_x: boolean "Disable simulation of angular motion along the X axis"
+#GameObjectSettings.lock_rotation_y -> lock_rotation_y: boolean "Disable simulation of angular motion along the Y axis"
+#GameObjectSettings.lock_rotation_z -> lock_rotation_z: boolean "Disable simulation of angular motion along the Z axis"
+#+ * GameObjectSettings.mass -> mass: float "Mass of the object"
+#+ * GameObjectSettings.physics_type -> physics_type: enum "Selects the type of physical representation"
+#+ * GameObjectSettings.properties -> properties: collection, "(read-only) Game engine properties"
+#+ * GameObjectSettings.radius -> radius: float "Radius of bounding sphere and material physics"
+#+ * GameObjectSettings.rotation_damping -> rotation_damping: float "General rotation damping"
+#+ * GameObjectSettings.sensors -> sensors: collection, "(read-only) Game engine sensor to detect events"
+#+ * GameObjectSettings.show_actuators -> show_actuators: boolean "Shows actuators for this object in the user interface"
+#+ * GameObjectSettings.show_controllers -> show_controllers: boolean "Shows controllers for this object in the user interface"
+#GameObjectSettings.show_debug_state -> show_debug_state: boolean "Print state debug info in the game engine"
+#+ * GameObjectSettings.show_sensors -> show_sensors: boolean "Shows sensors for this object in the user interface"
+#+ * GameObjectSettings.show_state_panel -> show_state_panel: boolean "Show state panel"
+#+ * GameObjectSettings.soft_body -> soft_body: pointer, "(read-only) Settings for Bullet soft body simulation"
+#GameObjectSettings.states_initial -> states_initial: boolean[30] "Initial state when the game starts"
+#GameObjectSettings.states_visible -> states_visible: boolean[30] "State determining which controllers are displayed"
+#+ * GameObjectSettings.use_activity_culling -> use_activity_culling: boolean "Disable simulation of angular motion along the Z axis"
+#GameObjectSettings.use_actor -> use_actor: boolean "Object is detected by the Near and Radar sensor"
+#GameObjectSettings.use_all_states -> use_all_states: boolean "Set all state bits"
+#GameObjectSettings.use_anisotropic_friction -> use_anisotropic_friction: boolean "Enable anisotropic friction"
+#+ * GameObjectSettings.use_collision_bounds -> use_collision_bounds: boolean "Specify a collision bounds type other than the default"
+#GameObjectSettings.use_collision_compound -> use_collision_compound: boolean "Add children to form a compound collision object"
+#GameObjectSettings.use_ghost -> use_ghost: boolean "Object does not restitute collisions, like a ghost"
+#GameObjectSettings.use_material_physics -> use_material_physics: boolean "Use physics settings in materials"
+#GameObjectSettings.use_rotate_from_normal -> use_rotate_from_normal: boolean "Use face normal to rotate object, so that it points away from the surface"
+#GameObjectSettings.use_sleep -> use_sleep: boolean "Disable auto (de)activation in physics simulation"
+#GameObjectSettings.used_states -> used_states: boolean[30], "(read-only) States which are being used by controllers"
+#GameObjectSettings.velocity_max -> velocity_max: float "Clamp velocity to this maximum speed"
+#GameObjectSettings.velocity_min -> velocity_min: float "Clamp velocity to this minimum speed (except when totally still)"
+#+ * GameProperty.name -> name: string "Available as GameObject attributes in the game engines python API"
+#GameProperty.show_debug -> show_debug: boolean "Print debug information for this property"
+#+ * GameProperty.type -> type: enum "NO DESCRIPTION"
+#+ * GameProperty|GameBooleanProperty.value -> value: boolean "Property value"
+#+ * GameProperty|GameFloatProperty.value -> value: float "Property value"
+#+ * GameProperty|GameIntProperty.value -> value: int "Property value"
+#+ * GameProperty|GameStringProperty.value -> value: string "Property value"
+#+ * GameProperty|GameTimerProperty.value -> value: float "Property value"
+#+ * GameSoftBodySettings.cluster_iterations -> cluster_iterations: int "Specify the number of cluster iterations"
+#GameSoftBodySettings.collision_margin -> collision_margin: float "Collision margin for soft body. Small value makes the algorithm unstable"
+#+ * GameSoftBodySettings.dynamic_friction -> dynamic_friction: float "Dynamic Friction"
+#GameSoftBodySettings.linear_stiffness -> linear_stiffness: float "Linear stiffness of the soft body links"
+#GameSoftBodySettings.location_iterations -> location_iterations: int "Position solver iterations"
+#GameSoftBodySettings.shape_threshold -> shape_threshold: float "Shape matching threshold"
+#GameSoftBodySettings.use_bending_constraints -> use_bending_constraints: boolean "Enable bending constraints"
+#GameSoftBodySettings.use_cluster_rigid_to_softbody -> use_cluster_rigid_to_softbody: boolean "Enable cluster collision between soft and rigid body"
+#GameSoftBodySettings.use_cluster_soft_to_softbody -> use_cluster_soft_to_softbody: boolean "Enable cluster collision between soft and soft body"
+#GameSoftBodySettings.use_shape_match -> use_shape_match: boolean "Enable soft body shape matching goal"
+#GameSoftBodySettings.weld_threshold -> weld_threshold: float "Welding threshold: distance between nearby vertices to be considered equal => set to 0.0 to disable welding test and speed up scene loading (ok if the mesh has no duplicates)"
+#+ * Header.bl_idname -> bl_idname: string "If this is set, the header gets a custom ID, otherwise it takes the name of the class used to define the panel. For example, if the class name is OBJECT_HT_hello, and bl_idname is not set by the script, then bl_idname = OBJECT_HT_hello"
+#+ * Header.bl_space_type -> bl_space_type: enum "The space where the header is going to be used in."
+#+ * Header.layout -> layout: pointer, "(read-only) Defines the structure of the header in the UI."
+#+ * Histogram.mode -> mode: enum "Channels to display when drawing the histogram"
+#+ * ID.library -> library: pointer, "(read-only) Library file the datablock is linked from"
+#+ * ID.name -> name: string "Unique datablock ID name"
+#+ * ID.tag -> tag: boolean "Tools can use this to tag data, (initial state is undefined)"
+#ID.use_fake_user -> use_fake_user: boolean "Saves this datablock even if it has no users"
+#+ * ID.users -> users: int, "(read-only) Number of times this datablock is referenced"
+#+ * IDProperty.collection -> collection: collection, "(read-only)"
+#+ * IDProperty.double -> double: float "NO DESCRIPTION"
+#+ * IDProperty.double_array -> double_array: float[1] "NO DESCRIPTION"
+#+ * IDProperty.float -> float: float "NO DESCRIPTION"
+#+ * IDProperty.float_array -> float_array: float[1] "NO DESCRIPTION"
+#+ * IDProperty.group -> group: pointer, "(read-only)"
+#+ * IDProperty.int -> int: int "NO DESCRIPTION"
+#+ * IDProperty.int_array -> int_array: int[1] "NO DESCRIPTION"
+#+ * IDProperty.string -> string: string "NO DESCRIPTION"
+#+ * IDPropertyGroup.name -> name: string "Unique name used in the code and scripting"
+#+ * IDPropertyGroup|NetRenderJob.name -> name: string "NO DESCRIPTION"
+#+ * IDPropertyGroup|NetRenderSettings.active_blacklisted_slave_index -> active_blacklisted_slave_index: int "NO DESCRIPTION"
+#+ * IDPropertyGroup|NetRenderSettings.active_job_index -> active_job_index: int "NO DESCRIPTION"
+#+ * IDPropertyGroup|NetRenderSettings.active_slave_index -> active_slave_index: int "NO DESCRIPTION"
+#+ * IDPropertyGroup|NetRenderSettings.chunks -> chunks: int "Number of frame to dispatch to each slave in one chunk"
+#+ * IDPropertyGroup|NetRenderSettings.job_category -> job_category: string "Category of the job"
+#+ * IDPropertyGroup|NetRenderSettings.job_id -> job_id: string "id of the last sent render job"
+#+ * IDPropertyGroup|NetRenderSettings.job_name -> job_name: string "Name of the job"
+#+ * IDPropertyGroup|NetRenderSettings.jobs -> jobs: collection, "(read-only)"
+#+ * IDPropertyGroup|NetRenderSettings.mode -> mode: enum "Mode of operation of this instance"
+#+ * IDPropertyGroup|NetRenderSettings.path -> path: string "Path for temporary files"
+#+ * IDPropertyGroup|NetRenderSettings.priority -> priority: int "Priority of the job"
+#+ * IDPropertyGroup|NetRenderSettings.server_address -> server_address: string "IP or name of the master render server"
+#+ * IDPropertyGroup|NetRenderSettings.server_port -> server_port: int "port of the master render server"
+#+ * IDPropertyGroup|NetRenderSettings.slaves -> slaves: collection, "(read-only)"
+#+ * IDPropertyGroup|NetRenderSettings.slaves_blacklist -> slaves_blacklist: collection, "(read-only)"
+#IDPropertyGroup|NetRenderSettings.use_master_broadcast -> use_master_broadcast: boolean "broadcast master server address on local network"
+#IDPropertyGroup|NetRenderSettings.use_master_clear -> use_master_clear: boolean "delete saved files on exit"
+#IDPropertyGroup|NetRenderSettings.use_slave_clear -> use_slave_clear: boolean "delete downloaded files on exit"
+#IDPropertyGroup|NetRenderSettings.use_slave_output_log -> use_slave_output_log: boolean "Output render text log to console as well as sending it to the master"
+#IDPropertyGroup|NetRenderSettings.use_slave_thumb -> use_slave_thumb: boolean "Generate thumbnails on slaves instead of master"
+#+ * IDPropertyGroup|NetRenderSlave.name -> name: string "NO DESCRIPTION"
+#+ * IDPropertyGroup|OperatorFileListElement.name -> name: string "the name of a file or directory within a file list"
+#+ * IDPropertyGroup|OperatorMousePath.loc -> loc: float[2] "Mouse location"
+#+ * IDPropertyGroup|OperatorMousePath.time -> time: float "Time of mouse location"
+#+ * IDPropertyGroup|OperatorStrokeElement.location -> location: float[3] "NO DESCRIPTION"
+#+ * IDPropertyGroup|OperatorStrokeElement.mouse -> mouse: float[2] "NO DESCRIPTION"
+#+ * IDPropertyGroup|OperatorStrokeElement.pen_flip -> pen_flip: boolean "NO DESCRIPTION"
+#+ * IDPropertyGroup|OperatorStrokeElement.pressure -> pressure: float "Tablet pressure"
+#+ * IDPropertyGroup|OperatorStrokeElement.time -> time: float "NO DESCRIPTION"
+#+ * IDPropertyGroup|PoseTemplate.name -> name: string "NO DESCRIPTION"
+#+ * IDPropertyGroup|PoseTemplateSettings.active_template_index -> active_template_index: int "NO DESCRIPTION"
+#+ * IDPropertyGroup|PoseTemplateSettings.templates -> templates: collection, "(read-only)"
+#IDPropertyGroup|PoseTemplateSettings.use_generate_deform_rig -> use_generate_deform_rig: boolean "Create a copy of the metarig, constrainted by the generated rig"
+#+ * ID|Action.fcurves -> fcurves: collection, "(read-only) The individual F-Curves that make up the Action"
+#+ * ID|Action.groups -> groups: collection, "(read-only) Convenient groupings of F-Curves"
+#+ * ID|Action.pose_markers -> pose_markers: collection, "(read-only) Markers specific to this Action, for labeling poses"
+#+ * ID|Armature.animation_data -> animation_data: pointer, "(read-only) Animation data for this datablock"
+#+ * ID|Armature.bones -> bones: collection, "(read-only)"
+#ID|Armature.draw_type -> draw_type: enum "NO DESCRIPTION"
+#+ * ID|Armature.edit_bones -> edit_bones: collection, "(read-only)"
+#+ * ID|Armature.ghost_frame_end -> ghost_frame_end: int "End frame of range of Ghosts to display (not for Around Current Frame Onion-skinning method)"
+#+ * ID|Armature.ghost_frame_start -> ghost_frame_start: int "Starting frame of range of Ghosts to display (not for Around Current Frame Onion-skinning method)"
+#+ * ID|Armature.ghost_size -> ghost_size: int "Frame step for Ghosts (not for On Keyframes Onion-skinning method)"
+#+ * ID|Armature.ghost_step -> ghost_step: int "Number of frame steps on either side of current frame to show as ghosts (only for Around Current Frame Onion-skinning method)"
+#+ * ID|Armature.ghost_type -> ghost_type: enum "Method of Onion-skinning for active Action"
+#ID|Armature.layers -> layers: boolean[32] "Armature layer visibility"
+#ID|Armature.layers_protected -> layers_protected: boolean[32] "Protected layers in Proxy Instances are restored to Proxy settings on file reload and undo"
+#+ * ID|Armature.pose_position -> pose_position: enum "Show armature in binding pose or final posed state"
+#ID|Armature.show_axes -> show_axes: boolean "Draw bone axes"
+#ID|Armature.show_bone_custom_shapes -> show_bone_custom_shapes: boolean "Draw bones with their custom shapes"
+#ID|Armature.show_group_colors -> show_group_colors: boolean "Draw bone group colors"
+#ID|Armature.show_names -> show_names: boolean "Draw bone names"
+#ID|Armature.show_only_ghost_selected -> show_only_ghost_selected: boolean "NO DESCRIPTION"
+#ID|Armature.use_auto_ik -> use_auto_ik: boolean "Add temporaral IK constraints while grabbing bones in Pose Mode"
+#ID|Armature.use_deform_delay -> use_deform_delay: boolean "Dont deform children when manipulating bones in Pose Mode"
+#ID|Armature.use_deform_envelopes -> use_deform_envelopes: boolean "Enable Bone Envelopes when defining deform"
+#ID|Armature.use_deform_preserve_volume -> use_deform_preserve_volume: boolean "Enable deform rotation with Quaternions"
+#ID|Armature.use_deform_vertex_groups -> use_deform_vertex_groups: boolean "Enable Vertex Groups when defining deform"
+#ID|Armature.use_mirror_x -> use_mirror_x: boolean "Apply changes to matching bone on opposite side of X-Axis"
+#ID|Brush.auto_smooth_factor -> auto_smooth_factor: float "Amount of smoothing to automatically apply to each stroke"
+#+ * ID|Brush.blend -> blend: enum "Brush blending mode"
+#+ * ID|Brush.clone_alpha -> clone_alpha: float "Opacity of clone image display"
+#+ * ID|Brush.clone_image -> clone_image: pointer "Image for clone tool"
+#+ * ID|Brush.clone_offset -> clone_offset: float[2] "NO DESCRIPTION"
+#+ * ID|Brush.color -> color: float[3] "NO DESCRIPTION"
+#+ * ID|Brush.crease_pinch_factor -> crease_pinch_factor: float "How much the crease brush pinches"
+#ID|Brush.cursor_color_add -> cursor_color_add: float[3] "Color of cursor when adding"
+#ID|Brush.cursor_color_subtract -> cursor_color_subtract: float[3] "Color of cursor when subtracting"
+#+ * ID|Brush.curve -> curve: pointer, "(read-only) Editable falloff curve"
+#+ * ID|Brush.direction -> direction: enum "NO DESCRIPTION"
+#+ * ID|Brush.icon_filepath -> icon_filepath: string "File path to brush icon"
+#+ * ID|Brush.imagepaint_tool -> imagepaint_tool: enum "NO DESCRIPTION"
+#+ * ID|Brush.jitter -> jitter: float "Jitter the position of the brush while painting"
+#+ * ID|Brush.normal_weight -> normal_weight: float "How much grab will pull vertexes out of surface during a grab"
+#+ * ID|Brush.plane_offset -> plane_offset: float "Adjusts plane on which the brush acts towards or away from the object surface"
+#+ * ID|Brush.plane_trim -> plane_trim: float "If a vertex is further from offset plane than this then it is not affected"
+#+ * ID|Brush.rate -> rate: float "Interval between paints for Airbrush"
+#+ * ID|Brush.sculpt_plane -> sculpt_plane: enum "NO DESCRIPTION"
+#+ * ID|Brush.sculpt_tool -> sculpt_tool: enum "NO DESCRIPTION"
+#+ * ID|Brush.size -> size: int "Radius of the brush in pixels"
+#+ * ID|Brush.smooth_stroke_factor -> smooth_stroke_factor: float "Higher values give a smoother stroke"
+#+ * ID|Brush.smooth_stroke_radius -> smooth_stroke_radius: int "Minimum distance from last point before stroke continues"
+#ID|Brush.spacing -> spacing: int "Spacing between brush daubs as a percentage of brush diameter"
+#+ * ID|Brush.strength -> strength: float "How powerful the effect of the brush is when applied"
+#+ * ID|Brush.stroke_method -> stroke_method: enum "NO DESCRIPTION"
+#+ * ID|Brush.texture -> texture: pointer "NO DESCRIPTION"
+#ID|Brush.texture_angle_source_no_random -> texture_angle_source_no_random: enum "NO DESCRIPTION"
+#ID|Brush.texture_angle_source_random -> texture_angle_source_random: enum "NO DESCRIPTION"
+#+ * ID|Brush.texture_overlay_alpha -> texture_overlay_alpha: int "NO DESCRIPTION"
+#+ * ID|Brush.texture_sample_bias -> texture_sample_bias: float "Value added to texture samples"
+#+ * ID|Brush.texture_slot -> texture_slot: pointer, "(read-only)"
+#+ * ID|Brush.unprojected_radius -> unprojected_radius: float "Radius of brush in Blender units"
+#+ * ID|Brush.use_accumulate -> use_accumulate: boolean "Accumulate stroke dabs on top of each other"
+#+ * ID|Brush.use_adaptive_space -> use_adaptive_space: boolean "Space daubs according to surface orientation instead of screen space"
+#+ * ID|Brush.use_airbrush -> use_airbrush: boolean "Keep applying paint effect while holding mouse (spray)"
+#+ * ID|Brush.use_alpha -> use_alpha: boolean "When this is disabled, lock alpha while painting"
+#+ * ID|Brush.use_anchor -> use_anchor: boolean "Keep the brush anchored to the initial location"
+#+ * ID|Brush.use_custom_icon -> use_custom_icon: boolean "Set the brush icon from an image file"
+#ID|Brush.use_edge_to_edge -> use_edge_to_edge: boolean "Drag anchor brush from edge-to-edge"
+#+ * ID|Brush.use_frontface -> use_frontface: boolean "Brush only affects vertexes that face the viewer"
+#+ * ID|Brush.use_inverse_smooth_pressure -> use_inverse_smooth_pressure: boolean "Lighter pressure causes more smoothing to be applied"
+#+ * ID|Brush.use_locked_size -> use_locked_size: boolean "When locked brush stays same size relative to object; when unlocked brush size is given in pixels"
+#+ * ID|Brush.use_offset_pressure -> use_offset_pressure: boolean "Enable tablet pressure sensitivity for offset"
+#+ * ID|Brush.use_original_normal -> use_original_normal: boolean "When locked keep using normal of surface where stroke was initiated"
+#+ * ID|Brush.use_paint_sculpt -> use_paint_sculpt: boolean "Use this brush in sculpt mode"
+#+ * ID|Brush.use_paint_texture -> use_paint_texture: boolean "Use this brush in texture paint mode"
+#+ * ID|Brush.use_paint_vertex -> use_paint_vertex: boolean "Use this brush in vertex paint mode"
+#+ * ID|Brush.use_paint_weight -> use_paint_weight: boolean "Use this brush in weight paint mode"
+#+ * ID|Brush.use_persistent -> use_persistent: boolean "Sculpts on a persistent layer of the mesh"
+#+ * ID|Brush.use_plane_trim -> use_plane_trim: boolean "Enable Plane Trim"
+#ID|Brush.use_pressure_jitter -> use_pressure_jitter: boolean "Enable tablet pressure sensitivity for jitter"
+#ID|Brush.use_pressure_size -> use_pressure_size: boolean "Enable tablet pressure sensitivity for size"
+#ID|Brush.use_pressure_spacing -> use_pressure_spacing: boolean "Enable tablet pressure sensitivity for spacing"
+#ID|Brush.use_pressure_strength -> use_pressure_strength: boolean "Enable tablet pressure sensitivity for strength"
+#+ * ID|Brush.use_rake -> use_rake: boolean "Rotate the brush texture to match the stroke direction"
+#+ * ID|Brush.use_random_rotation -> use_random_rotation: boolean "Rotate the brush texture at random"
+#ID|Brush.use_restore_mesh -> use_restore_mesh: boolean "Allows a single dot to be carefully positioned"
+#+ * ID|Brush.use_smooth_stroke -> use_smooth_stroke: boolean "Brush lags behind mouse and follows a smoother path"
+#+ * ID|Brush.use_space -> use_space: boolean "Limit brush application to the distance specified by spacing"
+#+ * ID|Brush.use_space_atten -> use_space_atten: boolean "Automatically adjusts strength to give consistent results for different spacings"
+#+ * ID|Brush.use_texture_overlay -> use_texture_overlay: boolean "Show texture in viewport"
+#+ * ID|Brush.use_wrap -> use_wrap: boolean "Enable torus wrapping while painting"
+#+ * ID|Brush.vertexpaint_tool -> vertexpaint_tool: enum "NO DESCRIPTION"
+#+ * ID|Camera.angle -> angle: float "Perspective Camera lens field of view in degrees"
+#+ * ID|Camera.animation_data -> animation_data: pointer, "(read-only) Animation data for this datablock"
+#+ * ID|Camera.clip_end -> clip_end: float "Camera far clipping distance"
+#+ * ID|Camera.clip_start -> clip_start: float "Camera near clipping distance"
+#+ * ID|Camera.dof_distance -> dof_distance: float "Distance to the focus point for depth of field"
+#+ * ID|Camera.dof_object -> dof_object: pointer "Use this object to define the depth of field focal point"
+#+ * ID|Camera.draw_size -> draw_size: float "Apparent size of the Camera object in the 3D View"
+#+ * ID|Camera.lens -> lens: float "Perspective Camera lens value in millimeters"
+#+ * ID|Camera.lens_unit -> lens_unit: enum "Unit to edit lens in for the user interface"
+#+ * ID|Camera.ortho_scale -> ortho_scale: float "Orthographic Camera scale (similar to zoom)"
+#+ * ID|Camera.passepartout_alpha -> passepartout_alpha: float "Opacity (alpha) of the darkened overlay in Camera view"
+#+ * ID|Camera.shift_x -> shift_x: float "Perspective Camera horizontal shift"
+#+ * ID|Camera.shift_y -> shift_y: float "Perspective Camera vertical shift"
+#+ * ID|Camera.show_limits -> show_limits: boolean "Draw the clipping range and focus point on the camera"
+#+ * ID|Camera.show_mist -> show_mist: boolean "Draw a line from the Camera to indicate the mist area"
+#+ * ID|Camera.show_name -> show_name: boolean "Show the active Cameras name in Camera view"
+#+ * ID|Camera.show_passepartout -> show_passepartout: boolean "Show a darkened overlay outside the image area in Camera view"
+#+ * ID|Camera.show_title_safe -> show_title_safe: boolean "Show indicators for the title safe zone in Camera view"
+#+ * ID|Camera.type -> type: enum "Camera types"
+#ID|Camera.use_panorama -> use_panorama: boolean "Render the scene with a cylindrical camera for pseudo-fisheye lens effects"
+#+ * ID|Curve.animation_data -> animation_data: pointer, "(read-only) Animation data for this datablock"
+#+ * ID|Curve.bevel_depth -> bevel_depth: float "Bevel depth when not using a bevel object"
+#+ * ID|Curve.bevel_object -> bevel_object: pointer "Curve object name that defines the bevel shape"
+#+ * ID|Curve.bevel_resolution -> bevel_resolution: int "Bevel resolution when depth is non-zero and no specific bevel object has been defined"
+#+ * ID|Curve.dimensions -> dimensions: enum "Select 2D or 3D curve type"
+#+ * ID|Curve.eval_time -> eval_time: float "Parametric position along the length of the curve that Objects following it should be at. Position is evaluated by dividing by the Path Length value"
+#+ * ID|Curve.extrude -> extrude: float "Amount of curve extrusion when not using a bevel object"
+#+ * ID|Curve.materials -> materials: collection, "(read-only)"
+#ID|Curve.offset -> offset: float "Scale the original width (1.0) based on given factor"
+#ID|Curve.path_duration -> path_duration: int "The number of frames that are needed to traverse the path, defining the maximum value for the Evaluation Time setting"
+#+ * ID|Curve.render_resolution_u -> render_resolution_u: int "Surface resolution in U direction used while rendering. Zero skips this property"
+#+ * ID|Curve.render_resolution_v -> render_resolution_v: int "Surface resolution in V direction used while rendering. Zero skips this property"
+#+ * ID|Curve.resolution_u -> resolution_u: int "Surface resolution in U direction"
+#+ * ID|Curve.resolution_v -> resolution_v: int "Surface resolution in V direction"
+#+ * ID|Curve.shape_keys -> shape_keys: pointer, "(read-only)"
+#ID|Curve.show_handles -> show_handles: boolean "Display bezier handles in editmode"
+#ID|Curve.show_normal_face -> show_normal_face: boolean "Display 3D curve normals in editmode"
+#+ * ID|Curve.splines -> splines: collection, "(read-only) Collection of splines in this curve data object"
+#+ * ID|Curve.taper_object -> taper_object: pointer "Curve object name that defines the taper (width)"
+#ID|Curve.texspace_location -> texspace_location: float[3] "Texture space location"
+#+ * ID|Curve.texspace_size -> texspace_size: float[3] "Texture space size"
+#+ * ID|Curve.twist_mode -> twist_mode: enum "The type of tilt calculation for 3D Curves"
+#+ * ID|Curve.twist_smooth -> twist_smooth: float "Smoothing iteration for tangents"
+#ID|Curve.use_auto_texspace -> use_auto_texspace: boolean "Adjusts active objects texture space automatically when transforming object"
+#+ * ID|Curve.use_deform_bounds -> use_deform_bounds: boolean "Use the mesh bounds to clamp the deformation"
+#ID|Curve.use_fill_back -> use_fill_back: boolean "Draw filled back for extruded/beveled curves"
+#ID|Curve.use_fill_deform -> use_fill_deform: boolean "Fill curve after applying deformation"
+#ID|Curve.use_fill_front -> use_fill_front: boolean "Draw filled front for extruded/beveled curves"
+#ID|Curve.use_map_on_length -> use_map_on_length: boolean "Generate texture mapping coordinates following the curve direction, rather than the local bounding box"
+#+ * ID|Curve.use_path -> use_path: boolean "Enable the curve to become a translation path"
+#+ * ID|Curve.use_path_follow -> use_path_follow: boolean "Make curve path children to rotate along the path"
+#+ * ID|Curve.use_radius -> use_radius: boolean "Option for paths: apply the curve radius with path following it and deforming"
+#+ * ID|Curve.use_stretch -> use_stretch: boolean "Option for curve-deform: makes deformed child to stretch along entire path"
+#+ * ID|Curve.use_time_offset -> use_time_offset: boolean "Children will use TimeOffs value as path distance offset"
+#ID|Curve|SurfaceCurve.use_map_on_length -> use_map_on_length: boolean "Generate texture mapping coordinates following the curve direction, rather than the local bounding box"
+#MAKE COLLECTION ATTR * ID|Curve|TextCurve.active_textbox -> active_textbox: int "NO DESCRIPTION"
+#ID|Curve|TextCurve.align -> align: enum "Text align from the object center"
+#+ * ID|Curve|TextCurve.body -> body: string "contents of this text object"
+#+ * ID|Curve|TextCurve.body_format -> body_format: collection, "(read-only) Stores the style of each character"
+#+ * ID|Curve|TextCurve.edit_format -> edit_format: pointer, "(read-only) Editing settings character formatting"
+#+ * ID|Curve|TextCurve.family -> family: string "Use Blender Objects as font characters. Give font objects a common name followed by the character it represents, eg. familya, familyb etc, and turn on Verts Duplication"
+#ID|Curve|TextCurve.follow_curve -> follow_curve: pointer "Curve deforming text object"
+#+ * ID|Curve|TextCurve.font -> font: pointer "NO DESCRIPTION"
+#+ * ID|Curve|TextCurve.offset_x -> offset_x: float "Horizontal offset from the object origin"
+#+ * ID|Curve|TextCurve.offset_y -> offset_y: float "Vertical offset from the object origin"
+#+ * ID|Curve|TextCurve.shear -> shear: float "Italic angle of the characters"
+#ID|Curve|TextCurve.size -> size: float "NO DESCRIPTION"
+#+ * ID|Curve|TextCurve.small_caps_scale -> small_caps_scale: float "Scale of small capitals"
+#ID|Curve|TextCurve.space_character -> space_character: float "NO DESCRIPTION"
+#ID|Curve|TextCurve.space_line -> space_line: float "NO DESCRIPTION"
+#ID|Curve|TextCurve.space_word -> space_word: float "NO DESCRIPTION"
+#ID|Curve|TextCurve.text_boxes -> text_boxes: collection, "(read-only)"
+#ID|Curve|TextCurve.underline_height -> underline_height: float "NO DESCRIPTION"
+#ID|Curve|TextCurve.underline_position -> underline_position: float "Vertical position of underline"
+#ID|Curve|TextCurve.use_fast_edit -> use_fast_edit: boolean "Dont fill polygons while editing"
+#ID|Curve|TextCurve.use_map_on_length -> use_map_on_length: boolean "Generate texture mapping coordinates following the curve direction, rather than the local bounding box"
+#+ * ID|GreasePencil.draw_mode -> draw_mode: enum "NO DESCRIPTION"
+#+ * ID|GreasePencil.layers -> layers: collection, "(read-only)"
+#+ * ID|GreasePencil.use_stroke_endpoints -> use_stroke_endpoints: boolean "Only use the first and last parts of the stroke for snapping"
+#+ * ID|Group.dupli_offset -> dupli_offset: float[3] "Offset from the origin to use when instancing as DupliGroup"
+#ID|Group.layers -> layers: boolean[20] "Layers visible when this groups is instanced as a dupli"
+#+ * ID|Group.objects -> objects: collection, "(read-only) A collection of this groups objects"
+#+ * ID|Image.bindcode -> bindcode: int, "(read-only) OpenGL bindcode"
+#+ * ID|Image.depth -> depth: int, "(read-only) Image bit depth"
+#+ * ID|Image.display_aspect -> display_aspect: float[2] "Display Aspect for this image, does not affect rendering"
+#+ * ID|Image.field_order -> field_order: enum "Order of video fields. Select which lines are displayed first"
+#+ * ID|Image.file_format -> file_format: enum "Format used for re-saving this file"
+#+ * ID|Image.filepath -> filepath: string "Image/Movie file name"
+#+ * ID|Image.filepath_raw -> filepath_raw: string "Image/Movie file name (without data refreshing)"
+#ID|Image.fps -> fps: int "Speed of the animation in frames per second"
+#ID|Image.frame_end -> frame_end: int "End frame of an animated texture"
+#ID|Image.frame_start -> frame_start: int "Start frame of an animated texture"
+#+ * ID|Image.generated_height -> generated_height: int "Generated image height"
+#+ * ID|Image.generated_type -> generated_type: enum "Generated image type"
+#+ * ID|Image.generated_width -> generated_width: int "Generated image width"
+#+ * ID|Image.has_data -> has_data: boolean, "(read-only) True if this image has data"
+#ID|Image.is_dirty -> is_dirty: boolean, "(read-only) Image has changed and is not saved"
+#+ * ID|Image.mapping -> mapping: enum "Mapping type to use for this image in the game engine"
+#+ * ID|Image.packed_file -> packed_file: pointer, "(read-only)"
+#+ * ID|Image.size -> size: int[2], "(read-only) Width and height in pixels, zero when image data cant be loaded"
+#+ * ID|Image.source -> source: enum "Where the image comes from"
+#+ * ID|Image.tiles_x -> tiles_x: int "Degree of repetition in the X direction"
+#+ * ID|Image.tiles_y -> tiles_y: int "Degree of repetition in the Y direction"
+#+ * ID|Image.type -> type: enum, "(read-only) How to generate the image"
+#ID|Image.use_animation -> use_animation: boolean "Use as animated texture in the game engine"
+#ID|Image.use_clamp_x -> use_clamp_x: boolean "Disable texture repeating horizontally"
+#ID|Image.use_clamp_y -> use_clamp_y: boolean "Disable texture repeating vertically"
+#ID|Image.use_fields -> use_fields: boolean "Use fields of the image"
+#ID|Image.use_premultiply -> use_premultiply: boolean "Convert RGB from key alpha to premultiplied alpha"
+#ID|Image.use_tiles -> use_tiles: boolean "Use of tilemode for faces (default shift-LMB to pick the tile for selected faces)"
+#+ * ID|Key.animation_data -> animation_data: pointer, "(read-only) Animation data for this datablock"
+#+ * ID|Key.keys -> keys: collection, "(read-only) Shape keys"
+#+ * ID|Key.reference_key -> reference_key: pointer, "(read-only)"
+#+ * ID|Key.slurph -> slurph: int "Creates a delay in amount of frames in applying keypositions, first vertex goes first"
+#ID|Key.use_relative -> use_relative: boolean "Makes shape keys relative"
+#+ * ID|Key.user -> user: pointer, "(read-only) Datablock using these shape keys"
+#+ * ID|Lamp.active_texture -> active_texture: pointer "Active texture slot being displayed"
+#+ * ID|Lamp.active_texture_index -> active_texture_index: int "Index of active texture slot"
+#+ * ID|Lamp.animation_data -> animation_data: pointer, "(read-only) Animation data for this datablock"
+#+ * ID|Lamp.color -> color: float[3] "Light color"
+#+ * ID|Lamp.distance -> distance: float "Falloff distance - the light is at half the original intensity at this point"
+#+ * ID|Lamp.energy -> energy: float "Amount of light that the lamp emits"
+#+ * ID|Lamp.texture_slots -> texture_slots: collection, "(read-only) Texture slots defining the mapping and influence of textures"
+#+ * ID|Lamp.type -> type: enum "Type of Lamp"
+#ID|Lamp.use_diffuse -> use_diffuse: boolean "Lamp does diffuse shading"
+#ID|Lamp.use_negative -> use_negative: boolean "Lamp casts negative light"
+#ID|Lamp.use_own_layer -> use_own_layer: boolean "Illuminates objects only on the same layer the lamp is on"
+#ID|Lamp.use_specular -> use_specular: boolean "Lamp creates specular highlights"
+#+ * ID|Lamp|AreaLamp.gamma -> gamma: float "Light gamma correction value"
+#+ * ID|Lamp|AreaLamp.shadow_adaptive_threshold -> shadow_adaptive_threshold: float "Threshold for Adaptive Sampling (Raytraced shadows)"
+#+ * ID|Lamp|AreaLamp.shadow_color -> shadow_color: float[3] "Color of shadows cast by the lamp"
+#+ * ID|Lamp|AreaLamp.shadow_method -> shadow_method: enum "Method to compute lamp shadow with"
+#ID|Lamp|AreaLamp.shadow_ray_sample_method -> shadow_ray_sample_method: enum "Method for generating shadow samples: Adaptive QMC is fastest, Constant QMC is less noisy but slower"
+#+ * ID|Lamp|AreaLamp.shadow_ray_samples_x -> shadow_ray_samples_x: int "Amount of samples taken extra (samples x samples)"
+#+ * ID|Lamp|AreaLamp.shadow_ray_samples_y -> shadow_ray_samples_y: int "Amount of samples taken extra (samples x samples)"
+#+ * ID|Lamp|AreaLamp.shadow_soft_size -> shadow_soft_size: float "Light size for ray shadow sampling (Raytraced shadows)"
+#+ * ID|Lamp|AreaLamp.shape -> shape: enum "Shape of the area lamp"
+#+ * ID|Lamp|AreaLamp.size -> size: float "Size of the area of the area Lamp, X direction size for Rectangle shapes"
+#+ * ID|Lamp|AreaLamp.size_y -> size_y: float "Size of the area of the area Lamp in the Y direction for Rectangle shapes"
+#ID|Lamp|AreaLamp.use_dither -> use_dither: boolean "Use 2x2 dithering for sampling (Constant Jittered sampling)"
+#ID|Lamp|AreaLamp.use_jitter -> use_jitter: boolean "Use noise for sampling (Constant Jittered sampling)"
+#ID|Lamp|AreaLamp.use_only_shadow -> use_only_shadow: boolean "Causes light to cast shadows only without illuminating objects"
+#ID|Lamp|AreaLamp.use_shadow_layer -> use_shadow_layer: boolean "Causes only objects on the same layer to cast shadows"
+#ID|Lamp|AreaLamp.use_umbra -> use_umbra: boolean "Emphasize parts that are fully shadowed (Constant Jittered sampling)"
+#+ * ID|Lamp|PointLamp.falloff_curve -> falloff_curve: pointer, "(read-only) Custom Lamp Falloff Curve"
+#+ * ID|Lamp|PointLamp.falloff_type -> falloff_type: enum "Intensity Decay with distance"
+#+ * ID|Lamp|PointLamp.linear_attenuation -> linear_attenuation: float "Linear distance attenuation"
+#+ * ID|Lamp|PointLamp.quadratic_attenuation -> quadratic_attenuation: float "Quadratic distance attenuation"
+#+ * ID|Lamp|PointLamp.shadow_adaptive_threshold -> shadow_adaptive_threshold: float "Threshold for Adaptive Sampling (Raytraced shadows)"
+#+ * ID|Lamp|PointLamp.shadow_color -> shadow_color: float[3] "Color of shadows cast by the lamp"
+#+ * ID|Lamp|PointLamp.shadow_method -> shadow_method: enum "Method to compute lamp shadow with"
+#ID|Lamp|PointLamp.shadow_ray_sample_method -> shadow_ray_sample_method: enum "Method for generating shadow samples: Adaptive QMC is fastest, Constant QMC is less noisy but slower"
+#+ * ID|Lamp|PointLamp.shadow_ray_samples -> shadow_ray_samples: int "Amount of samples taken extra (samples x samples)"
+#+ * ID|Lamp|PointLamp.shadow_soft_size -> shadow_soft_size: float "Light size for ray shadow sampling (Raytraced shadows)"
+#ID|Lamp|PointLamp.use_only_shadow -> use_only_shadow: boolean "Causes light to cast shadows only without illuminating objects"
+#ID|Lamp|PointLamp.use_shadow_layer -> use_shadow_layer: boolean "Causes only objects on the same layer to cast shadows"
+#ID|Lamp|PointLamp.use_sphere -> use_sphere: boolean "Sets light intensity to zero beyond lamp distance"
+#+ * ID|Lamp|SpotLamp.compression_threshold -> compression_threshold: float "Deep shadow map compression threshold"
+#+ * ID|Lamp|SpotLamp.falloff_curve -> falloff_curve: pointer, "(read-only) Custom Lamp Falloff Curve"
+#+ * ID|Lamp|SpotLamp.falloff_type -> falloff_type: enum "Intensity Decay with distance"
+#+ * ID|Lamp|SpotLamp.halo_intensity -> halo_intensity: float "Brightness of the spotlights halo cone (Buffer Shadows)"
+#+ * ID|Lamp|SpotLamp.halo_step -> halo_step: int "Volumetric halo sampling frequency"
+#+ * ID|Lamp|SpotLamp.linear_attenuation -> linear_attenuation: float "Linear distance attenuation"
+#+ * ID|Lamp|SpotLamp.quadratic_attenuation -> quadratic_attenuation: float "Quadratic distance attenuation"
+#+ * ID|Lamp|SpotLamp.shadow_adaptive_threshold -> shadow_adaptive_threshold: float "Threshold for Adaptive Sampling (Raytraced shadows)"
+#+ * ID|Lamp|SpotLamp.shadow_buffer_bias -> shadow_buffer_bias: float "Shadow buffer sampling bias"
+#+ * ID|Lamp|SpotLamp.shadow_buffer_clip_end -> shadow_buffer_clip_end: float "Shadow map clip end beyond which objects will not generate shadows"
+#+ * ID|Lamp|SpotLamp.shadow_buffer_clip_start -> shadow_buffer_clip_start: float "Shadow map clip start: objects closer will not generate shadows"
+#+ * ID|Lamp|SpotLamp.shadow_buffer_samples -> shadow_buffer_samples: int "Number of shadow buffer samples"
+#+ * ID|Lamp|SpotLamp.shadow_buffer_size -> shadow_buffer_size: int "Resolution of the shadow buffer, higher values give crisper shadows but use more memory"
+#+ * ID|Lamp|SpotLamp.shadow_buffer_soft -> shadow_buffer_soft: float "Size of shadow buffer sampling area"
+#+ * ID|Lamp|SpotLamp.shadow_buffer_type -> shadow_buffer_type: enum "Type of shadow buffer"
+#+ * ID|Lamp|SpotLamp.shadow_color -> shadow_color: float[3] "Color of shadows cast by the lamp"
+#+ * ID|Lamp|SpotLamp.shadow_filter_type -> shadow_filter_type: enum "Type of shadow filter (Buffer Shadows)"
+#+ * ID|Lamp|SpotLamp.shadow_method -> shadow_method: enum "Method to compute lamp shadow with"
+#ID|Lamp|SpotLamp.shadow_ray_sample_method -> shadow_ray_sample_method: enum "Method for generating shadow samples: Adaptive QMC is fastest, Constant QMC is less noisy but slower"
+#+ * ID|Lamp|SpotLamp.shadow_ray_samples -> shadow_ray_samples: int "Amount of samples taken extra (samples x samples)"
+#+ * ID|Lamp|SpotLamp.shadow_sample_buffers -> shadow_sample_buffers: enum "Number of shadow buffers to render for better AA, this increases memory usage"
+#+ * ID|Lamp|SpotLamp.shadow_soft_size -> shadow_soft_size: float "Light size for ray shadow sampling (Raytraced shadows)"
+#+ * ID|Lamp|SpotLamp.show_cone -> show_cone: boolean "Draw transparent cone in 3D view to visualize which objects are contained in it"
+#+ * ID|Lamp|SpotLamp.spot_blend -> spot_blend: float "The softness of the spotlight edge"
+#+ * ID|Lamp|SpotLamp.spot_size -> spot_size: float "Angle of the spotlight beam in degrees"
+#ID|Lamp|SpotLamp.use_auto_clip_end -> use_auto_clip_end: boolean "Automatic calculation of clipping-end, based on visible vertices"
+#ID|Lamp|SpotLamp.use_auto_clip_start -> use_auto_clip_start: boolean "Automatic calculation of clipping-start, based on visible vertices"
+#ID|Lamp|SpotLamp.use_halo -> use_halo: boolean "Renders spotlight with a volumetric halo (Buffer Shadows)"
+#ID|Lamp|SpotLamp.use_only_shadow -> use_only_shadow: boolean "Causes light to cast shadows only without illuminating objects"
+#ID|Lamp|SpotLamp.use_shadow_layer -> use_shadow_layer: boolean "Causes only objects on the same layer to cast shadows"
+#ID|Lamp|SpotLamp.use_sphere -> use_sphere: boolean "Sets light intensity to zero beyond lamp distance"
+#ID|Lamp|SpotLamp.use_square -> use_square: boolean "Casts a square spot light shape"
+#+ * ID|Lamp|SunLamp.shadow_adaptive_threshold -> shadow_adaptive_threshold: float "Threshold for Adaptive Sampling (Raytraced shadows)"
+#+ * ID|Lamp|SunLamp.shadow_color -> shadow_color: float[3] "Color of shadows cast by the lamp"
+#+ * ID|Lamp|SunLamp.shadow_method -> shadow_method: enum "Method to compute lamp shadow with"
+#ID|Lamp|SunLamp.shadow_ray_sample_method -> shadow_ray_sample_method: enum "Method for generating shadow samples: Adaptive QMC is fastest, Constant QMC is less noisy but slower"
+#+ * ID|Lamp|SunLamp.shadow_ray_samples -> shadow_ray_samples: int "Amount of samples taken extra (samples x samples)"
+#+ * ID|Lamp|SunLamp.shadow_soft_size -> shadow_soft_size: float "Light size for ray shadow sampling (Raytraced shadows)"
+#+ * ID|Lamp|SunLamp.sky -> sky: pointer, "(read-only) Sky related settings for sun lamps"
+#ID|Lamp|SunLamp.use_only_shadow -> use_only_shadow: boolean "Causes light to cast shadows only without illuminating objects"
+#ID|Lamp|SunLamp.use_shadow_layer -> use_shadow_layer: boolean "Causes only objects on the same layer to cast shadows"
+#+ * ID|Lattice.interpolation_type_u -> interpolation_type_u: enum "NO DESCRIPTION"
+#+ * ID|Lattice.interpolation_type_v -> interpolation_type_v: enum "NO DESCRIPTION"
+#+ * ID|Lattice.interpolation_type_w -> interpolation_type_w: enum "NO DESCRIPTION"
+#+ * ID|Lattice.points -> points: collection, "(read-only) Points of the lattice"
+#+ * ID|Lattice.points_u -> points_u: int "Points in U direction (cant be changed when there are shape keys)"
+#+ * ID|Lattice.points_v -> points_v: int "Points in V direction (cant be changed when there are shape keys)"
+#+ * ID|Lattice.points_w -> points_w: int "Points in W direction (cant be changed when there are shape keys)"
+#+ * ID|Lattice.shape_keys -> shape_keys: pointer, "(read-only)"
+#ID|Lattice.use_outside -> use_outside: boolean "Only draw, and take into account, the outer vertices"
+#+ * ID|Lattice.vertex_group -> vertex_group: string "Vertex group to apply the influence of the lattice"
+#+ * ID|Library.filepath -> filepath: string "Path to the library .blend file"
+#+ * ID|Library.parent -> parent: pointer, "(read-only)"
+#+ * ID|Material.active_node_material -> active_node_material: pointer "Active node material"
+#+ * ID|Material.active_texture -> active_texture: pointer "Active texture slot being displayed"
+#+ * ID|Material.active_texture_index -> active_texture_index: int "Index of active texture slot"
+#+ * ID|Material.alpha -> alpha: float "Alpha transparency of the material"
+#+ * ID|Material.ambient -> ambient: float "Amount of global ambient color the material receives"
+#+ * ID|Material.animation_data -> animation_data: pointer, "(read-only) Animation data for this datablock"
+#+ * ID|Material.darkness -> darkness: float "Minnaert darkness"
+#+ * ID|Material.diffuse_color -> diffuse_color: float[3] "NO DESCRIPTION"
+#+ * ID|Material.diffuse_fresnel -> diffuse_fresnel: float "Power of Fresnel"
+#+ * ID|Material.diffuse_fresnel_factor -> diffuse_fresnel_factor: float "Blending factor of Fresnel"
+#+ * ID|Material.diffuse_intensity -> diffuse_intensity: float "Amount of diffuse reflection"
+#+ * ID|Material.diffuse_ramp -> diffuse_ramp: pointer, "(read-only) Color ramp used to affect diffuse shading"
+#+ * ID|Material.diffuse_ramp_blend -> diffuse_ramp_blend: enum "NO DESCRIPTION"
+#+ * ID|Material.diffuse_ramp_factor -> diffuse_ramp_factor: float "Blending factor (also uses alpha in Colorband)"
+#+ * ID|Material.diffuse_ramp_input -> diffuse_ramp_input: enum "NO DESCRIPTION"
+#+ * ID|Material.diffuse_shader -> diffuse_shader: enum "NO DESCRIPTION"
+#+ * ID|Material.diffuse_toon_size -> diffuse_toon_size: float "Size of diffuse toon area"
+#+ * ID|Material.diffuse_toon_smooth -> diffuse_toon_smooth: float "Smoothness of diffuse toon area"
+#+ * ID|Material.emit -> emit: float "Amount of light to emit"
+#+ * ID|Material.halo -> halo: pointer, "(read-only) Halo settings for the material"
+#+ * ID|Material.invert_z -> invert_z: boolean "Renders materials faces with an inverted Z buffer (scanline only)"
+#+ * ID|Material.light_group -> light_group: pointer "Limit lighting to lamps in this Group"
+#+ * ID|Material.mirror_color -> mirror_color: float[3] "Mirror color of the material"
+#+ * ID|Material.node_tree -> node_tree: pointer, "(read-only) Node tree for node based materials"
+#ID|Material.offset_z -> offset_z: float "Gives faces an artificial offset in the Z buffer for Z transparency"
+#+ * ID|Material.physics -> physics: pointer, "(read-only) Game physics settings"
+#+ * ID|Material.preview_render_type -> preview_render_type: enum "Type of preview render"
+#+ * ID|Material.raytrace_mirror -> raytrace_mirror: pointer, "(read-only) Raytraced reflection settings for the material"
+#+ * ID|Material.raytrace_transparency -> raytrace_transparency: pointer, "(read-only) Raytraced transparency settings for the material"
+#+ * ID|Material.roughness -> roughness: float "Oren-Nayar Roughness"
+#+ * ID|Material.shadow_buffer_bias -> shadow_buffer_bias: float "Factor to multiply shadow buffer bias with (0 is ignore.)"
+#ID|Material.shadow_cast_alpha -> shadow_cast_alpha: float "Shadow casting alpha, in use for Irregular and Deep shadow buffer"
+#+ * ID|Material.shadow_ray_bias -> shadow_ray_bias: float "Shadow raytracing bias to prevent terminator problems on shadow boundary"
+#+ * ID|Material.specular_alpha -> specular_alpha: float "Alpha transparency for specular areas"
+#+ * ID|Material.specular_color -> specular_color: float[3] "Specular color of the material"
+#+ * ID|Material.specular_hardness -> specular_hardness: int "NO DESCRIPTION"
+#+ * ID|Material.specular_intensity -> specular_intensity: float "NO DESCRIPTION"
+#+ * ID|Material.specular_ior -> specular_ior: float "NO DESCRIPTION"
+#+ * ID|Material.specular_ramp -> specular_ramp: pointer, "(read-only) Color ramp used to affect specular shading"
+#+ * ID|Material.specular_ramp_blend -> specular_ramp_blend: enum "NO DESCRIPTION"
+#+ * ID|Material.specular_ramp_factor -> specular_ramp_factor: float "Blending factor (also uses alpha in Colorband)"
+#+ * ID|Material.specular_ramp_input -> specular_ramp_input: enum "NO DESCRIPTION"
+#+ * ID|Material.specular_shader -> specular_shader: enum "NO DESCRIPTION"
+#+ * ID|Material.specular_slope -> specular_slope: float "The standard deviation of surface slope"
+#+ * ID|Material.specular_toon_size -> specular_toon_size: float "Size of specular toon area"
+#+ * ID|Material.specular_toon_smooth -> specular_toon_smooth: float "Smoothness of specular toon area"
+#+ * ID|Material.strand -> strand: pointer, "(read-only) Strand settings for the material"
+#+ * ID|Material.subsurface_scattering -> subsurface_scattering: pointer, "(read-only) Subsurface scattering settings for the material"
+#+ * ID|Material.texture_slots -> texture_slots: collection, "(read-only) Texture slots defining the mapping and influence of textures"
+#+ * ID|Material.translucency -> translucency: float "Amount of diffuse shading on the back side"
+#+ * ID|Material.transparency_method -> transparency_method: enum "Method to use for rendering transparency"
+#+ * ID|Material.type -> type: enum "Material type defining how the object is rendered"
+#ID|Material.use_cast_approximate -> use_cast_approximate: boolean "Allow this material to cast shadows when using approximate ambient occlusion."
+#ID|Material.use_cast_buffer_shadows -> use_cast_buffer_shadows: boolean "Allow this material to cast shadows from shadow buffer lamps"
+#ID|Material.use_cast_shadows_only -> use_cast_shadows_only: boolean "Makes objects with this material appear invisible, only casting shadows (not rendered)"
+#ID|Material.use_cubic -> use_cubic: boolean "Use cubic interpolation for diffuse values, for smoother transitions"
+#+ * ID|Material.use_diffuse_ramp -> use_diffuse_ramp: boolean "Toggle diffuse ramp operations"
+#ID|Material.use_face_texture -> use_face_texture: boolean "Replaces the objects base color with color from face assigned image textures"
+#ID|Material.use_face_texture_alpha -> use_face_texture_alpha: boolean "Replaces the objects base alpha value with alpha from face assigned image textures"
+#ID|Material.use_full_oversampling -> use_full_oversampling: boolean "Force this material to render full shading/textures for all anti-aliasing samples"
+#ID|Material.use_light_group_exclusive -> use_light_group_exclusive: boolean "Material uses the light group exclusively - these lamps are excluded from other scene lighting"
+#ID|Material.use_mist -> use_mist: boolean "Use mist with this material (in world settings)"
+#+ * ID|Material.use_nodes -> use_nodes: boolean "Use shader nodes to render the material"
+#ID|Material.use_object_color -> use_object_color: boolean "Modulate the result with a per-object color"
+#ID|Material.use_only_shadow -> use_only_shadow: boolean "Renders shadows as the materials alpha value, making materials transparent except for shadowed areas"
+#ID|Material.use_ray_shadow_bias -> use_ray_shadow_bias: boolean "Prevents raytraced shadow errors on surfaces with smooth shaded normals (terminator problem)"
+#ID|Material.use_raytrace -> use_raytrace: boolean "Include this material and geometry that uses it in ray tracing calculations"
+#ID|Material.use_shadeless -> use_shadeless: boolean "Makes this material insensitive to light or shadow"
+#ID|Material.use_shadows -> use_shadows: boolean "Allows this material to receive shadows"
+#+ * ID|Material.use_sky -> use_sky: boolean "Renders this material with zero alpha, with sky background in place (scanline only)"
+#+ * ID|Material.use_specular_ramp -> use_specular_ramp: boolean "Toggle specular ramp operations"
+#ID|Material.use_tangent_shading -> use_tangent_shading: boolean "Use the materials tangent vector instead of the normal for shading - for anisotropic shading effects"
+#+ * ID|Material.use_textures -> use_textures: boolean[18] "Enable/Disable each texture"
+#ID|Material.use_transparency -> use_transparency: boolean "Render material as transparent"
+#ID|Material.use_transparent_shadows -> use_transparent_shadows: boolean "Allow this object to receive transparent shadows casted through other objects"
+#ID|Material.use_vertex_color_light -> use_vertex_color_light: boolean "Add vertex colors as additional lighting"
+#ID|Material.use_vertex_color_paint -> use_vertex_color_paint: boolean "Replaces object base color with vertex colors (multiplies with texture face face assigned textures)"
+#+ * ID|Material.volume -> volume: pointer, "(read-only) Volume settings for the material"
+#+ * ID|Mesh.active_uv_texture_index -> active_uv_texture_index: int "Active UV texture index"
+#+ * ID|Mesh.active_vertex_color_index -> active_vertex_color_index: int "Active vertex color index"
+#+ * ID|Mesh.animation_data -> animation_data: pointer, "(read-only) Animation data for this datablock"
+#ID|Mesh.auto_smooth_angle -> auto_smooth_angle: int "Defines maximum angle between face normals that Auto Smooth will operate on"
+#+ * ID|Mesh.edges -> edges: collection, "(read-only) Edges of the mesh"
+#+ * ID|Mesh.faces -> faces: collection, "(read-only) Faces of the mesh"
+#ID|Mesh.layers_float -> layers_float: collection, "(read-only)"
+#ID|Mesh.layers_int -> layers_int: collection, "(read-only)"
+#ID|Mesh.layers_string -> layers_string: collection, "(read-only)"
+#+ * ID|Mesh.materials -> materials: collection, "(read-only)"
+#+ * ID|Mesh.shape_keys -> shape_keys: pointer, "(read-only)"
+#ID|Mesh.show_all_edges -> show_all_edges: boolean "Displays all edges for wireframe in all view modes in the 3D view"
+#ID|Mesh.show_double_sided -> show_double_sided: boolean "Render/display the mesh with double or single sided lighting"
+#ID|Mesh.show_edge_bevel_weight -> show_edge_bevel_weight: boolean "Displays weights created for the Bevel modifier"
+#ID|Mesh.show_edge_crease -> show_edge_crease: boolean "Displays creases created for subsurf weighting"
+#ID|Mesh.show_edge_seams -> show_edge_seams: boolean "Displays UV unwrapping seams"
+#ID|Mesh.show_edge_sharp -> show_edge_sharp: boolean "Displays sharp edges, used with the EdgeSplit modifier"
+#ID|Mesh.show_edges -> show_edges: boolean "Displays selected edges using highlights in the 3D view and UV editor"
+#ID|Mesh.show_extra_edge_angle -> show_extra_edge_angle: boolean "Displays the angles in the selected edges in degrees, Using global values when set in the transform panel"
+#ID|Mesh.show_extra_edge_length -> show_extra_edge_length: boolean "Displays selected edge lengths, Using global values when set in the transform panel"
+#ID|Mesh.show_extra_face_area -> show_extra_face_area: boolean "Displays the area of selected faces, Using global values when set in the transform panel"
+#ID|Mesh.show_faces -> show_faces: boolean "Displays all faces as shades in the 3D view and UV editor"
+#ID|Mesh.show_normal_face -> show_normal_face: boolean "Displays face normals as lines"
+#ID|Mesh.show_normal_vertex -> show_normal_vertex: boolean "Displays vertex normals as lines"
+#+ * ID|Mesh.sticky -> sticky: collection, "(read-only) Sticky texture coordinates"
+#+ * ID|Mesh.texco_mesh -> texco_mesh: pointer "Derive texture coordinates from another mesh"
+#ID|Mesh.texspace_location -> texspace_location: float[3] "Texture space location"
+#+ * ID|Mesh.texspace_size -> texspace_size: float[3] "Texture space size"
+#+ * ID|Mesh.texture_mesh -> texture_mesh: pointer "Use another mesh for texture indices (vertex indices must be aligned)"
+#+ * ID|Mesh.total_edge_sel -> total_edge_sel: int, "(read-only) Selected edge count in editmode"
+#+ * ID|Mesh.total_face_sel -> total_face_sel: int, "(read-only) Selected face count in editmode"
+#+ * ID|Mesh.total_vert_sel -> total_vert_sel: int, "(read-only) Selected vertex count in editmode"
+#ID|Mesh.use_auto_smooth -> use_auto_smooth: boolean "Treats all set-smoothed faces with angles less than the specified angle as smooth during render"
+#ID|Mesh.use_auto_texspace -> use_auto_texspace: boolean "Adjusts active objects texture space automatically when transforming object"
+#+ * ID|Mesh.use_mirror_topology -> use_mirror_topology: boolean "Use topology based mirroring"
+#+ * ID|Mesh.use_mirror_x -> use_mirror_x: boolean "X Axis mirror editing"
+#+ * ID|Mesh.use_paint_mask -> use_paint_mask: boolean "Face selection masking for painting"
+#+ * ID|Mesh.uv_texture_clone -> uv_texture_clone: pointer "UV texture to be used as cloning source"
+#+ * ID|Mesh.uv_texture_clone_index -> uv_texture_clone_index: int "Clone UV texture index"
+#+ * ID|Mesh.uv_texture_stencil -> uv_texture_stencil: pointer "UV texture to mask the painted area"
+#+ * ID|Mesh.uv_texture_stencil_index -> uv_texture_stencil_index: int "Mask UV texture index"
+#+ * ID|Mesh.uv_textures -> uv_textures: collection, "(read-only)"
+#+ * ID|Mesh.vertex_colors -> vertex_colors: collection, "(read-only)"
+#ID|Mesh.vertices -> vertices: collection, "(read-only) Vertices of the mesh"
+#+ * ID|MetaBall.animation_data -> animation_data: pointer, "(read-only) Animation data for this datablock"
+#+ * ID|MetaBall.elements -> elements: collection, "(read-only) Meta elements"
+#+ * ID|MetaBall.materials -> materials: collection, "(read-only)"
+#ID|MetaBall.render_resolution -> render_resolution: float "Polygonization resolution in rendering"
+#ID|MetaBall.resolution -> resolution: float "Polygonization resolution in the 3D viewport"
+#ID|MetaBall.texspace_location -> texspace_location: float[3] "Texture space location"
+#+ * ID|MetaBall.texspace_size -> texspace_size: float[3] "Texture space size"
+#+ * ID|MetaBall.threshold -> threshold: float "Influence of meta elements"
+#ID|MetaBall.update_method -> update_method: enum "Metaball edit update behavior"
+#ID|MetaBall.use_auto_texspace -> use_auto_texspace: boolean "Adjusts active objects texture space automatically when transforming object"
+#+ * ID|NodeTree.animation_data -> animation_data: pointer, "(read-only) Animation data for this datablock"
+#+ * ID|NodeTree.grease_pencil -> grease_pencil: pointer "Grease Pencil datablock"
+#+ * ID|NodeTree.nodes -> nodes: collection, "(read-only)"
+#+ * ID|Object.active_material -> active_material: pointer "Active material being displayed"
+#+ * ID|Object.active_material_index -> active_material_index: int "Index of active material slot"
+#+ * ID|Object.active_particle_system -> active_particle_system: pointer, "(read-only) Active particle system being displayed"
+#+ * ID|Object.active_particle_system_index -> active_particle_system_index: int "Index of active particle system slot"
+#+ * ID|Object.active_shape_key -> active_shape_key: pointer, "(read-only) Current shape key"
+#+ * ID|Object.active_shape_key_index -> active_shape_key_index: int "Current shape key index"
+#+ * ID|Object.active_vertex_group -> active_vertex_group: pointer, "(read-only) Vertex groups of the object"
+#+ * ID|Object.active_vertex_group_index -> active_vertex_group_index: int "Active index in vertex group array"
+#+ * ID|Object.animation_data -> animation_data: pointer, "(read-only) Animation data for this datablock"
+#+ * ID|Object.animation_visualisation -> animation_visualisation: pointer, "(read-only) Animation data for this datablock"
+#+ * ID|Object.bound_box -> bound_box: float[24], "(read-only) Objects bound box in object-space coordinates"
+#+ * ID|Object.collision -> collision: pointer, "(read-only) Settings for using the objects as a collider in physics simulation"
+#+ * ID|Object.color -> color: float[4] "Object color and alpha, used when faces have the ObColor mode enabled"
+#+ * ID|Object.constraints -> constraints: collection, "(read-only) Constraints affecting the transformation of the object"
+#+ * ID|Object.data -> data: pointer "Object data"
+#+ * ID|Object.delta_location -> delta_location: float[3] "Extra translation added to the location of the object"
+#+ * ID|Object.delta_rotation_euler -> delta_rotation_euler: float[3] "Extra rotation added to the rotation of the object (when using Euler rotations)"
+#+ * ID|Object.delta_rotation_quaternion -> delta_rotation_quaternion: float[4] "Extra rotation added to the rotation of the object (when using Quaternion rotations)"
+#+ * ID|Object.delta_scale -> delta_scale: float[3] "Extra scaling added to the scale of the object"
+#+ * ID|Object.dimensions -> dimensions: float[3] "Absolute bounding box dimensions of the object"
+#+ * ID|Object.draw_bounds_type -> draw_bounds_type: enum "Object boundary display type"
+#ID|Object.draw_type -> draw_type: enum "Maximum draw type to display object with in viewport"
+#+ * ID|Object.dupli_faces_scale -> dupli_faces_scale: float "Scale the DupliFace objects"
+#+ * ID|Object.dupli_frames_end -> dupli_frames_end: int "End frame for DupliFrames"
+#+ * ID|Object.dupli_frames_off -> dupli_frames_off: int "Recurring frames to exclude from the Dupliframes"
+#+ * ID|Object.dupli_frames_on -> dupli_frames_on: int "Number of frames to use between DupOff frames"
+#+ * ID|Object.dupli_frames_start -> dupli_frames_start: int "Start frame for DupliFrames"
+#+ * ID|Object.dupli_group -> dupli_group: pointer "Instance an existing group"
+#+ * ID|Object.dupli_list -> dupli_list: collection, "(read-only) Object duplis"
+#+ * ID|Object.dupli_type -> dupli_type: enum "If not None, object duplication method to use"
+#+ * ID|Object.empty_draw_size -> empty_draw_size: float "Size of display for empties in the viewport"
+#+ * ID|Object.empty_draw_type -> empty_draw_type: enum "Viewport display style for empties"
+#+ * ID|Object.field -> field: pointer, "(read-only) Settings for using the objects as a field in physics simulation"
+#+ * ID|Object.game -> game: pointer, "(read-only) Game engine related settings for the object"
+#+ * ID|Object.grease_pencil -> grease_pencil: pointer "Grease Pencil datablock"
+#+ * ID|Object.hide -> hide: boolean "Restrict visibility in the viewport"
+#+ * ID|Object.hide_render -> hide_render: boolean "Restrict renderability"
+#+ * ID|Object.hide_select -> hide_select: boolean "Restrict selection in the viewport"
+#ID|Object.is_duplicator -> is_duplicator: boolean, "(read-only)"
+#+ * ID|Object.layers -> layers: boolean[20] "Layers the object is on"
+#+ * ID|Object.location -> location: float[3] "Location of the object"
+#+ * ID|Object.lock_location -> lock_location: boolean[3] "Lock editing of location in the interface"
+#+ * ID|Object.lock_rotation -> lock_rotation: boolean[3] "Lock editing of rotation in the interface"
+#+ * ID|Object.lock_rotation_w -> lock_rotation_w: boolean "Lock editing of angle component of four-component rotations in the interface"
+#+ * ID|Object.lock_rotations_4d -> lock_rotations_4d: boolean "Lock editing of four component rotations by components (instead of as Eulers)"
+#+ * ID|Object.lock_scale -> lock_scale: boolean[3] "Lock editing of scale in the interface"
+#+ * ID|Object.material_slots -> material_slots: collection, "(read-only) Material slots in the object"
+#+ * ID|Object.matrix_local -> matrix_local: float[16] "Parent relative transformation matrix"
+#+ * ID|Object.matrix_world -> matrix_world: float[16] "Worldspace transformation matrix"
+#+ * ID|Object.mode -> mode: enum, "(read-only) Object interaction mode"
+#+ * ID|Object.modifiers -> modifiers: collection, "(read-only) Modifiers affecting the geometric data of the object"
+#+ * ID|Object.motion_path -> motion_path: pointer, "(read-only) Motion Path for this element"
+#+ * ID|Object.parent -> parent: pointer "Parent Object"
+#+ * ID|Object.parent_bone -> parent_bone: string "Name of parent bone in case of a bone parenting relation"
+#+ * ID|Object.parent_type -> parent_type: enum "Type of parent relation"
+#+ * ID|Object.parent_vertices -> parent_vertices: int[3], "(read-only) Indices of vertices in cases of a vertex parenting relation"
+#+ * ID|Object.particle_systems -> particle_systems: collection, "(read-only) Particle systems emitted from the object"
+#+ * ID|Object.pass_index -> pass_index: int "Index # for the IndexOB render pass"
+#+ * ID|Object.pose -> pose: pointer, "(read-only) Current pose for armatures"
+#+ * ID|Object.pose_library -> pose_library: pointer, "(read-only) Action used as a pose library for armatures"
+#+ * ID|Object.proxy -> proxy: pointer, "(read-only) Library object this proxy object controls"
+#+ * ID|Object.proxy_group -> proxy_group: pointer, "(read-only) Library group duplicator object this proxy object controls"
+#+ * ID|Object.rotation_axis_angle -> rotation_axis_angle: float[4] "Angle of Rotation for Axis-Angle rotation representation"
+#+ * ID|Object.rotation_euler -> rotation_euler: float[3] "Rotation in Eulers"
+#+ * ID|Object.rotation_mode -> rotation_mode: enum "NO DESCRIPTION"
+#+ * ID|Object.rotation_quaternion -> rotation_quaternion: float[4] "Rotation in Quaternions"
+#+ * ID|Object.scale -> scale: float[3] "Scaling of the object"
+#+ * ID|Object.select -> select: boolean "Object selection state"
+#ID|Object.show_axis -> show_axis: boolean "Displays the objects origin and axis"
+#ID|Object.show_bounds -> show_bounds: boolean "Displays the objects bounds"
+#ID|Object.show_name -> show_name: boolean "Displays the objects name"
+#ID|Object.show_shape_key -> show_shape_key: boolean "Always show the current Shape for this Object"
+#ID|Object.show_texture_space -> show_texture_space: boolean "Displays the objects texture space"
+#ID|Object.show_transparent -> show_transparent: boolean "Enables transparent materials for the object (Mesh only)"
+#ID|Object.show_wire -> show_wire: boolean "Adds the objects wireframe over solid drawing"
+#ID|Object.show_x_ray -> show_x_ray: boolean "Makes the object draw in front of others"
+#+ * ID|Object.soft_body -> soft_body: pointer, "(read-only) Settings for soft body simulation"
+#+ * ID|Object.time_offset -> time_offset: float "Animation offset in frames for F-Curve and dupligroup instances"
+#+ * ID|Object.track_axis -> track_axis: enum "Axis that points in forward direction"
+#+ * ID|Object.type -> type: enum, "(read-only) Type of Object"
+#+ * ID|Object.up_axis -> up_axis: enum "Axis that points in the upward direction"
+#+ * ID|Object.use_dupli_faces_scale -> use_dupli_faces_scale: boolean "Scale dupli based on face size"
+#+ * ID|Object.use_dupli_frames_speed -> use_dupli_frames_speed: boolean "Set dupliframes to use the frame"
+#ID|Object.use_dupli_vertices_rotation -> use_dupli_vertices_rotation: boolean "Rotate dupli according to vertex normal"
+#ID|Object.use_shape_key_edit_mode -> use_shape_key_edit_mode: boolean "Apply shape keys in edit mode (for Meshes only)"
+#ID|Object.use_slow_parent -> use_slow_parent: boolean "Create a delay in the parent relationship"
+#ID|Object.use_time_offset_add_parent -> use_time_offset_add_parent: boolean "Add the parents time offset value"
+#ID|Object.use_time_offset_edit -> use_time_offset_edit: boolean "Use time offset when inserting keys and display time offset for F-Curve and action views"
+#ID|Object.use_time_offset_parent -> use_time_offset_parent: boolean "Apply the time offset to this objects parent relationship"
+#ID|Object.use_time_offset_particle -> use_time_offset_particle: boolean "Let the time offset work on the particle effect"
+#+ * ID|Object.vertex_groups -> vertex_groups: collection, "(read-only) Vertex groups of the object"
+#+ * ID|ParticleSettings.active_dupliweight -> active_dupliweight: pointer, "(read-only)"
+#+ * ID|ParticleSettings.active_dupliweight_index -> active_dupliweight_index: int "NO DESCRIPTION"
+#+ * ID|ParticleSettings.adaptive_angle -> adaptive_angle: int "How many degrees path has to curve to make another render segment"
+#ID|ParticleSettings.adaptive_pixel -> adaptive_pixel: int "How many pixels path has to cover to make another render segment"
+#+ * ID|ParticleSettings.angular_velocity_factor -> angular_velocity_factor: float "Angular velocity amount"
+#+ * ID|ParticleSettings.angular_velocity_mode -> angular_velocity_mode: enum "Particle angular velocity mode"
+#+ * ID|ParticleSettings.animation_data -> animation_data: pointer, "(read-only) Animation data for this datablock"
+#ID|ParticleSettings.apply_effector_to_children -> apply_effector_to_children: boolean "Apply effectors to children"
+#ID|ParticleSettings.apply_guide_to_children -> apply_guide_to_children: boolean "NO DESCRIPTION"
+#+ * ID|ParticleSettings.billboard_align -> billboard_align: enum "In respect to what the billboards are aligned"
+#+ * ID|ParticleSettings.billboard_animation -> billboard_animation: enum "How to animate billboard textures"
+#+ * ID|ParticleSettings.billboard_object -> billboard_object: pointer "Billboards face this object (default is active camera)"
+#+ * ID|ParticleSettings.billboard_offset -> billboard_offset: float[2] "NO DESCRIPTION"
+#ID|ParticleSettings.billboard_offset_split -> billboard_offset_split: enum "How to offset billboard textures"
+#+ * ID|ParticleSettings.billboard_tilt -> billboard_tilt: float "Tilt of the billboards"
+#ID|ParticleSettings.billboard_tilt_random -> billboard_tilt_random: float "Random tilt of the billboards"
+#+ * ID|ParticleSettings.billboard_uv_split -> billboard_uv_split: int "Amount of rows/columns to split UV coordinates for billboards"
+#+ * ID|ParticleSettings.boids -> boids: pointer, "(read-only)"
+#+ * ID|ParticleSettings.branch_threshold -> branch_threshold: float "Threshold of branching"
+#+ * ID|ParticleSettings.brownian_factor -> brownian_factor: float "Specify the amount of Brownian motion"
+#+ * ID|ParticleSettings.child_length -> child_length: float "Length of child paths"
+#ID|ParticleSettings.child_length_threshold -> child_length_threshold: float "Amount of particles left untouched by child path length"
+#+ * ID|ParticleSettings.child_nbr -> child_nbr: int "Amount of children/parent"
+#+ * ID|ParticleSettings.child_radius -> child_radius: float "Radius of children around parent"
+#+ * ID|ParticleSettings.child_roundness -> child_roundness: float "Roundness of children around parent"
+#+ * ID|ParticleSettings.child_size -> child_size: float "A multiplier for the child particle size"
+#ID|ParticleSettings.child_size_random -> child_size_random: float "Random variation to the size of the child particles"
+#+ * ID|ParticleSettings.child_type -> child_type: enum "Create child particles"
+#+ * ID|ParticleSettings.clump_factor -> clump_factor: float "Amount of clumping"
+#ID|ParticleSettings.clump_shape -> clump_shape: float "Shape of clumping"
+#ID|ParticleSettings.count -> count: int "Total number of particles"
+#ID|ParticleSettings.damping -> damping: float "Specify the amount of damping"
+#+ * ID|ParticleSettings.distribution -> distribution: enum "How to distribute particles on selected element"
+#+ * ID|ParticleSettings.drag_factor -> drag_factor: float "Specify the amount of air-drag"
+#ID|ParticleSettings.draw_method -> draw_method: enum "How particles are drawn in viewport"
+#ID|ParticleSettings.draw_percentage -> draw_percentage: int "Percentage of particles to display in 3D view"
+#+ * ID|ParticleSettings.draw_size -> draw_size: int "Size of particles on viewport in pixels (0=default)"
+#+ * ID|ParticleSettings.draw_step -> draw_step: int "How many steps paths are drawn with (power of 2)"
+#+ * ID|ParticleSettings.dupli_group -> dupli_group: pointer "Show Objects in this Group in place of particles"
+#+ * ID|ParticleSettings.dupli_object -> dupli_object: pointer "Show this Object in place of particles"
+#ID|ParticleSettings.dupli_weights -> dupli_weights: collection, "(read-only) Weights for all of the objects in the dupli group"
+#+ * ID|ParticleSettings.effect_hair -> effect_hair: float "Hair stiffness for effectors"
+#+ * ID|ParticleSettings.effector_weights -> effector_weights: pointer, "(read-only)"
+#+ * ID|ParticleSettings.emit_from -> emit_from: enum "Where to emit particles from"
+#ID|ParticleSettings.factor_random -> factor_random: float "Give the starting speed a random variation"
+#+ * ID|ParticleSettings.fluid -> fluid: pointer, "(read-only)"
+#+ * ID|ParticleSettings.force_field_1 -> force_field_1: pointer, "(read-only)"
+#+ * ID|ParticleSettings.force_field_2 -> force_field_2: pointer, "(read-only)"
+#+ * ID|ParticleSettings.frame_end -> frame_end: float "Frame # to stop emitting particles"
+#+ * ID|ParticleSettings.frame_start -> frame_start: float "Frame # to start emitting particles"
+#+ * ID|ParticleSettings.grid_resolution -> grid_resolution: int "The resolution of the particle grid"
+#+ * ID|ParticleSettings.hair_step -> hair_step: int "Number of hair segments"
+#+ * ID|ParticleSettings.integrator -> integrator: enum "Select physics integrator type"
+#ID|ParticleSettings.invert_grid -> invert_grid: boolean "Invert what is considered object and what is not"
+#+ * ID|ParticleSettings.jitter_factor -> jitter_factor: float "Amount of jitter applied to the sampling"
+#+ * ID|ParticleSettings.keyed_loops -> keyed_loops: int "Number of times the keys are looped"
+#+ * ID|ParticleSettings.keys_step -> keys_step: int "NO DESCRIPTION"
+#+ * ID|ParticleSettings.kink -> kink: enum "Type of periodic offset on the path"
+#+ * ID|ParticleSettings.kink_amplitude -> kink_amplitude: float "The amplitude of the offset"
+#+ * ID|ParticleSettings.kink_axis -> kink_axis: enum "Which axis to use for offset"
+#+ * ID|ParticleSettings.kink_frequency -> kink_frequency: float "The frequency of the offset (1/total length)"
+#+ * ID|ParticleSettings.kink_shape -> kink_shape: float "Adjust the offset to the beginning/end"
+#ID|ParticleSettings.length_random -> length_random: float "Give path length a random variation"
+#+ * ID|ParticleSettings.lifetime -> lifetime: float "Specify the life span of the particles"
+#ID|ParticleSettings.lifetime_random -> lifetime_random: float "Give the particle life a random variation"
+#+ * ID|ParticleSettings.line_length_head -> line_length_head: float "Length of the lines head"
+#+ * ID|ParticleSettings.line_length_tail -> line_length_tail: float "Length of the lines tail"
+#ID|ParticleSettings.lock_billboard -> lock_billboard: boolean "Lock the billboards align axis"
+#ID|ParticleSettings.lock_boids_to_surface -> lock_boids_to_surface: boolean "Constrain boids to a surface"
+#+ * ID|ParticleSettings.mass -> mass: float "Specify the mass of the particles"
+#+ * ID|ParticleSettings.material -> material: int "Specify material used for the particles"
+#+ * ID|ParticleSettings.normal_factor -> normal_factor: float "Let the surface normal give the particle a starting speed"
+#ID|ParticleSettings.object_align_factor -> object_align_factor: float[3] "Let the emitter object orientation give the particle a starting speed"
+#+ * ID|ParticleSettings.object_factor -> object_factor: float "Let the object give the particle a starting speed"
+#+ * ID|ParticleSettings.particle_factor -> particle_factor: float "Let the target particle give the particle a starting speed"
+#+ * ID|ParticleSettings.particle_size -> particle_size: float "The size of the particles"
+#+ * ID|ParticleSettings.path_end -> path_end: float "End time of drawn path"
+#+ * ID|ParticleSettings.path_start -> path_start: float "Starting time of drawn path"
+#+ * ID|ParticleSettings.phase_factor -> phase_factor: float "Initial rotation phase"
+#ID|ParticleSettings.phase_factor_random -> phase_factor_random: float "Randomize rotation phase"
+#+ * ID|ParticleSettings.physics_type -> physics_type: enum "Particle physics type"
+#+ * ID|ParticleSettings.react_event -> react_event: enum "The event of target particles to react on"
+#+ * ID|ParticleSettings.reaction_shape -> reaction_shape: float "Power of reaction strength dependence on distance to target"
+#+ * ID|ParticleSettings.reactor_factor -> reactor_factor: float "Let the vector away from the target particles location give the particle a starting speed"
+#+ * ID|ParticleSettings.render_step -> render_step: int "How many steps paths are rendered with (power of 2)"
+#ID|ParticleSettings.render_type -> render_type: enum "How particles are rendered"
+#ID|ParticleSettings.rendered_child_count -> rendered_child_count: int "Amount of children/parent for rendering"
+#ID|ParticleSettings.rotation_factor_random -> rotation_factor_random: float "Randomize rotation"
+#+ * ID|ParticleSettings.rotation_mode -> rotation_mode: enum "Particles initial rotation"
+#ID|ParticleSettings.roughness_1 -> roughness_1: float "Amount of location dependent rough"
+#ID|ParticleSettings.roughness_1_size -> roughness_1_size: float "Size of location dependent rough"
+#ID|ParticleSettings.roughness_2 -> roughness_2: float "Amount of random rough"
+#ID|ParticleSettings.roughness_2_size -> roughness_2_size: float "Size of random rough"
+#ID|ParticleSettings.roughness_2_threshold -> roughness_2_threshold: float "Amount of particles left untouched by random rough"
+#ID|ParticleSettings.roughness_end_shape -> roughness_end_shape: float "Shape of end point rough"
+#ID|ParticleSettings.roughness_endpoint -> roughness_endpoint: float "Amount of end point rough"
+#ID|ParticleSettings.show_health -> show_health: boolean "Draw boid health"
+#ID|ParticleSettings.show_material_color -> show_material_color: boolean "Draw particles using materials diffuse color"
+#ID|ParticleSettings.show_number -> show_number: boolean "Show particle number"
+#+ * ID|ParticleSettings.show_size -> show_size: boolean "Show particle size"
+#ID|ParticleSettings.show_unborn -> show_unborn: boolean "Show particles before they are emitted"
+#ID|ParticleSettings.show_velocity -> show_velocity: boolean "Show particle velocity"
+#+ * ID|ParticleSettings.simplify_rate -> simplify_rate: float "Speed of simplification"
+#+ * ID|ParticleSettings.simplify_refsize -> simplify_refsize: int "Reference size in pixels, after which simplification begins"
+#+ * ID|ParticleSettings.simplify_transition -> simplify_transition: float "Transition period for fading out strands"
+#+ * ID|ParticleSettings.simplify_viewport -> simplify_viewport: float "Speed of Simplification"
+#ID|ParticleSettings.size_random -> size_random: float "Give the particle size a random variation"
+#+ * ID|ParticleSettings.subframes -> subframes: int "Subframes to simulate for improved stability and finer granularity simulations"
+#+ * ID|ParticleSettings.tangent_factor -> tangent_factor: float "Let the surface tangent give the particle a starting speed"
+#+ * ID|ParticleSettings.tangent_phase -> tangent_phase: float "Rotate the surface tangent"
+#+ * ID|ParticleSettings.time_tweak -> time_tweak: float "A multiplier for physics timestep (1.0 means one frame = 1/25 seconds)"
+#+ * ID|ParticleSettings.trail_count -> trail_count: int "Number of trail particles"
+#+ * ID|ParticleSettings.type -> type: enum "NO DESCRIPTION"
+#ID|ParticleSettings.use_absolute_path_time -> use_absolute_path_time: boolean "Path timing is in absolute frames"
+#ID|ParticleSettings.use_animate_branching -> use_animate_branching: boolean "Animate branching"
+#ID|ParticleSettings.use_branching -> use_branching: boolean "Branch child paths from each other"
+#ID|ParticleSettings.use_dead -> use_dead: boolean "Show particles after they have died"
+#ID|ParticleSettings.use_die_on_collision -> use_die_on_collision: boolean "Particles die when they collide with a deflector object"
+#ID|ParticleSettings.use_dynamic_rotation -> use_dynamic_rotation: boolean "Sets rotation to dynamic/constant"
+#ID|ParticleSettings.use_emit_random -> use_emit_random: boolean "Emit in random order of elements"
+#ID|ParticleSettings.use_even_distribution -> use_even_distribution: boolean "Use even distribution from faces based on face areas or edge lengths"
+#+ * ID|ParticleSettings.use_global_dupli -> use_global_dupli: boolean "Use objects global coordinates for duplication"
+#+ * ID|ParticleSettings.use_group_count -> use_group_count: boolean "Use object multiple times in the same group"
+#ID|ParticleSettings.use_group_pick_random -> use_group_pick_random: boolean "Pick objects from group randomly"
+#ID|ParticleSettings.use_hair_bspline -> use_hair_bspline: boolean "Interpolate hair using B-Splines"
+#ID|ParticleSettings.use_multiply_size_mass -> use_multiply_size_mass: boolean "Multiply mass by particle size"
+#ID|ParticleSettings.use_parent_particles -> use_parent_particles: boolean "Render parent particles"
+#ID|ParticleSettings.use_react_multiple -> use_react_multiple: boolean "React multiple times"
+#ID|ParticleSettings.use_react_start_end -> use_react_start_end: boolean "Give birth to unreacted particles eventually"
+#ID|ParticleSettings.use_render_adaptive -> use_render_adaptive: boolean "Draw steps of the particle path"
+#ID|ParticleSettings.use_render_emitter -> use_render_emitter: boolean "Render emitter Object also"
+#ID|ParticleSettings.use_self_effect -> use_self_effect: boolean "Particle effectors effect themselves"
+#ID|ParticleSettings.use_simplify -> use_simplify: boolean "Remove child strands as the object becomes smaller on the screen"
+#ID|ParticleSettings.use_simplify_viewport -> use_simplify_viewport: boolean "NO DESCRIPTION"
+#ID|ParticleSettings.use_size_deflect -> use_size_deflect: boolean "Use particles size in deflection"
+#ID|ParticleSettings.use_strand_primitive -> use_strand_primitive: boolean "Use the strand primitive for rendering"
+#ID|ParticleSettings.use_symmetric_branching -> use_symmetric_branching: boolean "Start and end points are the same"
+#ID|ParticleSettings.use_velocity_length -> use_velocity_length: boolean "Multiply line length by particle speed"
+#ID|ParticleSettings.use_whole_group -> use_whole_group: boolean "Use whole group at once"
+#+ * ID|ParticleSettings.userjit -> userjit: int "Emission locations / face (0 = automatic)"
+#+ * ID|ParticleSettings.virtual_parents -> virtual_parents: float "Relative amount of virtual parents"
+#+ * ID|Scene.active_keying_set_index -> active_keying_set_index: int "Current Keying Set index (negative for builtin and positive for absolute)"
+#+ * ID|Scene.animation_data -> animation_data: pointer, "(read-only) Animation data for this datablock"
+#ID|Scene.audio_distance_model -> audio_distance_model: enum "Distance model for distance attenuation calculation"
+#ID|Scene.audio_doppler_factor -> audio_doppler_factor: float "Pitch factor for Doppler effect calculation"
+#ID|Scene.audio_doppler_speed -> audio_doppler_speed: float "Speed of sound for Doppler effect calculation"
+#ID|Scene.background_set -> background_set: pointer "Background set scene"
+#+ * ID|Scene.camera -> camera: pointer "Active camera used for rendering the scene"
+#+ * ID|Scene.cursor_location -> cursor_location: float[3] "3D cursor location"
+#+ * ID|Scene.frame_current -> frame_current: int "NO DESCRIPTION"
+#+ * ID|Scene.frame_end -> frame_end: int "Final frame of the playback/rendering range"
+#ID|Scene.frame_preview_end -> frame_preview_end: int "Alternative end frame for UI playback"
+#ID|Scene.frame_preview_start -> frame_preview_start: int "Alternative start frame for UI playback"
+#+ * ID|Scene.frame_start -> frame_start: int "First frame of the playback/rendering range"
+#+ * ID|Scene.frame_step -> frame_step: int "Number of frames to skip forward while rendering/playing back each frame"
+#ID|Scene.game_settings -> game_settings: pointer, "(read-only)"
+#+ * ID|Scene.gravity -> gravity: float[3] "Constant acceleration in a given direction"
+#+ * ID|Scene.grease_pencil -> grease_pencil: pointer "Grease Pencil datablock"
+#ID|Scene.is_nla_tweakmode -> is_nla_tweakmode: boolean, "(read-only) Indicates whether there is any action referenced by NLA being edited. Strictly read-only"
+#+ * ID|Scene.keying_sets -> keying_sets: collection, "(read-only) Absolute Keying Sets for this Scene"
+#ID|Scene.keying_sets_all -> keying_sets_all: collection, "(read-only) All Keying Sets available for use (builtins and Absolute Keying Sets for this Scene)"
+#+ * ID|Scene.layers -> layers: boolean[20] "Layers visible when rendering the scene"
+#+ * ID|Scene.network_render -> network_render: pointer, "(read-only) Network Render Settings"
+#+ * ID|Scene.nodetree -> nodetree: pointer, "(read-only) Compositing node tree"
+#ID|Scene.object_bases -> object_bases: collection, "(read-only)"
+#+ * ID|Scene.objects -> objects: collection, "(read-only)"
+#+ * ID|Scene.orientations -> orientations: collection, "(read-only)"
+#+ * ID|Scene.pose_templates -> pose_templates: pointer, "(read-only) Pose Template Settings"
+#+ * ID|Scene.render -> render: pointer, "(read-only)"
+#+ * ID|Scene.sequence_editor -> sequence_editor: pointer, "(read-only)"
+#+ * ID|Scene.sync_mode -> sync_mode: enum "How to sync playback"
+#+ * ID|Scene.timeline_markers -> timeline_markers: collection, "(read-only) Markers used in all timelines for the current scene"
+#+ * ID|Scene.tool_settings -> tool_settings: pointer, "(read-only)"
+#+ * ID|Scene.unit_settings -> unit_settings: pointer, "(read-only) Unit editing settings"
+#ID|Scene.use_audio -> use_audio: boolean "Play back of audio from Sequence Editor will be muted"
+#ID|Scene.use_audio_scrub -> use_audio_scrub: boolean "Play audio from Sequence Editor while scrubbing"
+#ID|Scene.use_audio_sync -> use_audio_sync: boolean "Play back and sync with audio clock, dropping frames if frame display is too slow"
+#ID|Scene.use_frame_drop -> use_frame_drop: boolean "Play back dropping frames if frame display is too slow"
+#+ * ID|Scene.use_gravity -> use_gravity: boolean "Use global gravity for all dynamics"
+#+ * ID|Scene.use_nodes -> use_nodes: boolean "Enable the compositing node tree"
+#+ * ID|Scene.use_preview_range -> use_preview_range: boolean "Use an alternative start/end frame for UI playback, rather than the scene start/end frame"
+#ID|Scene.use_stamp_note -> use_stamp_note: string "User define note for the render stamping"
+#+ * ID|Scene.world -> world: pointer "World used for rendering the scene"
+#+ * ID|Screen.areas -> areas: collection, "(read-only) Areas the screen is subdivided into"
+#ID|Screen.is_animation_playing -> is_animation_playing: boolean, "(read-only) Animation playback is active"
+#+ * ID|Screen.scene -> scene: pointer "Active scene to be edited in the screen"
+#ID|Screen.show_fullscreen -> show_fullscreen: boolean, "(read-only) An area is maximised, filling this screen"
+#+ * ID|Sound.filepath -> filepath: string "Sound sample file used by this Sound datablock"
+#+ * ID|Sound.packed_file -> packed_file: pointer, "(read-only)"
+#ID|Sound.use_memory_cache -> use_memory_cache: boolean "The sound file is decoded and loaded into RAM"
+#+ * ID|Text.current_character -> current_character: int, "(read-only) Index of current character in current line, and also start index of character in selection if one exists"
+#+ * ID|Text.current_line -> current_line: pointer, "(read-only) Current line, and start line of selection if one exists"
+#+ * ID|Text.filepath -> filepath: string "Filename of the text file"
+#ID|Text.is_dirty -> is_dirty: boolean, "(read-only) Text file has been edited since last save"
+#ID|Text.is_in_memory -> is_in_memory: boolean, "(read-only) Text file is in memory, without a corresponding file on disk"
+#ID|Text.is_modified -> is_modified: boolean, "(read-only) Text file on disk is different than the one in memory"
+#+ * ID|Text.lines -> lines: collection, "(read-only) Lines of text"
+#+ * ID|Text.markers -> markers: collection, "(read-only) Text markers highlighting part of the text"
+#ID|Text.select_end_character -> select_end_character: int, "(read-only) Index of character after end of selection in the selection end line"
+#ID|Text.select_end_line -> select_end_line: pointer, "(read-only) End line of selection"
+#+ * ID|Text.use_module -> use_module: boolean "Register this text as a module on loading, Text name must end with .py"
+#ID|Text.use_tabs_as_spaces -> use_tabs_as_spaces: boolean "Automatically converts all new tabs into spaces"
+#+ * ID|Texture.animation_data -> animation_data: pointer, "(read-only) Animation data for this datablock"
+#+ * ID|Texture.color_ramp -> color_ramp: pointer, "(read-only)"
+#+ * ID|Texture.contrast -> contrast: float "NO DESCRIPTION"
+#+TODO MAKE COLOR * ID|Texture.factor_blue -> factor_blue: float "NO DESCRIPTION"
+#+TODO MAKE COLOR * ID|Texture.factor_green -> factor_green: float "NO DESCRIPTION"
+#+TODO MAKE COLOR * ID|Texture.factor_red -> factor_red: float "NO DESCRIPTION"
+#ID|Texture.intensity -> intensity: float "NO DESCRIPTION"
+#+ * ID|Texture.node_tree -> node_tree: pointer, "(read-only) Node tree for node-based textures"
+#+ * ID|Texture.saturation -> saturation: float "NO DESCRIPTION"
+#+ * ID|Texture.type -> type: enum "NO DESCRIPTION"
+#+ * ID|Texture.use_color_ramp -> use_color_ramp: boolean "Toggle color ramp operations"
+#+ * ID|Texture.use_nodes -> use_nodes: boolean "Make this a node-based texture"
+#+ * ID|Texture.use_preview_alpha -> use_preview_alpha: boolean "Show Alpha in Preview Render"
+#+ * ID|Texture|BlendTexture.progression -> progression: enum "Sets the style of the color blending"
+#ID|Texture|BlendTexture.use_flip_axis -> use_flip_axis: enum "Flips the textures X and Y axis"
+#ID|Texture|CloudsTexture.cloud_type -> cloud_type: enum "NO DESCRIPTION"
+#+ * ID|Texture|CloudsTexture.nabla -> nabla: float "Size of derivative offset used for calculating normal"
+#+ * ID|Texture|CloudsTexture.noise_basis -> noise_basis: enum "Sets the noise basis used for turbulence"
+#+ * ID|Texture|CloudsTexture.noise_depth -> noise_depth: int "Sets the depth of the cloud calculation"
+#ID|Texture|CloudsTexture.noise_scale -> noise_scale: float "Sets scaling for noise input"
+#+ * ID|Texture|CloudsTexture.noise_type -> noise_type: enum "NO DESCRIPTION"
+#+ * ID|Texture|DistortedNoiseTexture.distortion -> distortion: float "NO DESCRIPTION"
+#+ * ID|Texture|DistortedNoiseTexture.nabla -> nabla: float "Size of derivative offset used for calculating normal"
+#+ * ID|Texture|DistortedNoiseTexture.noise_basis -> noise_basis: enum "Sets the noise basis used for turbulence"
+#+ * ID|Texture|DistortedNoiseTexture.noise_distortion -> noise_distortion: enum "Sets the noise basis for the distortion"
+#ID|Texture|DistortedNoiseTexture.noise_scale -> noise_scale: float "Sets scaling for noise input"
+#+ * ID|Texture|EnvironmentMapTexture.environment_map -> environment_map: pointer, "(read-only) Gets the environment map associated with this texture"
+#+ * ID|Texture|EnvironmentMapTexture.filter_eccentricity -> filter_eccentricity: int "Maximum eccentricity. Higher gives less blur at distant/oblique angles, but is also slower"
+#+ * ID|Texture|EnvironmentMapTexture.filter_probes -> filter_probes: int "Maximum number of samples. Higher gives less blur at distant/oblique angles, but is also slower"
+#+ * ID|Texture|EnvironmentMapTexture.filter_size -> filter_size: float "Multiplies the filter size used by MIP Map and Interpolation"
+#ID|Texture|EnvironmentMapTexture.filter_type -> filter_type: enum "Texture filter to use for sampling image"
+#+ * ID|Texture|EnvironmentMapTexture.image -> image: pointer "Source image file to read the environment map from"
+#+ * ID|Texture|EnvironmentMapTexture.image_user -> image_user: pointer, "(read-only) Parameters defining which layer, pass and frame of the image is displayed"
+#ID|Texture|EnvironmentMapTexture.use_filter_size_min -> use_filter_size_min: boolean "Use Filter Size as a minimal filter value in pixels"
+#ID|Texture|EnvironmentMapTexture.use_mipmap -> use_mipmap: boolean "Uses auto-generated MIP maps for the image"
+#ID|Texture|EnvironmentMapTexture.use_mipmap_gauss -> use_mipmap_gauss: boolean "Uses Gauss filter to sample down MIP maps"
+#+ * ID|Texture|ImageTexture.checker_distance -> checker_distance: float "Sets distance between checker tiles"
+#+ * ID|Texture|ImageTexture.crop_max_x -> crop_max_x: float "Sets maximum X value to crop the image"
+#+ * ID|Texture|ImageTexture.crop_max_y -> crop_max_y: float "Sets maximum Y value to crop the image"
+#+ * ID|Texture|ImageTexture.crop_min_x -> crop_min_x: float "Sets minimum X value to crop the image"
+#+ * ID|Texture|ImageTexture.crop_min_y -> crop_min_y: float "Sets minimum Y value to crop the image"
+#+ * ID|Texture|ImageTexture.extension -> extension: enum "Sets how the image is extrapolated past its original bounds"
+#+ * ID|Texture|ImageTexture.filter_eccentricity -> filter_eccentricity: int "Maximum eccentricity. Higher gives less blur at distant/oblique angles, but is also slower"
+#+ * ID|Texture|ImageTexture.filter_probes -> filter_probes: int "Maximum number of samples. Higher gives less blur at distant/oblique angles, but is also slower"
+#+ * ID|Texture|ImageTexture.filter_size -> filter_size: float "Multiplies the filter size used by MIP Map and Interpolation"
+#ID|Texture|ImageTexture.filter_type -> filter_type: enum "Texture filter to use for sampling image"
+#+ * ID|Texture|ImageTexture.image -> image: pointer "NO DESCRIPTION"
+#+ * ID|Texture|ImageTexture.image_user -> image_user: pointer, "(read-only) Parameters defining which layer, pass and frame of the image is displayed"
+#+ * ID|Texture|ImageTexture.invert_alpha -> invert_alpha: boolean "Inverts all the alpha values in the image"
+#+ * ID|Texture|ImageTexture.normal_space -> normal_space: enum "Sets space of normal map image"
+#+ * ID|Texture|ImageTexture.repeat_x -> repeat_x: int "Sets a repetition multiplier in the X direction"
+#+ * ID|Texture|ImageTexture.repeat_y -> repeat_y: int "Sets a repetition multiplier in the Y direction"
+#+ * ID|Texture|ImageTexture.use_alpha -> use_alpha: boolean "Uses the alpha channel information in the image"
+#ID|Texture|ImageTexture.use_calculate_alpha -> use_calculate_alpha: boolean "Calculates an alpha channel based on RGB values in the image"
+#ID|Texture|ImageTexture.use_checker_even -> use_checker_even: boolean "Sets even checker tiles"
+#ID|Texture|ImageTexture.use_checker_odd -> use_checker_odd: boolean "Sets odd checker tiles"
+#ID|Texture|ImageTexture.use_filter_size_min -> use_filter_size_min: boolean "Use Filter Size as a minimal filter value in pixels"
+#ID|Texture|ImageTexture.use_flip_axis -> use_flip_axis: boolean "Flips the textures X and Y axis"
+#ID|Texture|ImageTexture.use_interpolation -> use_interpolation: boolean "Interpolates pixels using Area filter"
+#ID|Texture|ImageTexture.use_mipmap -> use_mipmap: boolean "Uses auto-generated MIP maps for the image"
+#ID|Texture|ImageTexture.use_mipmap_gauss -> use_mipmap_gauss: boolean "Uses Gauss filter to sample down MIP maps"
+#ID|Texture|ImageTexture.use_mirror_x -> use_mirror_x: boolean "Mirrors the image repetition on the X direction"
+#ID|Texture|ImageTexture.use_mirror_y -> use_mirror_y: boolean "Mirrors the image repetition on the Y direction"
+#ID|Texture|ImageTexture.use_normal_map -> use_normal_map: boolean "Uses image RGB values for normal mapping"
+#+ * ID|Texture|MagicTexture.noise_depth -> noise_depth: int "Sets the depth of the cloud calculation"
+#+ * ID|Texture|MagicTexture.turbulence -> turbulence: float "Sets the turbulence of the bandnoise and ringnoise types"
+#ID|Texture|MarbleTexture.marble_type -> marble_type: enum "NO DESCRIPTION"
+#+ * ID|Texture|MarbleTexture.nabla -> nabla: float "Size of derivative offset used for calculating normal"
+#+ * ID|Texture|MarbleTexture.noise_basis -> noise_basis: enum "Sets the noise basis used for turbulence"
+#+ * ID|Texture|MarbleTexture.noise_depth -> noise_depth: int "Sets the depth of the cloud calculation"
+#ID|Texture|MarbleTexture.noise_scale -> noise_scale: float "Sets scaling for noise input"
+#+ * ID|Texture|MarbleTexture.noise_type -> noise_type: enum "NO DESCRIPTION"
+#ID|Texture|MarbleTexture.noisebasis_2 -> noisebasis_2: enum "NO DESCRIPTION"
+#+ * ID|Texture|MarbleTexture.turbulence -> turbulence: float "Sets the turbulence of the bandnoise and ringnoise types"
+#ID|Texture|MusgraveTexture.dimension_max -> dimension_max: float "Highest fractal dimension"
+#+ * ID|Texture|MusgraveTexture.gain -> gain: float "The gain multiplier"
+#+ * ID|Texture|MusgraveTexture.lacunarity -> lacunarity: float "Gap between successive frequencies"
+#+ * ID|Texture|MusgraveTexture.musgrave_type -> musgrave_type: enum "NO DESCRIPTION"
+#+ * ID|Texture|MusgraveTexture.nabla -> nabla: float "Size of derivative offset used for calculating normal"
+#+ * ID|Texture|MusgraveTexture.noise_basis -> noise_basis: enum "Sets the noise basis used for turbulence"
+#+ * ID|Texture|MusgraveTexture.noise_intensity -> noise_intensity: float "NO DESCRIPTION"
+#ID|Texture|MusgraveTexture.noise_scale -> noise_scale: float "Sets scaling for noise input"
+#+ * ID|Texture|MusgraveTexture.octaves -> octaves: float "Number of frequencies used"
+#+ * ID|Texture|MusgraveTexture.offset -> offset: float "The fractal offset"
+#ID|Texture|PointDensityTexture.point_density -> point_density: pointer, "(read-only) The point density settings associated with this texture"
+#+ * ID|Texture|StucciTexture.noise_basis -> noise_basis: enum "Sets the noise basis used for turbulence"
+#ID|Texture|StucciTexture.noise_scale -> noise_scale: float "Sets scaling for noise input"
+#+ * ID|Texture|StucciTexture.noise_type -> noise_type: enum "NO DESCRIPTION"
+#ID|Texture|StucciTexture.stucci_type -> stucci_type: enum "NO DESCRIPTION"
+#+ * ID|Texture|StucciTexture.turbulence -> turbulence: float "Sets the turbulence of the bandnoise and ringnoise types"
+#ID|Texture|VoronoiTexture.color_mode -> color_mode: enum "NO DESCRIPTION"
+#+ * ID|Texture|VoronoiTexture.distance_metric -> distance_metric: enum "NO DESCRIPTION"
+#+ * ID|Texture|VoronoiTexture.minkovsky_exponent -> minkovsky_exponent: float "Minkovsky exponent"
+#+ * ID|Texture|VoronoiTexture.nabla -> nabla: float "Size of derivative offset used for calculating normal"
+#+ * ID|Texture|VoronoiTexture.noise_intensity -> noise_intensity: float "NO DESCRIPTION"
+#ID|Texture|VoronoiTexture.noise_scale -> noise_scale: float "Sets scaling for noise input"
+#+ * ID|Texture|VoronoiTexture.weight_1 -> weight_1: float "Voronoi feature weight 1"
+#+ * ID|Texture|VoronoiTexture.weight_2 -> weight_2: float "Voronoi feature weight 2"
+#+ * ID|Texture|VoronoiTexture.weight_3 -> weight_3: float "Voronoi feature weight 3"
+#+ * ID|Texture|VoronoiTexture.weight_4 -> weight_4: float "Voronoi feature weight 4"
+#+ * ID|Texture|VoxelDataTexture.image -> image: pointer "NO DESCRIPTION"
+#+ * ID|Texture|VoxelDataTexture.image_user -> image_user: pointer, "(read-only) Parameters defining which layer, pass and frame of the image is displayed"
+#ID|Texture|VoxelDataTexture.voxel_data -> voxel_data: pointer, "(read-only) The voxel data associated with this texture"
+#+ * ID|Texture|WoodTexture.nabla -> nabla: float "Size of derivative offset used for calculating normal"
+#+ * ID|Texture|WoodTexture.noise_basis -> noise_basis: enum "Sets the noise basis used for turbulence"
+#ID|Texture|WoodTexture.noise_scale -> noise_scale: float "Sets scaling for noise input"
+#+ * ID|Texture|WoodTexture.noise_type -> noise_type: enum "NO DESCRIPTION"
+#ID|Texture|WoodTexture.noisebasis_2 -> noisebasis_2: enum "NO DESCRIPTION"
+#+ * ID|Texture|WoodTexture.turbulence -> turbulence: float "Sets the turbulence of the bandnoise and ringnoise types"
+#ID|Texture|WoodTexture.wood_type -> wood_type: enum "NO DESCRIPTION"
+#+ * ID|VectorFont.filepath -> filepath: string, "(read-only)"
+#+ * ID|VectorFont.packed_file -> packed_file: pointer, "(read-only)"
+#+ * ID|WindowManager.keyconfigs -> keyconfigs: collection, "(read-only) Registered key configurations"
+#+ * ID|WindowManager.operators -> operators: collection, "(read-only) Operator registry"
+#+ * ID|WindowManager.windows -> windows: collection, "(read-only) Open windows"
+#+ * ID|World.active_texture -> active_texture: pointer "Active texture slot being displayed"
+#+ * ID|World.active_texture_index -> active_texture_index: int "Index of active texture slot"
+#+ * ID|World.ambient_color -> ambient_color: float[3] "NO DESCRIPTION"
+#+ * ID|World.animation_data -> animation_data: pointer, "(read-only) Animation data for this datablock"
+#ID|World.color_range -> color_range: float "The color range that will be mapped to 0-1"
+#+ * ID|World.exposure -> exposure: float "Amount of exponential color correction for light"
+#+ * ID|World.horizon_color -> horizon_color: float[3] "Color at the horizon"
+#ID|World.light_settings -> light_settings: pointer, "(read-only) World lighting settings"
+#ID|World.mist_settings -> mist_settings: pointer, "(read-only) World mist settings"
+#ID|World.star_settings -> star_settings: pointer, "(read-only) World stars settings"
+#+ * ID|World.texture_slots -> texture_slots: collection, "(read-only) Texture slots defining the mapping and influence of textures"
+#ID|World.use_sky_blend -> use_sky_blend: boolean "Render background with natural progression from horizon to zenith"
+#ID|World.use_sky_paper -> use_sky_paper: boolean "Flatten blend or texture coordinates"
+#ID|World.use_sky_real -> use_sky_real: boolean "Render background with a real horizon, relative to the camera angle"
+#+ * ID|World.zenith_color -> zenith_color: float[3] "Color at the zenith"
+#+ * IKParam.ik_solver -> ik_solver: enum, "(read-only) IK solver for which these parameters are defined, 0 for Legacy, 1 for iTaSC"
+#IKParam|Itasc.damping_epsilon -> damping_epsilon: float "Singular value under which damping is progressively applied. Higher values=more stability, less reactivity. Default=0.1"
+#IKParam|Itasc.damping_max -> damping_max: float "Maximum damping coefficient when singular value is nearly 0. Higher values=more stability, less reactivity. Default=0.5"
+#+ * IKParam|Itasc.feedback -> feedback: float "Feedback coefficient for error correction. Average response time=1/feedback. Default=20"
+#IKParam|Itasc.iterations -> iterations: int "Maximum number of iterations for convergence in case of reiteration"
+#+ * IKParam|Itasc.mode -> mode: enum "NO DESCRIPTION"
+#+ * IKParam|Itasc.precision -> precision: float "Precision of convergence in case of reiteration"
+#IKParam|Itasc.reiteration_method -> reiteration_method: enum "Defines if the solver is allowed to reiterate (converges until precision is met) on none, first or all frames"
+#+ * IKParam|Itasc.solver -> solver: enum "Solving method selection: Automatic damping or manual damping"
+#IKParam|Itasc.step_count -> step_count: int "Divides the frame interval into this many steps"
+#IKParam|Itasc.step_max -> step_max: float "Higher bound for timestep in second in case of automatic substeps"
+#IKParam|Itasc.step_min -> step_min: float "Lower bound for timestep in second in case of automatic substeps"
+#IKParam|Itasc.use_auto_step -> use_auto_step: boolean "Automatically determine the optimal number of steps for best performance/accuracy trade off"
+#IKParam|Itasc.velocity_max -> velocity_max: float "Maximum joint velocity in rad/s. Default=50"
+#+ * ImageUser.fields_per_frame -> fields_per_frame: int "The number of fields per rendered frame (2 fields is 1 image)"
+#ImageUser.frame_duration -> frame_duration: int "Sets the number of images of a movie to use"
+#ImageUser.frame_offset -> frame_offset: int "Offsets the number of the frame to use in the animation"
+#+ * ImageUser.frame_start -> frame_start: int "Sets the global starting frame of the movie"
+#+ * ImageUser.multilayer_layer -> multilayer_layer: int, "(read-only) Layer in multilayer image"
+#+ * ImageUser.multilayer_pass -> multilayer_pass: int, "(read-only) Pass in multilayer image"
+#ImageUser.use_auto_refresh -> use_auto_refresh: boolean "Always refresh image on frame changes"
+#ImageUser.use_cyclic -> use_cyclic: boolean "Cycle the images in the movie"
+#KeyConfig.is_user_defined -> is_user_defined: boolean, "(read-only) Indicates that a keyconfig was defined by the user"
+#+ * KeyConfig.keymaps -> keymaps: collection, "(read-only) Key maps configured as part of this configuration"
+#+ * KeyConfig.name -> name: string "Name of the key configuration"
+#KeyConfigurations.active -> active: pointer "Active wm KeyConfig"
+#KeyConfigurations.default -> default: pointer, "(read-only)"
+#KeyMap.is_modal -> is_modal: boolean, "(read-only) Indicates that a keymap is used for translate modal events for an operator"
+#KeyMap.is_user_defined -> is_user_defined: boolean "Keymap is defined by the user"
+#+ * KeyMap.items -> items: collection, "(read-only) Items in the keymap, linking an operator to an input event"
+#+ * KeyMap.name -> name: string, "(read-only) Name of the key map"
+#+ * KeyMap.region_type -> region_type: enum, "(read-only) Optional region type keymap is associated with"
+#KeyMap.show_expanded_children -> show_expanded_children: boolean "Children expanded in the user interface"
+#KeyMap.show_expanded_items -> show_expanded_items: boolean "Expanded in the user interface"
+#+ * KeyMap.space_type -> space_type: enum, "(read-only) Optional space type keymap is associated with"
+#TODO MOVE TO COLLECTION * KeyMapItem.active -> active: boolean "Activate or deactivate item"
+#+ * KeyMapItem.id -> id: int, "(read-only) ID of the item"
+#+ * KeyMapItem.idname -> idname: string "Identifier of operator to call on input event"
+#+ * KeyMapItem.key_modifier -> key_modifier: enum "Regular key pressed as a modifier"
+#+ * KeyMapItem.map_type -> map_type: enum "Type of event mapping"
+#+ * KeyMapItem.name -> name: string, "(read-only) Name of operator to call on input event"
+ + * KeyMapItem.alt -> pressed_alt: boolean "Alt key pressed"
+ + * KeyMapItem.any -> pressed_any: boolean "Any modifier keys pressed"
+ + * KeyMapItem.ctrl -> pressed_ctrl: boolean "Control key pressed"
+ + * KeyMapItem.oskey -> pressed_oskey: boolean "Operating system key pressed"
+ + * KeyMapItem.shift -> pressed_shift: boolean "Shift key pressed"
+#+ * KeyMapItem.properties -> properties: pointer, "(read-only) Properties to set when the operator is called"
+#TODO * KeyMapItem.propvalue -> propvalue: enum "The value this event translates to in a modal keymap"
+#KeyMapItem.show_expanded -> show_expanded: boolean "Show key map event and property details in the user interface"
+#+ * KeyMapItem.type -> type: enum "Type of event"
+#+ * KeyMapItem.value -> value: enum "NO DESCRIPTION"
+#+ * Keyframe.co -> co: float[2] "Coordinates of the control point"
+#Keyframe.handle_left -> handle_left: float[2] "Coordinates of the first handle"
+#Keyframe.handle_left_type -> handle_left_type: enum "Handle types"
+#Keyframe.handle_right -> handle_right: float[2] "Coordinates of the second handle"
+#Keyframe.handle_right_type -> handle_right_type: enum "Handle types"
+#+ * Keyframe.interpolation -> interpolation: enum "Interpolation method to use for segment of the curve from this Keyframe until the next Keyframe"
+#+ * Keyframe.select_control_point -> select_control_point: boolean "Control point selection status"
+#+ * Keyframe.select_left_handle -> select_left_handle: boolean "Handle 1 selection status"
+#+ * Keyframe.select_right_handle -> select_right_handle: boolean "Handle 2 selection status"
+#+ * Keyframe.type -> type: enum "The type of keyframe"
+#+ * KeyingSet.active_path_index -> active_path_index: int "Current Keying Set index"
+#KeyingSet.is_path_absolute -> is_path_absolute: boolean, "(read-only) Keying Set defines specific paths/settings to be keyframed (i.e. is not reliant on context info)"
+#+ * KeyingSet.name -> name: string "NO DESCRIPTION"
+#+ * KeyingSet.paths -> paths: collection, "(read-only) Keying Set Paths to define settings that get keyframed together"
+#+ * KeyingSet.type_info -> type_info: pointer, "(read-only) Callback function defines for built-in Keying Sets"
+#KeyingSet.use_insertkey_needed -> use_insertkey_needed: boolean "Only insert keyframes where theyre needed in the relevant F-Curves"
+#KeyingSet.use_insertkey_visual -> use_insertkey_visual: boolean "Insert keyframes based on visual transforms"
+#KeyingSet.use_insertkey_xyz_to_rgb -> use_insertkey_xyz_to_rgb: boolean "Color for newly added transformation F-Curves (Location, Rotation, Scale) and also Color is based on the transform axis"
+#+ * KeyingSetInfo.bl_idname -> bl_idname: string "NO DESCRIPTION"
+#+ * KeyingSetInfo.bl_label -> bl_label: string "NO DESCRIPTION"
+#KeyingSetInfo.use_insertkey_needed -> use_insertkey_needed: boolean "Only insert keyframes where theyre needed in the relevant F-Curves"
+#KeyingSetInfo.use_insertkey_visual -> use_insertkey_visual: boolean "Insert keyframes based on visual transforms"
+#KeyingSetInfo.use_insertkey_xyz_to_rgb -> use_insertkey_xyz_to_rgb: boolean "Color for newly added transformation F-Curves (Location, Rotation, Scale) and also Color is based on the transform axis"
+#+ * KeyingSetPath.array_index -> array_index: int "Index to the specific setting if applicable"
+#+ * KeyingSetPath.data_path -> data_path: string "Path to property setting"
+#+ * KeyingSetPath.group -> group: string "Name of Action Group to assign setting(s) for this path to"
+#KeyingSetPath.group_method -> group_method: enum "Method used to define which Group-name to use"
+#+ * KeyingSetPath.id -> id: pointer "ID-Block that keyframes for Keying Set should be added to (for Absolute Keying Sets only)"
+#+ * KeyingSetPath.id_type -> id_type: enum "Type of ID-block that can be used"
+#KeyingSetPath.use_entire_array -> use_entire_array: boolean "When an array/vector type is chosen (Location, Rotation, Color, etc.), entire array is to be used"
+#KeyingSetPath.use_insertkey_needed -> use_insertkey_needed: boolean "Only insert keyframes where theyre needed in the relevant F-Curves"
+#KeyingSetPath.use_insertkey_visual -> use_insertkey_visual: boolean "Insert keyframes based on visual transforms"
+#KeyingSetPath.use_insertkey_xyz_to_rgb -> use_insertkey_xyz_to_rgb: boolean "Color for newly added transformation F-Curves (Location, Rotation, Scale) and also Color is based on the transform axis"
+#KeyingSetPaths.active -> active: pointer "Active Keying Set used to insert/delete keyframes"
+#KeyingSets.active -> active: pointer "Active Keying Set used to insert/delete keyframes"
+#+ * LampSkySettings.atmosphere_distance_factor -> atmosphere_distance_factor: float "Multiplier to convert blender units to physical distance"
+#+ * LampSkySettings.atmosphere_extinction -> atmosphere_extinction: float "Extinction scattering contribution factor"
+#+ * LampSkySettings.atmosphere_inscattering -> atmosphere_inscattering: float "Scatter contribution factor"
+#+ * LampSkySettings.atmosphere_turbidity -> atmosphere_turbidity: float "Sky turbidity"
+#+ * LampSkySettings.backscattered_light -> backscattered_light: float "Backscattered light"
+#+ * LampSkySettings.horizon_brightness -> horizon_brightness: float "Horizon brightness"
+#+ * LampSkySettings.sky_blend -> sky_blend: float "Blend factor with sky"
+#+ * LampSkySettings.sky_blend_type -> sky_blend_type: enum "Blend mode for combining sun sky with world sky"
+#+ * LampSkySettings.sky_color_space -> sky_color_space: enum "Color space to use for internal XYZ->RGB color conversion"
+#+ * LampSkySettings.sky_exposure -> sky_exposure: float "Strength of sky shading exponential exposure correction"
+#+ * LampSkySettings.spread -> spread: float "Horizon Spread"
+#+ * LampSkySettings.sun_brightness -> sun_brightness: float "Sun brightness"
+#+ * LampSkySettings.sun_intensity -> sun_intensity: float "Sun intensity"
+#+ * LampSkySettings.sun_size -> sun_size: float "Sun size"
+#+ * LampSkySettings.use_atmosphere -> use_atmosphere: boolean "Apply sun effect on atmosphere"
+#+ * LampSkySettings.use_sky -> use_sky: boolean "Apply sun effect on sky"
+#+ * LatticePoint.co -> co: float[3], "(read-only)"
+#LatticePoint.co_deform -> co_deform: float[3] "NO DESCRIPTION"
+#+ * LatticePoint.groups -> groups: collection, "(read-only) Weights for the vertex groups this point is member of"
+#+ * Macro.bl_description -> bl_description: string "NO DESCRIPTION"
+#+ * Macro.bl_idname -> bl_idname: string "NO DESCRIPTION"
+#+ * Macro.bl_label -> bl_label: string "NO DESCRIPTION"
+#+ * Macro.bl_options -> bl_options: enum "Options for this operator type"
+#+ * Macro.name -> name: string, "(read-only)"
+#+ * Macro.properties -> properties: pointer, "(read-only)"
+#+ * Main.actions -> actions: collection, "(read-only) Action datablocks."
+#+ * Main.armatures -> armatures: collection, "(read-only) Armature datablocks."
+#+ * Main.brushes -> brushes: collection, "(read-only) Brush datablocks."
+#+ * Main.cameras -> cameras: collection, "(read-only) Camera datablocks."
+#+ * Main.curves -> curves: collection, "(read-only) Curve datablocks."
+#+ * Main.filepath -> filepath: string, "(read-only) Path to the .blend file"
+#+ * Main.fonts -> fonts: collection, "(read-only) Vector font datablocks."
+#Main.grease_pencil -> grease_pencil: collection, "(read-only) Grease Pencil datablocks."
+#+ * Main.groups -> groups: collection, "(read-only) Group datablocks."
+#+ * Main.images -> images: collection, "(read-only) Image datablocks."
+#Main.is_dirty -> is_dirty: boolean, "(read-only) Has the current session been saved to disk as a .blend file"
+#+ * Main.lamps -> lamps: collection, "(read-only) Lamp datablocks."
+#+ * Main.lattices -> lattices: collection, "(read-only) Lattice datablocks."
+#+ * Main.libraries -> libraries: collection, "(read-only) Library datablocks."
+#+ * Main.materials -> materials: collection, "(read-only) Material datablocks."
+#+ * Main.meshes -> meshes: collection, "(read-only) Mesh datablocks."
+#+ * Main.metaballs -> metaballs: collection, "(read-only) Metaball datablocks."
+#+ * Main.node_groups -> node_groups: collection, "(read-only) Node group datablocks."
+#+ * Main.objects -> objects: collection, "(read-only) Object datablocks."
+#+ * Main.particles -> particles: collection, "(read-only) Particle datablocks."
+#+ * Main.scenes -> scenes: collection, "(read-only) Scene datablocks."
+#+ * Main.screens -> screens: collection, "(read-only) Screen datablocks."
+#+ * Main.scripts -> scripts: collection, "(read-only) Script datablocks (DEPRECATED)."
+ + * Main.debug -> show_debug: boolean "Print debugging information in console"
+#+ * Main.sounds -> sounds: collection, "(read-only) Sound datablocks."
+#+ * Main.texts -> texts: collection, "(read-only) Text datablocks."
+#+ * Main.textures -> textures: collection, "(read-only) Texture datablocks."
+#+ * Main.window_managers -> window_managers: collection, "(read-only) Window manager datablocks."
+#+ * Main.worlds -> worlds: collection, "(read-only) World datablocks."
+#+ * MaterialHalo.add -> add: float "Sets the strength of the add effect"
+#+ * MaterialHalo.flare_boost -> flare_boost: float "Gives the flare extra strength"
+#+ * MaterialHalo.flare_seed -> flare_seed: int "Specifies an offset in the flare seed table"
+#+ * MaterialHalo.flare_size -> flare_size: float "Sets the factor by which the flare is larger than the halo"
+#MaterialHalo.flare_subflare_count -> flare_subflare_count: int "Sets the number of subflares"
+#MaterialHalo.flare_subflare_size -> flare_subflare_size: float "Sets the dimension of the subflares, dots and circles"
+#+ * MaterialHalo.hardness -> hardness: int "Sets the hardness of the halo"
+#MaterialHalo.line_count -> line_count: int "Sets the number of star shaped lines rendered over the halo"
+#MaterialHalo.ring_count -> ring_count: int "Sets the number of rings rendered over the halo"
+#+ * MaterialHalo.seed -> seed: int "Randomizes ring dimension and line location"
+#+ * MaterialHalo.size -> size: float "Sets the dimension of the halo"
+#MaterialHalo.star_tip_count -> star_tip_count: int "Sets the number of points on the star shaped halo"
+#MaterialHalo.use_extreme_alpha -> use_extreme_alpha: boolean "Uses extreme alpha"
+#MaterialHalo.use_flare_mode -> use_flare_mode: boolean "Renders halo as a lensflare"
+#MaterialHalo.use_lines -> use_lines: boolean "Renders star shaped lines over halo"
+#MaterialHalo.use_ring -> use_ring: boolean "Renders rings over halo"
+#MaterialHalo.use_shaded -> use_shaded: boolean "Lets halo receive light and shadows from external objects"
+#MaterialHalo.use_soft -> use_soft: boolean "Softens the edges of halos at intersections with other geometry"
+#MaterialHalo.use_star -> use_star: boolean "Renders halo as a star"
+#MaterialHalo.use_texture -> use_texture: boolean "Gives halo a texture"
+#MaterialHalo.use_vertex_normal -> use_vertex_normal: boolean "Uses the vertex normal to specify the dimension of the halo"
+#MaterialPhysics.damping -> damping: float "Damping of the spring force, when inside the physics distance area"
+#+ * MaterialPhysics.distance -> distance: float "Distance of the physics area"
+#+ * MaterialPhysics.elasticity -> elasticity: float "Elasticity of collisions"
+#+ * MaterialPhysics.force -> force: float "Upward spring force, when inside the physics distance area"
+#+ * MaterialPhysics.friction -> friction: float "Coulomb friction coefficient, when inside the physics distance area"
+#MaterialPhysics.use_normal_align -> use_normal_align: boolean "Align dynamic game objects along the surface normal, when inside the physics distance area"
+#+ * MaterialRaytraceMirror.depth -> depth: int "Maximum allowed number of light inter-reflections"
+#+ * MaterialRaytraceMirror.distance -> distance: float "Maximum distance of reflected rays. Reflections further than this range fade to sky color or material color"
+#+ * MaterialRaytraceMirror.fade_to -> fade_to: enum "The color that rays with no intersection within the Max Distance take. Material color can be best for indoor scenes, sky color for outdoor"
+#+ * MaterialRaytraceMirror.fresnel -> fresnel: float "Power of Fresnel for mirror reflection"
+#+ * MaterialRaytraceMirror.fresnel_factor -> fresnel_factor: float "Blending factor for Fresnel"
+#+ * MaterialRaytraceMirror.gloss_anisotropic -> gloss_anisotropic: float "The shape of the reflection, from 0.0 (circular) to 1.0 (fully stretched along the tangent"
+#+ * MaterialRaytraceMirror.gloss_factor -> gloss_factor: float "The shininess of the reflection. Values < 1.0 give diffuse, blurry reflections"
+#+ * MaterialRaytraceMirror.gloss_samples -> gloss_samples: int "Number of cone samples averaged for blurry reflections"
+#+ * MaterialRaytraceMirror.gloss_threshold -> gloss_threshold: float "Threshold for adaptive sampling. If a sample contributes less than this amount (as a percentage), sampling is stopped"
+#+ * MaterialRaytraceMirror.reflect_factor -> reflect_factor: float "Sets the amount mirror reflection for raytrace"
+#+ * MaterialRaytraceMirror.use -> use: boolean "Enable raytraced reflections"
+#+ * MaterialRaytraceTransparency.depth -> depth: int "Maximum allowed number of light inter-refractions"
+#MaterialRaytraceTransparency.depth_max -> depth_max: float "Maximum depth for light to travel through the transparent material before becoming fully filtered (0.0 is disabled)"
+#+ * MaterialRaytraceTransparency.falloff -> falloff: float "Falloff power for transmissivity filter effect (1.0 is linear)"
+#+ * MaterialRaytraceTransparency.filter -> filter: float "Amount to blend in the materials diffuse color in raytraced transparency (simulating absorption)"
+#+ * MaterialRaytraceTransparency.fresnel -> fresnel: float "Power of Fresnel for transparency (Ray or ZTransp)"
+#+ * MaterialRaytraceTransparency.fresnel_factor -> fresnel_factor: float "Blending factor for Fresnel"
+#+ * MaterialRaytraceTransparency.gloss_factor -> gloss_factor: float "The clarity of the refraction. Values < 1.0 give diffuse, blurry refractions"
+#+ * MaterialRaytraceTransparency.gloss_samples -> gloss_samples: int "Number of cone samples averaged for blurry refractions"
+#+ * MaterialRaytraceTransparency.gloss_threshold -> gloss_threshold: float "Threshold for adaptive sampling. If a sample contributes less than this amount (as a percentage), sampling is stopped"
+#+ * MaterialRaytraceTransparency.ior -> ior: float "Sets angular index of refraction for raytraced refraction"
+#+ * MaterialSlot.link -> link: enum "Link material to object or the objects data"
+#+ * MaterialSlot.material -> material: pointer "Material datablock used by this material slot"
+#+ * MaterialSlot.name -> name: string, "(read-only) Material slot name"
+#+ * MaterialStrand.blend_distance -> blend_distance: float "Worldspace distance over which to blend in the surface normal"
+#+ * MaterialStrand.root_size -> root_size: float "Start size of strands in pixels or Blender units"
+#+ * MaterialStrand.shape -> shape: float "Positive values make strands rounder, negative makes strands spiky"
+#MaterialStrand.size_min -> size_min: float "Minimum size of strands in pixels"
+#+ * MaterialStrand.tip_size -> tip_size: float "End size of strands in pixels or Blender units"
+#MaterialStrand.use_blender_units -> use_blender_units: boolean "Use Blender units for widths instead of pixels"
+#MaterialStrand.use_surface_diffuse -> use_surface_diffuse: boolean "Make diffuse shading more similar to shading the surface"
+#MaterialStrand.use_tangent_shading -> use_tangent_shading: boolean "Uses direction of strands as normal for tangent-shading"
+#+ * MaterialStrand.uv_layer -> uv_layer: string "Name of UV layer to override"
+#+ * MaterialStrand.width_fade -> width_fade: float "Transparency along the width of the strand"
+#+ * MaterialSubsurfaceScattering.back -> back: float "Back scattering weight"
+#+ * MaterialSubsurfaceScattering.color -> color: float[3] "Scattering color"
+#+ * MaterialSubsurfaceScattering.color_factor -> color_factor: float "Blend factor for SSS colors"
+#MaterialSubsurfaceScattering.error_threshold -> error_threshold: float "Error tolerance (low values are slower and higher quality)"
+#+ * MaterialSubsurfaceScattering.front -> front: float "Front scattering weight"
+#+ * MaterialSubsurfaceScattering.ior -> ior: float "Index of refraction (higher values are denser)"
+#+ * MaterialSubsurfaceScattering.radius -> radius: float[3] "Mean red/green/blue scattering path length"
+#+ * MaterialSubsurfaceScattering.scale -> scale: float "Object scale factor"
+#+ * MaterialSubsurfaceScattering.texture_factor -> texture_factor: float "Texture scatting blend factor"
+#+ * MaterialSubsurfaceScattering.use -> use: boolean "Enable diffuse subsurface scatting effects in a material"
+#+ * MaterialVolume.asymmetry -> asymmetry: float "Back scattering (-1.0) to Forward scattering (1.0) and the range in between"
+#+ * MaterialVolume.cache_resolution -> cache_resolution: int "Resolution of the voxel grid, low resolutions are faster, high resolutions use more memory"
+#+ * MaterialVolume.density -> density: float "The base density of the volume"
+#+ * MaterialVolume.density_scale -> density_scale: float "Multiplier for the materials density"
+#MaterialVolume.depth_threshold -> depth_threshold: float "Stop ray marching early if transmission drops below this luminance - higher values give speedups in dense volumes at the expense of accuracy"
+#+ * MaterialVolume.emission -> emission: float "Amount of light that gets emitted by the volume"
+#+ * MaterialVolume.emission_color -> emission_color: float[3] "NO DESCRIPTION"
+#MaterialVolume.light_method -> light_method: enum "Method of shading, attenuating, and scattering light through the volume"
+#+ * MaterialVolume.ms_diffusion -> ms_diffusion: float "Diffusion factor, the strength of the blurring effect"
+#+ * MaterialVolume.ms_intensity -> ms_intensity: float "Multiplier for multiple scattered light energy"
+#+ * MaterialVolume.ms_spread -> ms_spread: float "Proportional distance over which the light is diffused"
+#+ * MaterialVolume.reflection -> reflection: float "Multiplier to make out-scattered light brighter or darker (non-physically correct)"
+#+ * MaterialVolume.reflection_color -> reflection_color: float[3] "Colour of light scattered out of the volume (does not affect transmission)"
+#+ * MaterialVolume.scattering -> scattering: float "Amount of light that gets scattered out by the volume - the more out-scattering, the shallower the light will penetrate"
+#MaterialVolume.step_method -> step_method: enum "Method of calculating the steps through the volume"
+#+ * MaterialVolume.step_size -> step_size: float "Distance between subsequent volume depth samples"
+#+ * MaterialVolume.transmission_color -> transmission_color: float[3] "Result color of the volume, after other light has been scattered/absorbed"
+#MaterialVolume.use_external_shadows -> use_external_shadows: boolean "Receive shadows from sources outside the volume (temporary)"
+#MaterialVolume.use_light_cache -> use_light_cache: boolean "Pre-calculate the shading information into a voxel grid, speeds up shading at slightly less accuracy"
+#+ * Menu.bl_idname -> bl_idname: string "If this is set, the menu gets a custom ID, otherwise it takes the name of the class used to define the panel. For example, if the class name is OBJECT_MT_hello, and bl_idname is not set by the script, then bl_idname = OBJECT_MT_hello"
+#+ * Menu.bl_label -> bl_label: string "The menu label"
+#+ * Menu.layout -> layout: pointer, "(read-only) Defines the structure of the menu in the UI."
+#+ * MeshColor.color1 -> color1: float[3] "NO DESCRIPTION"
+#+ * MeshColor.color2 -> color2: float[3] "NO DESCRIPTION"
+#+ * MeshColor.color3 -> color3: float[3] "NO DESCRIPTION"
+#+ * MeshColor.color4 -> color4: float[3] "NO DESCRIPTION"
+#+ * MeshColorLayer.active -> active: boolean "Sets the layer as active for display and editing"
+#+ * MeshColorLayer.active_render -> active_render: boolean "Sets the layer as active for rendering"
+#+ * MeshColorLayer.data -> data: collection, "(read-only)"
+#+ * MeshColorLayer.name -> name: string "NO DESCRIPTION"
+#+ * MeshEdge.bevel_weight -> bevel_weight: float "Weight used by the Bevel modifier"
+#+ * MeshEdge.crease -> crease: float "Weight used by the Subsurf modifier for creasing"
+#+ * MeshEdge.hide -> hide: boolean "NO DESCRIPTION"
+#+ * MeshEdge.index -> index: int, "(read-only) Index number of the vertex"
+#MeshEdge.is_fgon -> is_fgon: boolean "Fgon edge"
+#MeshEdge.is_loose -> is_loose: boolean "Loose edge"
+#+ * MeshEdge.select -> select: boolean "NO DESCRIPTION"
+#MeshEdge.use_edge_sharp -> use_edge_sharp: boolean "Sharp edge for the EdgeSplit modifier"
+#MeshEdge.use_seam -> use_seam: boolean "Seam edge for UV unwrapping"
+#MeshEdge.vertices -> vertices: int[2] "Vertex indices"
+#+ * MeshFace.area -> area: float, "(read-only) read only area of the face"
+#+ * MeshFace.hide -> hide: boolean "NO DESCRIPTION"
+#+ * MeshFace.index -> index: int, "(read-only) Index number of the vertex"
+#+ * MeshFace.material_index -> material_index: int "NO DESCRIPTION"
+#+ * MeshFace.normal -> normal: float[3], "(read-only) local space unit length normal vector for this face"
+#+ * MeshFace.select -> select: boolean "NO DESCRIPTION"
+#MeshFace.use_smooth -> use_smooth: boolean "NO DESCRIPTION"
+#MeshFace.vertices -> vertices: int[4] "Vertex indices"
+#MeshFace.vertices_raw -> vertices_raw: int[4] "Fixed size vertex indices array"
+#+ * MeshFaces.active -> active: int "The active face for this mesh"
+#+ * MeshFaces.active_tface -> active_tface: pointer, "(read-only) Active Texture Face"
+#+ * MeshFloatProperty.value -> value: float "NO DESCRIPTION"
+#+ * MeshFloatPropertyLayer.data -> data: collection, "(read-only)"
+#+ * MeshFloatPropertyLayer.name -> name: string "NO DESCRIPTION"
+#+ * MeshIntProperty.value -> value: int "NO DESCRIPTION"
+#+ * MeshIntPropertyLayer.data -> data: collection, "(read-only)"
+#+ * MeshIntPropertyLayer.name -> name: string "NO DESCRIPTION"
+#+ * MeshSticky.co -> co: float[2] "Sticky texture coordinate location"
+#+ * MeshStringProperty.value -> value: string "NO DESCRIPTION"
+#+ * MeshStringPropertyLayer.data -> data: collection, "(read-only)"
+#+ * MeshStringPropertyLayer.name -> name: string "NO DESCRIPTION"
+#MeshTextureFace.blend_type -> blend_type: enum "Transparency blending mode"
+#MeshTextureFace.hide -> hide: boolean "Make face invisible"
+#+ * MeshTextureFace.image -> image: pointer "NO DESCRIPTION"
+#MeshTextureFace.pin_uv -> pin_uv: boolean[4] "NO DESCRIPTION"
+#+ * MeshTextureFace.select_uv -> select_uv: boolean[4] "NO DESCRIPTION"
+#MeshTextureFace.use_alpha_sort -> use_alpha_sort: boolean "Enable sorting of faces for correct alpha drawing (slow, use Clip Alpha instead when possible)"
+#MeshTextureFace.use_billboard -> use_billboard: boolean "Billboard with Z-axis constraint"
+#MeshTextureFace.use_bitmap_text -> use_bitmap_text: boolean "Enable bitmap text on face"
+#MeshTextureFace.use_blend_shared -> use_blend_shared: boolean "Blend vertex colors across face when vertices are shared"
+#MeshTextureFace.use_collision -> use_collision: boolean "Use face for collision and ray-sensor detection"
+#MeshTextureFace.use_halo -> use_halo: boolean "Screen aligned billboard"
+#MeshTextureFace.use_image -> use_image: boolean "Render face with texture"
+#MeshTextureFace.use_light -> use_light: boolean "Use light for face"
+#MeshTextureFace.use_object_color -> use_object_color: boolean "Use ObColor instead of vertex colors"
+#MeshTextureFace.use_shadow_cast -> use_shadow_cast: boolean "Face is used for shadow"
+#MeshTextureFace.use_twoside -> use_twoside: boolean "Render face two-sided"
+#+ * MeshTextureFace.uv -> uv: float[8] "NO DESCRIPTION"
+#+ * MeshTextureFace.uv1 -> uv1: float[2] "NO DESCRIPTION"
+#+ * MeshTextureFace.uv2 -> uv2: float[2] "NO DESCRIPTION"
+#+ * MeshTextureFace.uv3 -> uv3: float[2] "NO DESCRIPTION"
+#+ * MeshTextureFace.uv4 -> uv4: float[2] "NO DESCRIPTION"
+#+ * MeshTextureFace.uv_raw -> uv_raw: float[8] "Fixed size UV coordinates array"
+#+ * MeshTextureFaceLayer.active -> active: boolean "Sets the layer as active for display and editing"
+#+ * MeshTextureFaceLayer.active_clone -> active_clone: boolean "Sets the layer as active for cloning"
+#+ * MeshTextureFaceLayer.active_render -> active_render: boolean "Sets the layer as active for rendering"
+#+ * MeshTextureFaceLayer.data -> data: collection, "(read-only)"
+#+ * MeshTextureFaceLayer.name -> name: string "NO DESCRIPTION"
+#+ * MeshVertex.bevel_weight -> bevel_weight: float "Weight used by the Bevel modifier Only Vertices option"
+#+ * MeshVertex.co -> co: float[3] "NO DESCRIPTION"
+#+ * MeshVertex.groups -> groups: collection, "(read-only) Weights for the vertex groups this vertex is member of"
+#+ * MeshVertex.hide -> hide: boolean "NO DESCRIPTION"
+#+ * MeshVertex.index -> index: int, "(read-only) Index number of the vertex"
+#+ * MeshVertex.normal -> normal: float[3] "Vertex Normal"
+#+ * MeshVertex.select -> select: boolean "NO DESCRIPTION"
+#MetaBallElements.active -> active: pointer, "(read-only) Last selected element"
+#MetaElement.co -> co: float[3] "NO DESCRIPTION"
+#+ * MetaElement.hide -> hide: boolean "Hide element"
+#+ * MetaElement.radius -> radius: float "NO DESCRIPTION"
+#+ * MetaElement.rotation -> rotation: float[4] "NO DESCRIPTION"
+#+ * MetaElement.size_x -> size_x: float "Size of element, use of components depends on element type"
+#+ * MetaElement.size_y -> size_y: float "Size of element, use of components depends on element type"
+#+ * MetaElement.size_z -> size_z: float "Size of element, use of components depends on element type"
+#+ * MetaElement.stiffness -> stiffness: float "Stiffness defines how much of the element to fill"
+#+ * MetaElement.type -> type: enum "Metaball types"
+#MetaElement.use_negative -> use_negative: boolean "Set metaball as negative one"
+#+ * Modifier.name -> name: string "Modifier name"
+#Modifier.show_expanded -> show_expanded: boolean "Set modifier expanded in the user interface"
+#Modifier.show_in_editmode -> show_in_editmode: boolean "Use modifier while in the edit mode"
+#Modifier.show_on_cage -> show_on_cage: boolean "Enable direct editing of modifier control cage"
+#Modifier.show_render -> show_render: boolean "Use modifier during rendering"
+#Modifier.show_viewport -> show_viewport: boolean "Realtime display of a modifier"
+#+ * Modifier.type -> type: enum, "(read-only)"
+#Modifier|ArmatureModifier.invert_vertex_group -> invert_vertex_group: boolean "Invert vertex group influence"
+#+ * Modifier|ArmatureModifier.object -> object: pointer "Armature object to deform with"
+#+ * Modifier|ArmatureModifier.use_bone_envelopes -> use_bone_envelopes: boolean "NO DESCRIPTION"
+#Modifier|ArmatureModifier.use_deform_preserve_volume -> use_deform_preserve_volume: boolean "Deform rotation interpolation with quaternions"
+#Modifier|ArmatureModifier.use_multi_modifier -> use_multi_modifier: boolean "Use same input as previous modifier, and mix results using overall vgroup"
+#+ * Modifier|ArmatureModifier.use_vertex_groups -> use_vertex_groups: boolean "NO DESCRIPTION"
+#+ * Modifier|ArmatureModifier.vertex_group -> vertex_group: string "Vertex group name"
+#Modifier|ArrayModifier.constant_offset_displace -> constant_offset_displace: float[3] "NO DESCRIPTION"
+#+ * Modifier|ArrayModifier.count -> count: int "Number of duplicates to make"
+#+ * Modifier|ArrayModifier.curve -> curve: pointer "Curve object to fit array length to"
+#+ * Modifier|ArrayModifier.end_cap -> end_cap: pointer "Mesh object to use as an end cap"
+#Modifier|ArrayModifier.fit_length -> fit_length: float "Length to fit array within"
+#+ * Modifier|ArrayModifier.fit_type -> fit_type: enum "Array length calculation method"
+#Modifier|ArrayModifier.merge_threshold -> merge_threshold: float "Limit below which to merge vertices"
+#+ * Modifier|ArrayModifier.offset_object -> offset_object: pointer "NO DESCRIPTION"
+#Modifier|ArrayModifier.relative_offset_displace -> relative_offset_displace: float[3] "NO DESCRIPTION"
+#+ * Modifier|ArrayModifier.start_cap -> start_cap: pointer "Mesh object to use as a start cap"
+#Modifier|ArrayModifier.use_constant_offset -> use_constant_offset: boolean "Add a constant offset"
+#Modifier|ArrayModifier.use_merge_vertices -> use_merge_vertices: boolean "Merge vertices in adjacent duplicates"
+#Modifier|ArrayModifier.use_merge_vertices_cap -> use_merge_vertices_cap: boolean "Merge vertices in first and last duplicates"
+#Modifier|ArrayModifier.use_object_offset -> use_object_offset: boolean "Add another objects transformation to the total offset"
+#Modifier|ArrayModifier.use_relative_offset -> use_relative_offset: boolean "Add an offset relative to the objects bounding box"
+#Modifier|BevelModifier.angle_limit -> angle_limit: float "Angle above which to bevel edges"
+#+ * Modifier|BevelModifier.edge_weight_method -> edge_weight_method: enum "What edge weight to use for weighting a vertex"
+#+ * Modifier|BevelModifier.limit_method -> limit_method: enum "NO DESCRIPTION"
+#Modifier|BevelModifier.use_only_vertices -> use_only_vertices: boolean "Bevel verts/corners, not edges"
+#+ * Modifier|BevelModifier.width -> width: float "Bevel value/amount"
+#+ * Modifier|BooleanModifier.object -> object: pointer "Mesh object to use for Boolean operation"
+#+ * Modifier|BooleanModifier.operation -> operation: enum "NO DESCRIPTION"
+#Modifier|BuildModifier.frame_duration -> frame_duration: float "Specify the total time the build effect requires"
+#+ * Modifier|BuildModifier.frame_start -> frame_start: float "Specify the start frame of the effect"
+#+ * Modifier|BuildModifier.seed -> seed: int "Specify the seed for random if used"
+#Modifier|BuildModifier.use_random_order -> use_random_order: boolean "Randomize the faces or edges during build"
+#+ * Modifier|CastModifier.cast_type -> cast_type: enum "NO DESCRIPTION"
+#+ * Modifier|CastModifier.factor -> factor: float "NO DESCRIPTION"
+#+ * Modifier|CastModifier.object -> object: pointer "Control object: if available, its location determines the center of the effect"
+#+ * Modifier|CastModifier.radius -> radius: float "Only deform vertices within this distance from the center of the effect (leave as 0 for infinite.)"
+#+ * Modifier|CastModifier.size -> size: float "Size of projection shape (leave as 0 for auto.)"
+#Modifier|CastModifier.use_radius_as_size -> use_radius_as_size: boolean "Use radius as size of projection shape (0 = auto)"
+#+ * Modifier|CastModifier.use_transform -> use_transform: boolean "Use object transform to control projection shape"
+#Modifier|CastModifier.use_x -> use_x: boolean "NO DESCRIPTION"
+#Modifier|CastModifier.use_y -> use_y: boolean "NO DESCRIPTION"
+#Modifier|CastModifier.use_z -> use_z: boolean "NO DESCRIPTION"
+#+ * Modifier|CastModifier.vertex_group -> vertex_group: string "Vertex group name"
+#+ * Modifier|ClothModifier.collision_settings -> collision_settings: pointer, "(read-only)"
+#+ * Modifier|ClothModifier.point_cache -> point_cache: pointer, "(read-only)"
+#+ * Modifier|ClothModifier.settings -> settings: pointer, "(read-only)"
+#+ * Modifier|CollisionModifier.settings -> settings: pointer, "(read-only)"
+#+ * Modifier|CurveModifier.deform_axis -> deform_axis: enum "The axis that the curve deforms along"
+#+ * Modifier|CurveModifier.object -> object: pointer "Curve object to deform with"
+#+ * Modifier|CurveModifier.vertex_group -> vertex_group: string "Vertex group name"
+#+ * Modifier|DecimateModifier.face_count -> face_count: int, "(read-only) The current number of faces in the decimated mesh"
+#+ * Modifier|DecimateModifier.ratio -> ratio: float "Defines the ratio of triangles to reduce to"
+#+ * Modifier|DisplaceModifier.direction -> direction: enum "NO DESCRIPTION"
+#Modifier|DisplaceModifier.mid_level -> mid_level: float "Material value that gives no displacement"
+#+ * Modifier|DisplaceModifier.strength -> strength: float "NO DESCRIPTION"
+#+ * Modifier|DisplaceModifier.texture -> texture: pointer "NO DESCRIPTION"
+#+ * Modifier|DisplaceModifier.texture_coordinate_object -> texture_coordinate_object: pointer "NO DESCRIPTION"
+#Modifier|DisplaceModifier.texture_coords -> texture_coords: enum "NO DESCRIPTION"
+#+ * Modifier|DisplaceModifier.uv_layer -> uv_layer: string "UV layer name"
+#+ * Modifier|DisplaceModifier.vertex_group -> vertex_group: string "Vertex group name"
+#+ * Modifier|EdgeSplitModifier.split_angle -> split_angle: float "Angle above which to split edges"
+#+ * Modifier|EdgeSplitModifier.use_edge_angle -> use_edge_angle: boolean "Split edges with high angle between faces"
+#Modifier|EdgeSplitModifier.use_edge_sharp -> use_edge_sharp: boolean "Split edges that are marked as sharp"
+#+ * Modifier|ExplodeModifier.protect -> protect: float "Clean vertex group edges"
+#Modifier|ExplodeModifier.show_alive -> show_alive: boolean "Show mesh when particles are alive"
+#Modifier|ExplodeModifier.show_dead -> show_dead: boolean "Show mesh when particles are dead"
+#Modifier|ExplodeModifier.show_unborn -> show_unborn: boolean "Show mesh when particles are unborn"
+#Modifier|ExplodeModifier.use_edge_split -> use_edge_split: boolean "Split face edges for nicer shrapnel"
+#Modifier|ExplodeModifier.use_size -> use_size: boolean "Use particle size for the shrapnel"
+#+ * Modifier|ExplodeModifier.vertex_group -> vertex_group: string "NO DESCRIPTION"
+#+ * Modifier|FluidSimulationModifier.settings -> settings: pointer, "(read-only) Settings for how this object is used in the fluid simulation"
+#+ * Modifier|HookModifier.falloff -> falloff: float "If not zero, the distance from the hook where influence ends"
+#+ * Modifier|HookModifier.force -> force: float "Relative force of the hook"
+#+ * Modifier|HookModifier.object -> object: pointer "Parent Object for hook, also recalculates and clears offset"
+#+ * Modifier|HookModifier.subtarget -> subtarget: string "Name of Parent Bone for hook (if applicable), also recalculates and clears offset"
+#+ * Modifier|HookModifier.vertex_group -> vertex_group: string "Vertex group name"
+#+ * Modifier|LatticeModifier.object -> object: pointer "Lattice object to deform with"
+#+ * Modifier|LatticeModifier.vertex_group -> vertex_group: string "Vertex group name"
+#+ * Modifier|MaskModifier.armature -> armature: pointer "Armature to use as source of bones to mask"
+#Modifier|MaskModifier.invert_vertex_group -> invert_vertex_group: boolean "Use vertices that are not part of region defined"
+#+ * Modifier|MaskModifier.mode -> mode: enum "NO DESCRIPTION"
+#+ * Modifier|MaskModifier.vertex_group -> vertex_group: string "Vertex group name"
+#Modifier|MeshDeformModifier.invert_vertex_group -> invert_vertex_group: boolean "Invert vertex group influence"
+#+ * Modifier|MeshDeformModifier.is_bound -> is_bound: boolean, "(read-only) Whether geometry has been bound to control cage"
+#+ * Modifier|MeshDeformModifier.object -> object: pointer "Mesh object to deform with"
+#+ * Modifier|MeshDeformModifier.precision -> precision: int "The grid size for binding"
+#Modifier|MeshDeformModifier.use_dynamic_bind -> use_dynamic_bind: boolean "Recompute binding dynamically on top of other deformers (slower and more memory consuming.)"
+#+ * Modifier|MeshDeformModifier.vertex_group -> vertex_group: string "Vertex group name"
+#Modifier|MirrorModifier.merge_threshold -> merge_threshold: float "Distance from axis within which mirrored vertices are merged"
+#+ * Modifier|MirrorModifier.mirror_object -> mirror_object: pointer "Object to use as mirror"
+#Modifier|MirrorModifier.use_clip -> use_clip: boolean "Prevents vertices from going through the mirror during transform"
+#Modifier|MirrorModifier.use_mirror_u -> use_mirror_u: boolean "Mirror the U texture coordinate around the 0.5 point"
+#Modifier|MirrorModifier.use_mirror_v -> use_mirror_v: boolean "Mirror the V texture coordinate around the 0.5 point"
+#Modifier|MirrorModifier.use_mirror_vertex_groups -> use_mirror_vertex_groups: boolean "Mirror vertex groups (e.g. .R->.L)"
+#Modifier|MirrorModifier.use_x -> use_x: boolean "Enable X axis mirror"
+#Modifier|MirrorModifier.use_y -> use_y: boolean "Enable Y axis mirror"
+#Modifier|MirrorModifier.use_z -> use_z: boolean "Enable Z axis mirror"
+#+ * Modifier|MultiresModifier.filepath -> filepath: string "Path to external displacements file"
+#Modifier|MultiresModifier.is_external -> is_external: boolean, "(read-only) Store multires displacements outside the .blend file, to save memory"
+#+ * Modifier|MultiresModifier.levels -> levels: int "Number of subdivisions to use in the viewport"
+#+ * Modifier|MultiresModifier.render_levels -> render_levels: int "NO DESCRIPTION"
+#+ * Modifier|MultiresModifier.sculpt_levels -> sculpt_levels: int "Number of subdivisions to use in sculpt mode"
+#Modifier|MultiresModifier.show_only_control_edges -> show_only_control_edges: boolean "Skip drawing/rendering of interior subdivided edges"
+#+ * Modifier|MultiresModifier.subdivision_type -> subdivision_type: enum "Selects type of subdivision algorithm"
+#+ * Modifier|MultiresModifier.total_levels -> total_levels: int, "(read-only) Number of subdivisions for which displacements are stored"
+#+ * Modifier|ParticleInstanceModifier.axis -> axis: enum "Pole axis for rotation"
+#+ * Modifier|ParticleInstanceModifier.object -> object: pointer "Object that has the particle system"
+#Modifier|ParticleInstanceModifier.particle_system_index -> particle_system_index: int "NO DESCRIPTION"
+#+ * Modifier|ParticleInstanceModifier.position -> position: float "Position along path"
+#+ * Modifier|ParticleInstanceModifier.random_position -> random_position: float "Randomize position along path"
+#Modifier|ParticleInstanceModifier.show_alive -> show_alive: boolean "Show instances when particles are alive"
+#Modifier|ParticleInstanceModifier.show_dead -> show_dead: boolean "Show instances when particles are dead"
+#Modifier|ParticleInstanceModifier.show_unborn -> show_unborn: boolean "Show instances when particles are unborn"
+#Modifier|ParticleInstanceModifier.use_children -> use_children: boolean "Create instances from child particles"
+#Modifier|ParticleInstanceModifier.use_normal -> use_normal: boolean "Create instances from normal particles"
+#+ * Modifier|ParticleInstanceModifier.use_path -> use_path: boolean "Create instances along particle paths"
+#Modifier|ParticleInstanceModifier.use_preserve_shape -> use_preserve_shape: boolean "Dont stretch the object"
+#Modifier|ParticleInstanceModifier.use_size -> use_size: boolean "Use particle size to scale the instances"
+#+ * Modifier|ParticleSystemModifier.particle_system -> particle_system: pointer, "(read-only) Particle System that this modifier controls"
+#+ * Modifier|ScrewModifier.angle -> angle: float "Angle of revolution"
+#+ * Modifier|ScrewModifier.axis -> axis: enum "Screw axis"
+#+ * Modifier|ScrewModifier.iterations -> iterations: int "Number of times to apply the screw operation"
+#+ * Modifier|ScrewModifier.object -> object: pointer "Object to define the screw axis"
+#+ * Modifier|ScrewModifier.render_steps -> render_steps: int "Number of steps in the revolution"
+#+ * Modifier|ScrewModifier.screw_offset -> screw_offset: float "Offset the revolution along its axis"
+#+ * Modifier|ScrewModifier.steps -> steps: int "Number of steps in the revolution"
+#+ * Modifier|ScrewModifier.use_normal_calculate -> use_normal_calculate: boolean "Calculate the order of edges (needed for meshes, but not curves)"
+#+ * Modifier|ScrewModifier.use_normal_flip -> use_normal_flip: boolean "Flip normals of lathed faces"
+#+ * Modifier|ScrewModifier.use_object_screw_offset -> use_object_screw_offset: boolean "Use the distance between the objects to make a screw"
+#+ * Modifier|ShrinkwrapModifier.auxiliary_target -> auxiliary_target: pointer "Additional mesh target to shrink to"
+#+ * Modifier|ShrinkwrapModifier.offset -> offset: float "Distance to keep from the target"
+#+ * Modifier|ShrinkwrapModifier.subsurf_levels -> subsurf_levels: int "Number of subdivisions that must be performed before extracting vertices positions and normals"
+#+ * Modifier|ShrinkwrapModifier.target -> target: pointer "Mesh target to shrink to"
+#Modifier|ShrinkwrapModifier.use_cull_back_faces -> use_cull_back_faces: boolean "Stop vertices from projecting to a back face on the target"
+#Modifier|ShrinkwrapModifier.use_cull_front_faces -> use_cull_front_faces: boolean "Stop vertices from projecting to a front face on the target"
+#Modifier|ShrinkwrapModifier.use_keep_above_surface -> use_keep_above_surface: boolean "NO DESCRIPTION"
+#Modifier|ShrinkwrapModifier.use_negative_direction -> use_negative_direction: boolean "Allow vertices to move in the negative direction of axis"
+#Modifier|ShrinkwrapModifier.use_positive_direction -> use_positive_direction: boolean "Allow vertices to move in the positive direction of axis"
+#Modifier|ShrinkwrapModifier.use_project_x -> use_project_x: boolean "NO DESCRIPTION"
+#Modifier|ShrinkwrapModifier.use_project_y -> use_project_y: boolean "NO DESCRIPTION"
+#Modifier|ShrinkwrapModifier.use_project_z -> use_project_z: boolean "NO DESCRIPTION"
+#+ * Modifier|ShrinkwrapModifier.vertex_group -> vertex_group: string "Vertex group name"
+#Modifier|ShrinkwrapModifier.wrap_method -> wrap_method: enum "NO DESCRIPTION"
+#Modifier|SimpleDeformModifier.deform_method -> deform_method: enum "NO DESCRIPTION"
+#+ * Modifier|SimpleDeformModifier.factor -> factor: float "NO DESCRIPTION"
+#+ * Modifier|SimpleDeformModifier.limits -> limits: float[2] "Lower/Upper limits for deform"
+#Modifier|SimpleDeformModifier.lock_x -> lock_x: boolean "NO DESCRIPTION"
+#Modifier|SimpleDeformModifier.lock_y -> lock_y: boolean "NO DESCRIPTION"
+#+ * Modifier|SimpleDeformModifier.origin -> origin: pointer "Origin of modifier space coordinates"
+#Modifier|SimpleDeformModifier.use_relative -> use_relative: boolean "Sets the origin of deform space to be relative to the object"
+#+ * Modifier|SimpleDeformModifier.vertex_group -> vertex_group: string "Vertex group name"
+#+ * Modifier|SmokeModifier.coll_settings -> coll_settings: pointer, "(read-only)"
+#+ * Modifier|SmokeModifier.domain_settings -> domain_settings: pointer, "(read-only)"
+#+ * Modifier|SmokeModifier.flow_settings -> flow_settings: pointer, "(read-only)"
+#Modifier|SmokeModifier.smoke_type -> smoke_type: enum "NO DESCRIPTION"
+#+ * Modifier|SmoothModifier.factor -> factor: float "NO DESCRIPTION"
+#Modifier|SmoothModifier.iterations -> iterations: int "NO DESCRIPTION"
+#Modifier|SmoothModifier.use_x -> use_x: boolean "NO DESCRIPTION"
+#Modifier|SmoothModifier.use_y -> use_y: boolean "NO DESCRIPTION"
+#Modifier|SmoothModifier.use_z -> use_z: boolean "NO DESCRIPTION"
+#+ * Modifier|SmoothModifier.vertex_group -> vertex_group: string "Vertex group name"
+#+ * Modifier|SoftBodyModifier.point_cache -> point_cache: pointer, "(read-only)"
+#+ * Modifier|SoftBodyModifier.settings -> settings: pointer, "(read-only)"
+#+ * Modifier|SolidifyModifier.edge_crease_inner -> edge_crease_inner: float "Assign a crease to inner edges"
+#+ * Modifier|SolidifyModifier.edge_crease_outer -> edge_crease_outer: float "Assign a crease to outer edges"
+#+ * Modifier|SolidifyModifier.edge_crease_rim -> edge_crease_rim: float "Assign a crease to the edges making up the rim"
+#Modifier|SolidifyModifier.invert_vertex_group -> invert_vertex_group: boolean "Invert the vertex group influence"
+#+ * Modifier|SolidifyModifier.offset -> offset: float "Offset the thickness from the center"
+#+ * Modifier|SolidifyModifier.thickness -> thickness: float "Thickness of the shell"
+#+ * Modifier|SolidifyModifier.use_even_offset -> use_even_offset: boolean "Maintain thickness by adjusting for sharp corners (slow, disable when not needed)"
+#+ * Modifier|SolidifyModifier.use_quality_normals -> use_quality_normals: boolean "Calculate normals which result in more even thickness (slow, disable when not needed)"
+#+ * Modifier|SolidifyModifier.use_rim -> use_rim: boolean "Create edge loops between the inner and outer surfaces on face edges (slow, disable when not needed)"
+#+ * Modifier|SolidifyModifier.use_rim_material -> use_rim_material: boolean "Use in the next material for rim faces"
+#+ * Modifier|SolidifyModifier.vertex_group -> vertex_group: string "Vertex group name"
+#+ * Modifier|SubsurfModifier.levels -> levels: int "Number of subdivisions to perform"
+#+ * Modifier|SubsurfModifier.render_levels -> render_levels: int "Number of subdivisions to perform when rendering"
+#Modifier|SubsurfModifier.show_only_control_edges -> show_only_control_edges: boolean "Skip drawing/rendering of interior subdivided edges"
+#+ * Modifier|SubsurfModifier.subdivision_type -> subdivision_type: enum "Selects type of subdivision algorithm"
+#Modifier|SubsurfModifier.use_subsurf_uv -> use_subsurf_uv: boolean "Use subsurf to subdivide UVs"
+#+ * Modifier|UVProjectModifier.aspect_x -> aspect_x: float "NO DESCRIPTION"
+#+ * Modifier|UVProjectModifier.aspect_y -> aspect_y: float "NO DESCRIPTION"
+#+ * Modifier|UVProjectModifier.image -> image: pointer "NO DESCRIPTION"
+#Modifier|UVProjectModifier.projector_count -> projector_count: int "Number of projectors to use"
+#+ * Modifier|UVProjectModifier.projectors -> projectors: collection, "(read-only)"
+#+ * Modifier|UVProjectModifier.scale_x -> scale_x: float "NO DESCRIPTION"
+#+ * Modifier|UVProjectModifier.scale_y -> scale_y: float "NO DESCRIPTION"
+#Modifier|UVProjectModifier.use_image_override -> use_image_override: boolean "Override faces current images with the given image"
+#+ * Modifier|UVProjectModifier.uv_layer -> uv_layer: string "UV layer name"
+#+ * Modifier|WaveModifier.damping_time -> damping_time: float "NO DESCRIPTION"
+#+ * Modifier|WaveModifier.falloff_radius -> falloff_radius: float "NO DESCRIPTION"
+#+ * Modifier|WaveModifier.height -> height: float "NO DESCRIPTION"
+#+ * Modifier|WaveModifier.lifetime -> lifetime: float "NO DESCRIPTION"
+#+ * Modifier|WaveModifier.narrowness -> narrowness: float "NO DESCRIPTION"
+#+ * Modifier|WaveModifier.speed -> speed: float "NO DESCRIPTION"
+#+ * Modifier|WaveModifier.start_position_object -> start_position_object: pointer "NO DESCRIPTION"
+#+ * Modifier|WaveModifier.start_position_x -> start_position_x: float "NO DESCRIPTION"
+#+ * Modifier|WaveModifier.start_position_y -> start_position_y: float "NO DESCRIPTION"
+#+ * Modifier|WaveModifier.texture -> texture: pointer "Texture for modulating the wave"
+#Modifier|WaveModifier.texture_coords -> texture_coords: enum "Texture coordinates used for modulating input"
+#Modifier|WaveModifier.texture_coords_object -> texture_coords_object: pointer "NO DESCRIPTION"
+#+ * Modifier|WaveModifier.time_offset -> time_offset: float "Either the starting frame (for positive speed) or ending frame (for negative speed.)"
+#Modifier|WaveModifier.use_cyclic -> use_cyclic: boolean "Cyclic wave effect"
+#Modifier|WaveModifier.use_normal -> use_normal: boolean "Displace along normals"
+#Modifier|WaveModifier.use_normal_x -> use_normal_x: boolean "Enable displacement along the X normal"
+#Modifier|WaveModifier.use_normal_y -> use_normal_y: boolean "Enable displacement along the Y normal"
+#Modifier|WaveModifier.use_normal_z -> use_normal_z: boolean "Enable displacement along the Z normal"
+#Modifier|WaveModifier.use_x -> use_x: boolean "X axis motion"
+#Modifier|WaveModifier.use_y -> use_y: boolean "Y axis motion"
+#+ * Modifier|WaveModifier.uv_layer -> uv_layer: string "UV layer name"
+#+ * Modifier|WaveModifier.vertex_group -> vertex_group: string "Vertex group name for modulating the wave"
+#+ * Modifier|WaveModifier.width -> width: float "NO DESCRIPTION"
+#+ * MotionPath.frame_end -> frame_end: int, "(read-only) End frame of the stored range"
+#+ * MotionPath.frame_start -> frame_start: int, "(read-only) Starting frame of the stored range"
+#MotionPath.is_modified -> is_modified: boolean "Path is being edited"
+#+ * MotionPath.length -> length: int, "(read-only) Number of frames cached"
+#+ * MotionPath.points -> points: collection, "(read-only) Cached positions per frame"
+#+ * MotionPath.use_bone_head -> use_bone_head: boolean, "(read-only) For PoseBone paths, use the bone head location when calculating this path"
+#+ * MotionPathVert.co -> co: float[3] "NO DESCRIPTION"
+#+ * MotionPathVert.select -> select: boolean "Path point is selected for editing"
+#+ * NlaStrip.action -> action: pointer "Action referenced by this strip"
+#NlaStrip.action_frame_end -> action_frame_end: float "NO DESCRIPTION"
+#NlaStrip.action_frame_start -> action_frame_start: float "NO DESCRIPTION"
+#+ * NlaStrip.active -> active: boolean, "(read-only) NLA Strip is active"
+#+ * NlaStrip.blend_in -> blend_in: float "Number of frames at start of strip to fade in influence"
+#+ * NlaStrip.blend_out -> blend_out: float "NO DESCRIPTION"
+#NlaStrip.blend_type -> blend_type: enum "Method used for combining strips result with accumulated result"
+#+ * NlaStrip.extrapolation -> extrapolation: enum "Action to take for gaps past the strip extents"
+#+ * NlaStrip.fcurves -> fcurves: collection, "(read-only) F-Curves for controlling the strips influence and timing"
+#+ * NlaStrip.frame_end -> frame_end: float "NO DESCRIPTION"
+#+ * NlaStrip.frame_start -> frame_start: float "NO DESCRIPTION"
+#+ * NlaStrip.influence -> influence: float "Amount the strip contributes to the current result"
+#+ * NlaStrip.modifiers -> modifiers: collection, "(read-only) Modifiers affecting all the F-Curves in the referenced Action"
+#+ * NlaStrip.mute -> mute: boolean "NLA Strip is not evaluated"
+#+ * NlaStrip.name -> name: string "NO DESCRIPTION"
+#+ * NlaStrip.repeat -> repeat: float "Number of times to repeat the action range"
+#+ * NlaStrip.scale -> scale: float "Scaling factor for action"
+#+ * NlaStrip.select -> select: boolean "NLA Strip is selected"
+#+ * NlaStrip.strip_time -> strip_time: float "Frame of referenced Action to evaluate"
+#+ * NlaStrip.strips -> strips: collection, "(read-only) NLA Strips that this strip acts as a container for (if it is of type Meta)"
+#+ * NlaStrip.type -> type: enum, "(read-only) Type of NLA Strip"
+#NlaStrip.use_animated_influence -> use_animated_influence: boolean "Influence setting is controlled by an F-Curve rather than automatically determined"
+#NlaStrip.use_animated_time -> use_animated_time: boolean "Strip time is controlled by an F-Curve rather than automatically determined"
+#NlaStrip.use_animated_time_cyclic -> use_animated_time_cyclic: boolean "Cycle the animated time within the action start & end"
+#NlaStrip.use_auto_blend -> use_auto_blend: boolean "Number of frames for Blending In/Out is automatically determined from overlapping strips"
+#NlaStrip.use_reverse -> use_reverse: boolean "NLA Strip is played back in reverse order (only when timing is automatically determined)"
+#+ * NlaTrack.active -> active: boolean, "(read-only) NLA Track is active"
+#NlaTrack.is_solo -> is_solo: boolean, "(read-only) NLA Track is evaluated itself (i.e. active Action and all other NLA Tracks in the same AnimData block are disabled)"
+#+ * NlaTrack.lock -> lock: boolean "NLA Track is locked"
+#+ * NlaTrack.mute -> mute: boolean "NLA Track is not evaluated"
+#+ * NlaTrack.name -> name: string "NO DESCRIPTION"
+#+ * NlaTrack.select -> select: boolean "NLA Track is selected"
+#+ * NlaTrack.strips -> strips: collection, "(read-only) NLA Strips on this NLA-track"
+#+ * Node.inputs -> inputs: collection, "(read-only)"
+#+ * Node.location -> location: float[2] "NO DESCRIPTION"
+#+ * Node.name -> name: string "Node name"
+#+ * Node.outputs -> outputs: collection, "(read-only)"
+#+ * Node|CompositorNode.type -> type: enum, "(read-only)"
+#+ * Node|CompositorNode|CompositorNodeAlphaOver.premul -> premul: float "Mix Factor"
+#Node|CompositorNode|CompositorNodeAlphaOver.use_premultiply -> use_premultiply: boolean "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeBilateralblur.iterations -> iterations: int "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeBilateralblur.sigma_color -> sigma_color: float "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeBilateralblur.sigma_space -> sigma_space: float "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeBlur.factor -> factor: float "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeBlur.factor_x -> factor_x: float "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeBlur.factor_y -> factor_y: float "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeBlur.filter_type -> filter_type: enum "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeBlur.size_x -> size_x: int "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeBlur.size_y -> size_y: int "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeBlur.use_bokeh -> use_bokeh: boolean "Uses circular filter (slower)"
+#Node|CompositorNode|CompositorNodeBlur.use_gamma_correction -> use_gamma_correction: boolean "Applies filter on gamma corrected values"
+#Node|CompositorNode|CompositorNodeBlur.use_relative -> use_relative: boolean "Use relative (percent) values to define blur radius"
+#+ * Node|CompositorNode|CompositorNodeChannelMatte.color_space -> color_space: enum "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeChannelMatte.limit_channel -> limit_channel: enum "Limit by this channels value"
+#Node|CompositorNode|CompositorNodeChannelMatte.limit_max -> limit_max: float "Values higher than this setting are 100% opaque"
+#Node|CompositorNode|CompositorNodeChannelMatte.limit_method -> limit_method: enum "Algorithm to use to limit channel"
+#Node|CompositorNode|CompositorNodeChannelMatte.limit_min -> limit_min: float "Values lower than this setting are 100% keyed"
+#Node|CompositorNode|CompositorNodeChannelMatte.matte_channel -> matte_channel: enum "Channel used to determine matte"
+#+ * Node|CompositorNode|CompositorNodeChromaMatte.gain -> gain: float "Alpha gain"
+#+ * Node|CompositorNode|CompositorNodeChromaMatte.lift -> lift: float "Alpha lift"
+#+ * Node|CompositorNode|CompositorNodeChromaMatte.shadow_adjust -> shadow_adjust: float "Adjusts the brightness of any shadows captured"
+#Node|CompositorNode|CompositorNodeChromaMatte.threshold -> threshold: float "Tolerance below which colors will be considered as exact matches"
+#Node|CompositorNode|CompositorNodeChromaMatte.tolerance -> tolerance: float "Tolerance for a color to be considered a keying color"
+#Node|CompositorNode|CompositorNodeColorBalance.correction_method -> correction_method: enum "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeColorBalance.gain -> gain: float[3] "Correction for Highlights"
+#+ * Node|CompositorNode|CompositorNodeColorBalance.gamma -> gamma: float[3] "Correction for Midtones"
+#+ * Node|CompositorNode|CompositorNodeColorBalance.lift -> lift: float[3] "Correction for Shadows"
+#+ * Node|CompositorNode|CompositorNodeColorBalance.offset -> offset: float[3] "Correction for Shadows"
+#+ * Node|CompositorNode|CompositorNodeColorBalance.power -> power: float[3] "Correction for Midtones"
+#+ * Node|CompositorNode|CompositorNodeColorBalance.slope -> slope: float[3] "Correction for Highlights"
+#Node|CompositorNode|CompositorNodeColorMatte.color_hue -> color_hue: float "Hue tolerance for colors to be considered a keying color"
+#Node|CompositorNode|CompositorNodeColorMatte.color_saturation -> color_saturation: float "Saturation Tolerance for the color"
+#Node|CompositorNode|CompositorNodeColorMatte.color_value -> color_value: float "Value Tolerance for the color"
+#+ * Node|CompositorNode|CompositorNodeColorSpill.channel -> channel: enum "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeColorSpill.limit_channel -> limit_channel: enum "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeColorSpill.limit_method -> limit_method: enum "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeColorSpill.ratio -> ratio: float "Scale limit by value"
+#+ * Node|CompositorNode|CompositorNodeColorSpill.unspill_blue -> unspill_blue: float "Blue spillmap scale"
+#+ * Node|CompositorNode|CompositorNodeColorSpill.unspill_green -> unspill_green: float "Green spillmap scale"
+#+ * Node|CompositorNode|CompositorNodeColorSpill.unspill_red -> unspill_red: float "Red spillmap scale"
+#Node|CompositorNode|CompositorNodeColorSpill.use_unspill -> use_unspill: boolean "Compensate all channels (diffenrently) by hand"
+#Node|CompositorNode|CompositorNodeCrop.max_x -> max_x: int "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeCrop.max_y -> max_y: int "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeCrop.min_x -> min_x: int "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeCrop.min_y -> min_y: int "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeCrop.use_crop_size -> use_crop_size: boolean "Whether to crop the size of the input image"
+#+ * Node|CompositorNode|CompositorNodeCurveRGB.mapping -> mapping: pointer, "(read-only)"
+#+ * Node|CompositorNode|CompositorNodeCurveVec.mapping -> mapping: pointer, "(read-only)"
+#+ * Node|CompositorNode|CompositorNodeDBlur.angle -> angle: float "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeDBlur.center_x -> center_x: float "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeDBlur.center_y -> center_y: float "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeDBlur.distance -> distance: float "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeDBlur.iterations -> iterations: int "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeDBlur.spin -> spin: float "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeDBlur.use_wrap -> use_wrap: boolean "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeDBlur.zoom -> zoom: float "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeDefocus.angle -> angle: int "Bokeh shape rotation offset in degrees"
+#Node|CompositorNode|CompositorNodeDefocus.blur_max -> blur_max: float "blur limit, maximum CoC radius, 0=no limit"
+#+ * Node|CompositorNode|CompositorNodeDefocus.bokeh -> bokeh: enum "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeDefocus.f_stop -> f_stop: float "Amount of focal blur, 128=infinity=perfect focus, half the value doubles the blur radius"
+#+ * Node|CompositorNode|CompositorNodeDefocus.samples -> samples: int "Number of samples (16=grainy, higher=less noise)"
+#+ * Node|CompositorNode|CompositorNodeDefocus.threshold -> threshold: float "CoC radius threshold, prevents background bleed on in-focus midground, 0=off"
+#Node|CompositorNode|CompositorNodeDefocus.use_gamma_correction -> use_gamma_correction: boolean "Enable gamma correction before and after main process"
+#Node|CompositorNode|CompositorNodeDefocus.use_preview -> use_preview: boolean "Enable sampling mode, useful for preview when using low samplecounts"
+#+ * Node|CompositorNode|CompositorNodeDefocus.use_zbuffer -> use_zbuffer: boolean "Disable when using an image as input instead of actual zbuffer (auto enabled if node not image based, eg. time node)"
+#+ * Node|CompositorNode|CompositorNodeDefocus.z_scale -> z_scale: float "Scales the Z input when not using a zbuffer, controls maximum blur designated by the color white or input value 1"
+#+ * Node|CompositorNode|CompositorNodeDiffMatte.falloff -> falloff: float "Color distances below this additional threshold are partially keyed"
+#+ * Node|CompositorNode|CompositorNodeDiffMatte.tolerance -> tolerance: float "Color distances below this threshold are keyed"
+#+ * Node|CompositorNode|CompositorNodeDilateErode.distance -> distance: int "Distance to grow/shrink (number of iterations)"
+#+ * Node|CompositorNode|CompositorNodeDistanceMatte.falloff -> falloff: float "Color distances below this additional threshold are partially keyed"
+#+ * Node|CompositorNode|CompositorNodeDistanceMatte.tolerance -> tolerance: float "Color distances below this threshold are keyed"
+#+ * Node|CompositorNode|CompositorNodeFilter.filter_type -> filter_type: enum "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeFlip.axis -> axis: enum "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeGlare.angle_offset -> angle_offset: float "Streak angle offset in degrees"
+#+ * Node|CompositorNode|CompositorNodeGlare.color_modulation -> color_modulation: float "Amount of Color Modulation, modulates colors of streaks and ghosts for a spectral dispersion effect"
+#+ * Node|CompositorNode|CompositorNodeGlare.fade -> fade: float "Streak fade-out factor"
+#+ * Node|CompositorNode|CompositorNodeGlare.glare_type -> glare_type: enum "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeGlare.iterations -> iterations: int "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeGlare.mix -> mix: float "-1 is original image only, 0 is exact 50/50 mix, 1 is processed image only"
+#+ * Node|CompositorNode|CompositorNodeGlare.quality -> quality: enum "If not set to high quality, the effect will be applied to a low-res copy of the source image"
+#+ * Node|CompositorNode|CompositorNodeGlare.size -> size: int "Glow/glare size (not actual size; relative to initial size of bright area of pixels)"
+#+ * Node|CompositorNode|CompositorNodeGlare.streaks -> streaks: int "Total number of streaks"
+#+ * Node|CompositorNode|CompositorNodeGlare.threshold -> threshold: float "The glare filter will only be applied to pixels brighter than this value"
+#Node|CompositorNode|CompositorNodeGlare.use_rotate_45 -> use_rotate_45: boolean "Simple star filter: add 45 degree rotation offset"
+#+ * Node|CompositorNode|CompositorNodeHueCorrect.mapping -> mapping: pointer, "(read-only)"
+#Node|CompositorNode|CompositorNodeHueSat.color_hue -> color_hue: float "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeHueSat.color_saturation -> color_saturation: float "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeHueSat.color_value -> color_value: float "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeIDMask.index -> index: int "Pass index number to convert to alpha"
+#Node|CompositorNode|CompositorNodeImage.frame_duration -> frame_duration: int "Number of images used in animation"
+#Node|CompositorNode|CompositorNodeImage.frame_offset -> frame_offset: int "Offsets the number of the frame to use in the animation"
+#Node|CompositorNode|CompositorNodeImage.frame_start -> frame_start: int "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeImage.image -> image: pointer "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeImage.layer -> layer: enum "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeImage.use_auto_refresh -> use_auto_refresh: boolean "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeImage.use_cyclic -> use_cyclic: boolean "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeInvert.invert_alpha -> invert_alpha: boolean "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeInvert.invert_rgb -> invert_rgb: boolean "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeLensdist.use_fit -> use_fit: boolean "For positive distortion factor only: scale image such that black areas are not visible"
+#Node|CompositorNode|CompositorNodeLensdist.use_jitter -> use_jitter: boolean "Enable/disable jittering; faster, but also noisier"
+#Node|CompositorNode|CompositorNodeLensdist.use_projector -> use_projector: boolean "Enable/disable projector mode. Effect is applied in horizontal direction only"
+#+ * Node|CompositorNode|CompositorNodeLevels.channel -> channel: enum "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeLumaMatte.limit_max -> limit_max: float "Values higher than this setting are 100% opaque"
+#Node|CompositorNode|CompositorNodeLumaMatte.limit_min -> limit_min: float "Values lower than this setting are 100% keyed"
+#+ * Node|CompositorNode|CompositorNodeMapUV.alpha -> alpha: int "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeMapValue.max -> max: float[1] "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeMapValue.min -> min: float[1] "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeMapValue.offset -> offset: float[1] "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeMapValue.size -> size: float[1] "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeMapValue.use_max -> use_max: boolean "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeMapValue.use_min -> use_min: boolean "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeMath.operation -> operation: enum "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeMixRGB.blend_type -> blend_type: enum "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeMixRGB.use_alpha -> use_alpha: boolean "Include alpha of second input in this operation"
+#+ * Node|CompositorNode|CompositorNodeOutputFile.exr_codec -> exr_codec: enum "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeOutputFile.filepath -> filepath: string "Output path for the image, same functionality as render output."
+#+ * Node|CompositorNode|CompositorNodeOutputFile.frame_end -> frame_end: int "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeOutputFile.frame_start -> frame_start: int "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeOutputFile.image_type -> image_type: enum "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeOutputFile.quality -> quality: int "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeOutputFile.use_exr_half -> use_exr_half: boolean "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodePremulKey.mapping -> mapping: enum "Conversion between premultiplied alpha and key alpha"
+#+ * Node|CompositorNode|CompositorNodeRLayers.layer -> layer: enum "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeRLayers.scene -> scene: pointer "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeRotate.filter_type -> filter_type: enum "Method to use to filter rotation"
+#+ * Node|CompositorNode|CompositorNodeScale.space -> space: enum "Coordinate space to scale relative to"
+#+ * Node|CompositorNode|CompositorNodeSplitViewer.axis -> axis: enum "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeSplitViewer.factor -> factor: int "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeTexture.node_output -> node_output: int "For node-based textures, which output node to use"
+#+ * Node|CompositorNode|CompositorNodeTexture.texture -> texture: pointer "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeTime.curve -> curve: pointer, "(read-only)"
+#Node|CompositorNode|CompositorNodeTime.frame_end -> frame_end: int "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeTime.frame_start -> frame_start: int "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeTonemap.adaptation -> adaptation: float "If 0, global; if 1, based on pixel intensity"
+#+ * Node|CompositorNode|CompositorNodeTonemap.contrast -> contrast: float "Set to 0 to use estimate from input image"
+#+ * Node|CompositorNode|CompositorNodeTonemap.correction -> correction: float "If 0, same for all channels; if 1, each independent"
+#+ * Node|CompositorNode|CompositorNodeTonemap.gamma -> gamma: float "If not used, set to 1"
+#+ * Node|CompositorNode|CompositorNodeTonemap.intensity -> intensity: float "If less than zero, darkens image; otherwise, makes it brighter"
+#+ * Node|CompositorNode|CompositorNodeTonemap.key -> key: float "The value the average luminance is mapped to"
+#+ * Node|CompositorNode|CompositorNodeTonemap.offset -> offset: float "Normally always 1, but can be used as an extra control to alter the brightness curve"
+#+ * Node|CompositorNode|CompositorNodeTonemap.tonemap_type -> tonemap_type: enum "NO DESCRIPTION"
+#+ * Node|CompositorNode|CompositorNodeValToRGB.color_ramp -> color_ramp: pointer, "(read-only)"
+#+ * Node|CompositorNode|CompositorNodeVecBlur.factor -> factor: float "Scaling factor for motion vectors; actually shutter speed in frames"
+#+ * Node|CompositorNode|CompositorNodeVecBlur.samples -> samples: int "NO DESCRIPTION"
+#Node|CompositorNode|CompositorNodeVecBlur.speed_max -> speed_max: int "Maximum speed, or zero for none"
+#Node|CompositorNode|CompositorNodeVecBlur.speed_min -> speed_min: int "Minimum speed for a pixel to be blurred; used to separate background from foreground"
+#Node|CompositorNode|CompositorNodeVecBlur.use_curved -> use_curved: boolean "Interpolate between frames in a bezier curve, rather than linearly"
+#+ * Node|NodeGroup.nodetree -> nodetree: pointer "NO DESCRIPTION"
+#+ * Node|ShaderNode.type -> type: enum, "(read-only)"
+#+ * Node|ShaderNode|ShaderNodeExtendedMaterial.invert_normal -> invert_normal: boolean "Material Node uses inverted normal"
+#+ * Node|ShaderNode|ShaderNodeExtendedMaterial.material -> material: pointer "NO DESCRIPTION"
+#Node|ShaderNode|ShaderNodeExtendedMaterial.use_diffuse -> use_diffuse: boolean "Material Node outputs Diffuse"
+#Node|ShaderNode|ShaderNodeExtendedMaterial.use_specular -> use_specular: boolean "Material Node outputs Specular"
+#+ * Node|ShaderNode|ShaderNodeGeometry.color_layer -> color_layer: string "NO DESCRIPTION"
+#+ * Node|ShaderNode|ShaderNodeGeometry.uv_layer -> uv_layer: string "NO DESCRIPTION"
+#+ * Node|ShaderNode|ShaderNodeMapping.location -> location: float[3] "Location offset for the input coordinate"
+#Node|ShaderNode|ShaderNodeMapping.max -> max: float[3] "Maximum value to clamp coordinate to"
+#Node|ShaderNode|ShaderNodeMapping.min -> min: float[3] "Minimum value to clamp coordinate to"
+#+ * Node|ShaderNode|ShaderNodeMapping.rotation -> rotation: float[3] "Rotation offset for the input coordinate"
+#+ * Node|ShaderNode|ShaderNodeMapping.scale -> scale: float[3] "Scale adjustment for the input coordinate"
+#Node|ShaderNode|ShaderNodeMapping.use_max -> use_max: boolean "Clamp the output coordinate to a maximum value"
+#Node|ShaderNode|ShaderNodeMapping.use_min -> use_min: boolean "Clamp the output coordinate to a minimum value"
+#+ * Node|ShaderNode|ShaderNodeMaterial.invert_normal -> invert_normal: boolean "Material Node uses inverted normal"
+#+ * Node|ShaderNode|ShaderNodeMaterial.material -> material: pointer "NO DESCRIPTION"
+#Node|ShaderNode|ShaderNodeMaterial.use_diffuse -> use_diffuse: boolean "Material Node outputs Diffuse"
+#Node|ShaderNode|ShaderNodeMaterial.use_specular -> use_specular: boolean "Material Node outputs Specular"
+#+ * Node|ShaderNode|ShaderNodeMath.operation -> operation: enum "NO DESCRIPTION"
+#+ * Node|ShaderNode|ShaderNodeMixRGB.blend_type -> blend_type: enum "NO DESCRIPTION"
+#Node|ShaderNode|ShaderNodeMixRGB.use_alpha -> use_alpha: boolean "Include alpha of second input in this operation"
+#+ * Node|ShaderNode|ShaderNodeRGBCurve.mapping -> mapping: pointer, "(read-only)"
+#+ * Node|ShaderNode|ShaderNodeTexture.node_output -> node_output: int "For node-based textures, which output node to use"
+#+ * Node|ShaderNode|ShaderNodeTexture.texture -> texture: pointer "NO DESCRIPTION"
+#+ * Node|ShaderNode|ShaderNodeValToRGB.color_ramp -> color_ramp: pointer, "(read-only)"
+#+ * Node|ShaderNode|ShaderNodeVectorCurve.mapping -> mapping: pointer, "(read-only)"
+#+ * Node|ShaderNode|ShaderNodeVectorMath.operation -> operation: enum "NO DESCRIPTION"
+#+ * Node|TextureNode.type -> type: enum, "(read-only)"
+#+ * Node|TextureNode|TextureNodeBricks.offset -> offset: float "NO DESCRIPTION"
+#+ * Node|TextureNode|TextureNodeBricks.offset_frequency -> offset_frequency: int "Offset every N rows"
+#+ * Node|TextureNode|TextureNodeBricks.squash -> squash: float "NO DESCRIPTION"
+#+ * Node|TextureNode|TextureNodeBricks.squash_frequency -> squash_frequency: int "Squash every N rows"
+#+ * Node|TextureNode|TextureNodeCurveRGB.mapping -> mapping: pointer, "(read-only)"
+#+ * Node|TextureNode|TextureNodeCurveTime.curve -> curve: pointer, "(read-only)"
+#Node|TextureNode|TextureNodeCurveTime.frame_end -> frame_end: int "NO DESCRIPTION"
+#Node|TextureNode|TextureNodeCurveTime.frame_start -> frame_start: int "NO DESCRIPTION"
+#+ * Node|TextureNode|TextureNodeImage.image -> image: pointer "NO DESCRIPTION"
+#+ * Node|TextureNode|TextureNodeMath.operation -> operation: enum "NO DESCRIPTION"
+#+ * Node|TextureNode|TextureNodeMixRGB.blend_type -> blend_type: enum "NO DESCRIPTION"
+#Node|TextureNode|TextureNodeMixRGB.use_alpha -> use_alpha: boolean "Include alpha of second input in this operation"
+#Node|TextureNode|TextureNodeOutput.filepath -> filepath: string "NO DESCRIPTION"
+#+ * Node|TextureNode|TextureNodeTexture.node_output -> node_output: int "For node-based textures, which output node to use"
+#+ * Node|TextureNode|TextureNodeTexture.texture -> texture: pointer "NO DESCRIPTION"
+#+ * Node|TextureNode|TextureNodeValToRGB.color_ramp -> color_ramp: pointer, "(read-only)"
+#+ * ObjectBase.layers -> layers: boolean[20] "Layers the object base is on"
+#+ * ObjectBase.object -> object: pointer, "(read-only) Object this base links to"
+#+ * ObjectBase.select -> select: boolean "Object base selection state"
+#+ * ObjectConstraints.active -> active: pointer "Active Object constraint"
+#+ * Operator.bl_description -> bl_description: string "NO DESCRIPTION"
+#+ * Operator.bl_idname -> bl_idname: string "NO DESCRIPTION"
+#+ * Operator.bl_label -> bl_label: string "NO DESCRIPTION"
+#+ * Operator.bl_options -> bl_options: enum "Options for this operator type"
+#+ * Operator.has_reports -> has_reports: boolean, "(read-only) Operator has a set of reports (warnings and errors) from last execution"
+#+ * Operator.layout -> layout: pointer, "(read-only)"
+#+ * Operator.name -> name: string, "(read-only)"
+#+ * Operator.properties -> properties: pointer, "(read-only)"
+#+ * OperatorTypeMacro.properties -> properties: pointer, "(read-only)"
+#+ * PackedFile.size -> size: int, "(read-only) Size of packed file in bytes"
+#+ * Paint.brush -> brush: pointer "Active Brush"
+#+ * Paint.show_brush -> show_brush: boolean "NO DESCRIPTION"
+#+ * Paint.show_brush_on_surface -> show_brush_on_surface: boolean "NO DESCRIPTION"
+#Paint.show_low_resolution -> show_low_resolution: boolean "For multires, show low resolution while navigating the view"
+#+ * Paint|ImagePaint.invert_stencil -> invert_stencil: boolean "Invert the stencil layer"
+#+ * Paint|ImagePaint.normal_angle -> normal_angle: int "Paint most on faces pointing towards the view according to this angle"
+#+ * Paint|ImagePaint.screen_grab_size -> screen_grab_size: int[2] "Size to capture the image for re-projecting"
+#+ * Paint|ImagePaint.seam_bleed -> seam_bleed: int "Extend paint beyond the faces UVs to reduce seams (in pixels, slower)"
+#+ * Paint|ImagePaint.show_brush -> show_brush: boolean "Enables brush shape while not drawing"
+#+ * Paint|ImagePaint.show_brush_draw -> show_brush_draw: boolean "Enables brush shape while drawing"
+#Paint|ImagePaint.use_backface_culling -> use_backface_culling: boolean "Ignore faces pointing away from the view (faster)"
+#+ * Paint|ImagePaint.use_clone_layer -> use_clone_layer: boolean "Use another UV layer as clone source, otherwise use 3D the cursor as the source"
+#+ * Paint|ImagePaint.use_normal_falloff -> use_normal_falloff: boolean "Paint most on faces pointing towards the view"
+#+ * Paint|ImagePaint.use_occlude -> use_occlude: boolean "Only paint onto the faces directly under the brush (slower)"
+#+ * Paint|ImagePaint.use_projection -> use_projection: boolean "Use projection painting for improved consistency in the brush strokes"
+#+ * Paint|ImagePaint.use_stencil_layer -> use_stencil_layer: boolean "Set the mask layer from the UV layer buttons"
+#+ * Paint|Sculpt.lock_x -> lock_x: boolean "Disallow changes to the X axis of vertices"
+#+ * Paint|Sculpt.lock_y -> lock_y: boolean "Disallow changes to the Y axis of vertices"
+#+ * Paint|Sculpt.lock_z -> lock_z: boolean "Disallow changes to the Z axis of vertices"
+#Paint|Sculpt.radial_symmetry -> radial_symmetry: int[3] "Number of times to copy strokes across the surface"
+#+ * Paint|Sculpt.use_symmetry_feather -> use_symmetry_feather: boolean "Reduce the strength of the brush where it overlaps symmetrical daubs"
+#Paint|Sculpt.use_symmetry_x -> use_symmetry_x: boolean "Mirror brush across the X axis"
+#Paint|Sculpt.use_symmetry_y -> use_symmetry_y: boolean "Mirror brush across the Y axis"
+#Paint|Sculpt.use_symmetry_z -> use_symmetry_z: boolean "Mirror brush across the Z axis"
+#Paint|Sculpt.use_threaded -> use_threaded: boolean "Take advantage of multiple CPU cores to improve sculpting performance"
+#Paint|VertexPaint.use_all_faces -> use_all_faces: boolean "Paint on all faces inside brush"
+#Paint|VertexPaint.use_normal -> use_normal: boolean "Applies the vertex normal before painting"
+#Paint|VertexPaint.use_spray -> use_spray: boolean "Keep applying paint effect while holding mouse"
+#+ * Panel.bl_context -> bl_context: string "The context in which the panel belongs to. (TODO: explain the possible combinations bl_context/bl_region_type/bl_space_type)"
+#+ * Panel.bl_idname -> bl_idname: string "If this is set, the panel gets a custom ID, otherwise it takes the name of the class used to define the panel. For example, if the class name is OBJECT_PT_hello, and bl_idname is not set by the script, then bl_idname = OBJECT_PT_hello"
+#+ * Panel.bl_label -> bl_label: string "The panel label, shows up in the panel header at the right of the triangle used to collapse the panel."
+#+ * Panel.bl_region_type -> bl_region_type: enum "The region where the panel is going to be used in."
+#+ * Panel.bl_show_header -> bl_show_header: boolean "If set to True, the panel shows a header, which contains a clickable arrow to collapse the panel and the label (see bl_label)."
+#+ * Panel.bl_space_type -> bl_space_type: enum "The space where the panel is going to be used in."
+ + * Panel.bl_default_closed -> bl_use_closed: boolean "Defines if the panel has to be open or collapsed at the time of its creation. Note that once the panel has been created with bl_default_closed = True, at reload (F8) it stays open."
+#+ * Panel.layout -> layout: pointer, "(read-only) Defines the structure of the panel in the UI."
+#TODO SHOULD THIS BE HERE * Panel.text -> text: string "XXX todo"
+#+ * Particle.alive_state -> alive_state: enum "NO DESCRIPTION"
+#+ * Particle.angular_velocity -> angular_velocity: float[3] "NO DESCRIPTION"
+#Particle.birth_time -> birth_time: float "NO DESCRIPTION"
+#+ * Particle.die_time -> die_time: float "NO DESCRIPTION"
+#Particle.is_exist -> is_exist: boolean, "(read-only)"
+#Particle.is_hair -> is_hair: collection, "(read-only)"
+#+ * Particle.is_visible -> is_visible: boolean, "(read-only)"
+#+ * Particle.keys -> keys: collection, "(read-only)"
+#+ * Particle.lifetime -> lifetime: float "NO DESCRIPTION"
+#+ * Particle.location -> location: float[3] "NO DESCRIPTION"
+#+ * Particle.prev_angular_velocity -> prev_angular_velocity: float[3] "NO DESCRIPTION"
+#+ * Particle.prev_location -> prev_location: float[3] "NO DESCRIPTION"
+#+ * Particle.prev_rotation -> prev_rotation: float[4] "NO DESCRIPTION"
+#+ * Particle.prev_velocity -> prev_velocity: float[3] "NO DESCRIPTION"
+#+ * Particle.rotation -> rotation: float[4] "NO DESCRIPTION"
+#+ * Particle.size -> size: float "NO DESCRIPTION"
+#+ * Particle.velocity -> velocity: float[3] "NO DESCRIPTION"
+#+ * ParticleBrush.count -> count: int "Particle count"
+#+ * ParticleBrush.curve -> curve: pointer, "(read-only)"
+#+ * ParticleBrush.length_mode -> length_mode: enum "NO DESCRIPTION"
+#+ * ParticleBrush.puff_mode -> puff_mode: enum "NO DESCRIPTION"
+#+ * ParticleBrush.size -> size: int "Brush size"
+#+ * ParticleBrush.steps -> steps: int "Brush steps"
+#+ * ParticleBrush.strength -> strength: float "Brush strength"
+#+ * ParticleBrush.use_puff_volume -> use_puff_volume: boolean "Apply puff to unselected end-points, (helps maintain hair volume when puffing root)"
+#+ * ParticleDupliWeight.count -> count: int "The number of times this object is repeated with respect to other objects"
+#+ * ParticleDupliWeight.name -> name: string, "(read-only) Particle dupliobject name"
+#+ * ParticleEdit.brush -> brush: pointer, "(read-only)"
+#ParticleEdit.default_key_count -> default_key_count: int "How many keys to make new particles with"
+#+ * ParticleEdit.draw_step -> draw_step: int "How many steps to draw the path with"
+#+ * ParticleEdit.emitter_distance -> emitter_distance: float "Distance to keep particles away from the emitter"
+#+ * ParticleEdit.fade_frames -> fade_frames: int "How many frames to fade"
+#ParticleEdit.is_editable -> is_editable: boolean, "(read-only) A valid edit mode exists"
+#ParticleEdit.is_hair -> is_hair: boolean, "(read-only) Editing hair"
+#+ * ParticleEdit.object -> object: pointer, "(read-only) The edited object"
+#ParticleEdit.select_mode -> select_mode: enum "Particle select and display mode"
+#ParticleEdit.show_particles -> show_particles: boolean "Draw actual particles"
+#+ * ParticleEdit.tool -> tool: enum "NO DESCRIPTION"
+#+ * ParticleEdit.type -> type: enum "NO DESCRIPTION"
+#ParticleEdit.use_auto_velocity -> use_auto_velocity: boolean "Calculate point velocities automatically"
+#ParticleEdit.use_default_interpolate -> use_default_interpolate: boolean "Interpolate new particles from the existing ones"
+#ParticleEdit.use_emitter_deflect -> use_emitter_deflect: boolean "Keep paths from intersecting the emitter"
+#ParticleEdit.use_fade_time -> use_fade_time: boolean "Fade paths and keys further away from current frame"
+#ParticleEdit.use_preserve_length -> use_preserve_length: boolean "Keep path lengths constant"
+#ParticleEdit.use_preserve_root -> use_preserve_root: boolean "Keep root keys unmodified"
+#ParticleHairKey.co -> co: float[3] "Location of the hair key in object space"
+#ParticleHairKey.co_hair_space -> co_hair_space: float[3] "Location of the hair key in its internal coordinate system, relative to the emitting face"
+#+ * ParticleHairKey.time -> time: float "Relative time of key over hair length"
+#+ * ParticleHairKey.weight -> weight: float "Weight for cloth simulation"
+#+ * ParticleKey.angular_velocity -> angular_velocity: float[3] "Key angular velocity"
+#+ * ParticleKey.location -> location: float[3] "Key location"
+#+ * ParticleKey.rotation -> rotation: float[4] "Key rotation quaterion"
+#+ * ParticleKey.time -> time: float "Time of key over the simulation"
+#+ * ParticleKey.velocity -> velocity: float[3] "Key velocity"
+#+ * ParticleSystem.active_particle_target -> active_particle_target: pointer, "(read-only)"
+#+ * ParticleSystem.active_particle_target_index -> active_particle_target_index: int "NO DESCRIPTION"
+#+ * ParticleSystem.billboard_normal_uv -> billboard_normal_uv: string "UV Layer to control billboard normals"
+#+ * ParticleSystem.billboard_split_uv -> billboard_split_uv: string "UV Layer to control billboard splitting"
+#+ * ParticleSystem.billboard_time_index_uv -> billboard_time_index_uv: string "UV Layer to control billboard time index (X-Y)"
+#+ * ParticleSystem.child_particles -> child_particles: collection, "(read-only) Child particles generated by the particle system"
+#+ * ParticleSystem.cloth -> cloth: pointer, "(read-only) Cloth dynamics for hair"
+#ParticleSystem.has_multiple_caches -> has_multiple_caches: boolean, "(read-only) Particle system has multiple point caches"
+#ParticleSystem.invert_vertex_group_clump -> invert_vertex_group_clump: boolean "Negate the effect of the clump vertex group"
+#ParticleSystem.invert_vertex_group_density -> invert_vertex_group_density: boolean "Negate the effect of the density vertex group"
+#ParticleSystem.invert_vertex_group_field -> invert_vertex_group_field: boolean "Negate the effect of the field vertex group"
+#ParticleSystem.invert_vertex_group_kink -> invert_vertex_group_kink: boolean "Negate the effect of the kink vertex group"
+#ParticleSystem.invert_vertex_group_length -> invert_vertex_group_length: boolean "Negate the effect of the length vertex group"
+#ParticleSystem.invert_vertex_group_rotation -> invert_vertex_group_rotation: boolean "Negate the effect of the rotation vertex group"
+#ParticleSystem.invert_vertex_group_roughness_1 -> invert_vertex_group_roughness_1: boolean "Negate the effect of the roughness 1 vertex group"
+#ParticleSystem.invert_vertex_group_roughness_2 -> invert_vertex_group_roughness_2: boolean "Negate the effect of the roughness 2 vertex group"
+#ParticleSystem.invert_vertex_group_roughness_end -> invert_vertex_group_roughness_end: boolean "Negate the effect of the roughness end vertex group"
+#ParticleSystem.invert_vertex_group_size -> invert_vertex_group_size: boolean "Negate the effect of the size vertex group"
+#ParticleSystem.invert_vertex_group_tangent -> invert_vertex_group_tangent: boolean "Negate the effect of the tangent vertex group"
+#ParticleSystem.invert_vertex_group_velocity -> invert_vertex_group_velocity: boolean "Negate the effect of the velocity vertex group"
+#ParticleSystem.is_editable -> is_editable: boolean, "(read-only) Particle system can be edited in particle mode"
+#ParticleSystem.is_edited -> is_edited: boolean, "(read-only) Particle system has been edited in particle mode"
+#ParticleSystem.is_global_hair -> is_global_hair: boolean, "(read-only) Hair keys are in global coordinate space"
+#+ * ParticleSystem.name -> name: string "Particle system name"
+#+ * ParticleSystem.parent -> parent: pointer "Use this objects coordinate system instead of global coordinate system"
+#+ * ParticleSystem.particles -> particles: collection, "(read-only) Particles generated by the particle system"
+#+ * ParticleSystem.point_cache -> point_cache: pointer, "(read-only)"
+#+ * ParticleSystem.reactor_target_object -> reactor_target_object: pointer "For reactor systems, the object that has the target particle system (empty if same object)"
+#+ * ParticleSystem.reactor_target_particle_system -> reactor_target_particle_system: int "For reactor systems, index of particle system on the target object"
+#+ * ParticleSystem.seed -> seed: int "Offset in the random number table, to get a different randomized result"
+#+ * ParticleSystem.settings -> settings: pointer "Particle system settings"
+#+ * ParticleSystem.targets -> targets: collection, "(read-only) Target particle systems"
+#ParticleSystem.use_hair_dynamics -> use_hair_dynamics: boolean "Enable hair dynamics using cloth simulation"
+#ParticleSystem.use_keyed_timing -> use_keyed_timing: boolean "Use key times"
+#+ * ParticleSystem.vertex_group_clump -> vertex_group_clump: string "Vertex group to control clump"
+#+ * ParticleSystem.vertex_group_density -> vertex_group_density: string "Vertex group to control density"
+#+ * ParticleSystem.vertex_group_field -> vertex_group_field: string "Vertex group to control field"
+#+ * ParticleSystem.vertex_group_kink -> vertex_group_kink: string "Vertex group to control kink"
+#+ * ParticleSystem.vertex_group_length -> vertex_group_length: string "Vertex group to control length"
+#+ * ParticleSystem.vertex_group_rotation -> vertex_group_rotation: string "Vertex group to control rotation"
+#ParticleSystem.vertex_group_roughness_1 -> vertex_group_roughness_1: string "Vertex group to control roughness 1"
+#ParticleSystem.vertex_group_roughness_2 -> vertex_group_roughness_2: string "Vertex group to control roughness 2"
+#+ * ParticleSystem.vertex_group_roughness_end -> vertex_group_roughness_end: string "Vertex group to control roughness end"
+#+ * ParticleSystem.vertex_group_size -> vertex_group_size: string "Vertex group to control size"
+#+ * ParticleSystem.vertex_group_tangent -> vertex_group_tangent: string "Vertex group to control tangent"
+#+ * ParticleSystem.vertex_group_velocity -> vertex_group_velocity: string "Vertex group to control velocity"
+#ParticleTarget.alliance -> alliance: enum "NO DESCRIPTION"
+#+ * ParticleTarget.duration -> duration: float "NO DESCRIPTION"
+#ParticleTarget.is_valid -> is_valid: boolean "Keyed particles target is valid"
+#+ * ParticleTarget.name -> name: string, "(read-only) Particle target name"
+#+ * ParticleTarget.object -> object: pointer "The object that has the target particle system (empty if same object)"
+#+ * ParticleTarget.system -> system: int "The index of particle system on the target object"
+#+ * ParticleTarget.time -> time: float "NO DESCRIPTION"
+#+ * PointCache.active_point_cache_index -> active_point_cache_index: int "NO DESCRIPTION"
+#+ * PointCache.filepath -> filepath: string "Cache file path"
+#+ * PointCache.frame_end -> frame_end: int "Frame on which the simulation stops"
+#+ * PointCache.frame_start -> frame_start: int "Frame on which the simulation starts"
+#PointCache.frame_step -> frame_step: int "Number of frames between cached frames"
+#+ * PointCache.frames_skipped -> frames_skipped: boolean, "(read-only)"
+#+ * PointCache.index -> index: int "Index number of cache files"
+#+ * PointCache.info -> info: string, "(read-only) Info on current cache status"
+#PointCache.is_baked -> is_baked: boolean, "(read-only)"
+#PointCache.is_baking -> is_baking: boolean, "(read-only)"
+#PointCache.is_outdated -> is_outdated: boolean, "(read-only)"
+#+ * PointCache.name -> name: string "Cache name"
+#PointCache.point_caches -> point_caches: collection, "(read-only) Point cache list"
+#PointCache.use_disk_cache -> use_disk_cache: boolean "Save cache files to disk (.blend file must be saved first)"
+#PointCache.use_external -> use_external: boolean "Read cache from an external location"
+#+ * PointCache.use_library_path -> use_library_path: boolean "Use this files path when library linked into another file."
+#PointCache.use_quick_cache -> use_quick_cache: boolean "Update simulation with cache steps"
+#+ * PointDensity.color_ramp -> color_ramp: pointer, "(read-only)"
+#+ * PointDensity.color_source -> color_source: enum "Data to derive color results from"
+#+ * PointDensity.falloff -> falloff: enum "Method of attenuating density by distance from the point"
+#PointDensity.falloff_soft -> falloff_soft: float "Softness of the soft falloff option"
+#+ * PointDensity.noise_basis -> noise_basis: enum "Noise formula used for turbulence"
+#+ * PointDensity.object -> object: pointer "Object to take point data from"
+#PointDensity.particle_cache_space -> particle_cache_space: enum "Co-ordinate system to cache particles in"
+#+ * PointDensity.particle_system -> particle_system: pointer "Particle System to render as points"
+#+ * PointDensity.point_source -> point_source: enum "Point data to use as renderable point density"
+#+ * PointDensity.radius -> radius: float "Radius from the shaded sample to look for points within"
+#+ * PointDensity.speed_scale -> speed_scale: float "Multiplier to bring particle speed within an acceptable range"
+#+ * PointDensity.turbulence_depth -> turbulence_depth: int "Level of detail in the added turbulent noise"
+#+ * PointDensity.turbulence_influence -> turbulence_influence: enum "Method for driving added turbulent noise"
+#PointDensity.turbulence_scale -> turbulence_scale: float "Scale of the added turbulent noise"
+#+ * PointDensity.turbulence_strength -> turbulence_strength: float "NO DESCRIPTION"
+#PointDensity.use_turbulence -> use_turbulence: boolean "Add directed noise to the density at render-time"
+#PointDensity.vertex_cache_space -> vertex_cache_space: enum "Co-ordinate system to cache vertices in"
+#+ * Pose.active_bone_group_index -> active_bone_group_index: int "Active index in bone groups array"
+#+ * Pose.animation_visualisation -> animation_visualisation: pointer, "(read-only) Animation data for this datablock"
+#+ * Pose.bone_groups -> bone_groups: collection, "(read-only) Groups of the bones"
+#+ * Pose.bones -> bones: collection, "(read-only) Individual pose bones for the armature"
+#+ * Pose.ik_param -> ik_param: pointer, "(read-only) Parameters for IK solver"
+#+ * Pose.ik_solver -> ik_solver: enum "Selection of IK solver for IK chain, current choice is 0 for Legacy, 1 for iTaSC"
+#+ * PoseBone.bone -> bone: pointer, "(read-only) Bone associated with this PoseBone"
+#+ * PoseBone.bone_group -> bone_group: pointer "Bone Group this pose channel belongs to"
+#+ * PoseBone.bone_group_index -> bone_group_index: int "Bone Group this pose channel belongs to (0=no group)"
+#+ * PoseBone.child -> child: pointer, "(read-only) Child of this pose bone"
+#+ * PoseBone.constraints -> constraints: collection, "(read-only) Constraints that act on this PoseChannel"
+#+ * PoseBone.custom_shape -> custom_shape: pointer "Object that defines custom draw type for this bone"
+#+ * PoseBone.custom_shape_transform -> custom_shape_transform: pointer "Bone that defines the display transform of this custom shape"
+#+ * PoseBone.head -> head: float[3], "(read-only) Location of head of the channels bone"
+#PoseBone.ik_linear_weight -> ik_linear_weight: float "Weight of scale constraint for IK"
+#+ * PoseBone.ik_max_x -> ik_max_x: float "Maximum angles for IK Limit"
+#+ * PoseBone.ik_max_y -> ik_max_y: float "Maximum angles for IK Limit"
+#+ * PoseBone.ik_max_z -> ik_max_z: float "Maximum angles for IK Limit"
+#+ * PoseBone.ik_min_x -> ik_min_x: float "Minimum angles for IK Limit"
+#+ * PoseBone.ik_min_y -> ik_min_y: float "Minimum angles for IK Limit"
+#+ * PoseBone.ik_min_z -> ik_min_z: float "Minimum angles for IK Limit"
+#PoseBone.ik_rotation_weight -> ik_rotation_weight: float "Weight of rotation constraint for IK"
+#+ * PoseBone.ik_stiffness_x -> ik_stiffness_x: float "IK stiffness around the X axis"
+#+ * PoseBone.ik_stiffness_y -> ik_stiffness_y: float "IK stiffness around the Y axis"
+#+ * PoseBone.ik_stiffness_z -> ik_stiffness_z: float "IK stiffness around the Z axis"
+#+ * PoseBone.ik_stretch -> ik_stretch: float "Allow scaling of the bone for IK"
+#PoseBone.is_in_ik_chain -> is_in_ik_chain: boolean, "(read-only) Is part of an IK chain"
+#+ * PoseBone.location -> location: float[3] "NO DESCRIPTION"
+#PoseBone.lock_ik_x -> lock_ik_x: boolean "Disallow movement around the X axis"
+#PoseBone.lock_ik_y -> lock_ik_y: boolean "Disallow movement around the Y axis"
+#PoseBone.lock_ik_z -> lock_ik_z: boolean "Disallow movement around the Z axis"
+#+ * PoseBone.lock_location -> lock_location: boolean[3] "Lock editing of location in the interface"
+#+ * PoseBone.lock_rotation -> lock_rotation: boolean[3] "Lock editing of rotation in the interface"
+#+ * PoseBone.lock_rotation_w -> lock_rotation_w: boolean "Lock editing of angle component of four-component rotations in the interface"
+#+ * PoseBone.lock_rotations_4d -> lock_rotations_4d: boolean "Lock editing of four component rotations by components (instead of as Eulers)"
+#+ * PoseBone.lock_scale -> lock_scale: boolean[3] "Lock editing of scale in the interface"
+#+ * PoseBone.matrix -> matrix: float[16], "(read-only) Final 4x4 matrix for this channel"
+#+ * PoseBone.matrix_channel -> matrix_channel: float[16], "(read-only) 4x4 matrix, before constraints"
+#+ * PoseBone.matrix_local -> matrix_local: float[16] "Matrix representing the parent relative location, scale and rotation. Provides an alternative access to these properties."
+#+ * PoseBone.motion_path -> motion_path: pointer, "(read-only) Motion Path for this element"
+#+ * PoseBone.name -> name: string "NO DESCRIPTION"
+#+ * PoseBone.parent -> parent: pointer, "(read-only) Parent of this pose bone"
+#+ * PoseBone.rotation_axis_angle -> rotation_axis_angle: float[4] "Angle of Rotation for Axis-Angle rotation representation"
+#+ * PoseBone.rotation_euler -> rotation_euler: float[3] "Rotation in Eulers"
+#+ * PoseBone.rotation_mode -> rotation_mode: enum "NO DESCRIPTION"
+#+ * PoseBone.rotation_quaternion -> rotation_quaternion: float[4] "Rotation in Quaternions"
+#+ * PoseBone.scale -> scale: float[3] "NO DESCRIPTION"
+#+ * PoseBone.select -> select: boolean "NO DESCRIPTION"
+#+ * PoseBone.tail -> tail: float[3], "(read-only) Location of tail of the channels bone"
+#PoseBone.use_ik_limit_x -> use_ik_limit_x: boolean "Limit movement around the X axis"
+#PoseBone.use_ik_limit_y -> use_ik_limit_y: boolean "Limit movement around the Y axis"
+#PoseBone.use_ik_limit_z -> use_ik_limit_z: boolean "Limit movement around the Z axis"
+#PoseBone.use_ik_linear_control -> use_ik_linear_control: boolean "Apply channel size as IK constraint if stretching is enabled"
+#PoseBone.use_ik_rotation_control -> use_ik_rotation_control: boolean "Apply channel rotation as IK constraint"
+#+ * PoseBoneConstraints.active -> active: pointer "Active PoseChannel constraint"
+#+ * Property.description -> description: string, "(read-only) Description of the property for tooltips"
+#+ * Property.identifier -> identifier: string, "(read-only) Unique name used in the code and scripting"
+#+ * Property.is_never_none -> is_never_none: boolean, "(read-only) True when this value cant be set to None"
+#Property.is_output -> is_output: boolean, "(read-only) True when this property is an output value from an RNA function"
+#+ * Property.is_readonly -> is_readonly: boolean, "(read-only) Property is editable through RNA"
+#Property.is_registered -> is_registered: boolean, "(read-only) Property is registered as part of type registration"
+#Property.is_registered_optional -> is_registered_optional: boolean, "(read-only) Property is optionally registered as part of type registration"
+#+ * Property.is_required -> is_required: boolean, "(read-only) False when this property is an optional argument in an RNA function"
+#+ * Property.name -> name: string, "(read-only) Human readable name"
+#+ * Property.srna -> srna: pointer, "(read-only) Struct definition used for properties assigned to this item"
+#+ * Property.subtype -> subtype: enum, "(read-only) Semantic interpretation of the property"
+#+ * Property.type -> type: enum, "(read-only) Data type of the property"
+#+ * Property.unit -> unit: enum, "(read-only) Type of units for this property"
+#+ * Property|BooleanProperty.array_length -> array_length: int, "(read-only) Maximum length of the array, 0 means unlimited"
+#+ * Property|BooleanProperty.default -> default: boolean, "(read-only) Default value for this number"
+#+ * Property|BooleanProperty.default_array -> default_array: boolean[3], "(read-only) Default value for this array"
+#+ * Property|CollectionProperty.fixed_type -> fixed_type: pointer, "(read-only) Fixed pointer type, empty if variable type"
+#+ * Property|EnumProperty.default -> default: enum, "(read-only) Default value for this enum"
+#+ * Property|EnumProperty.items -> items: collection, "(read-only) Possible values for the property"
+#+ * Property|FloatProperty.array_length -> array_length: int, "(read-only) Maximum length of the array, 0 means unlimited"
+#+ * Property|FloatProperty.default -> default: float, "(read-only) Default value for this number"
+#+ * Property|FloatProperty.default_array -> default_array: float[3], "(read-only) Default value for this array"
+#+ * Property|FloatProperty.hard_max -> hard_max: float, "(read-only) Maximum value used by buttons"
+#+ * Property|FloatProperty.hard_min -> hard_min: float, "(read-only) Minimum value used by buttons"
+#+ * Property|FloatProperty.precision -> precision: int, "(read-only) Number of digits after the dot used by buttons"
+#+ * Property|FloatProperty.soft_max -> soft_max: float, "(read-only) Maximum value used by buttons"
+#+ * Property|FloatProperty.soft_min -> soft_min: float, "(read-only) Minimum value used by buttons"
+#+ * Property|FloatProperty.step -> step: float, "(read-only) Step size used by number buttons, for floats 1/100th of the step size"
+#+ * Property|IntProperty.array_length -> array_length: int, "(read-only) Maximum length of the array, 0 means unlimited"
+#+ * Property|IntProperty.default -> default: int, "(read-only) Default value for this number"
+#+ * Property|IntProperty.default_array -> default_array: int[3], "(read-only) Default value for this array"
+#+ * Property|IntProperty.hard_max -> hard_max: int, "(read-only) Maximum value used by buttons"
+#+ * Property|IntProperty.hard_min -> hard_min: int, "(read-only) Minimum value used by buttons"
+#+ * Property|IntProperty.soft_max -> soft_max: int, "(read-only) Maximum value used by buttons"
+#+ * Property|IntProperty.soft_min -> soft_min: int, "(read-only) Minimum value used by buttons"
+#+ * Property|IntProperty.step -> step: int, "(read-only) Step size used by number buttons, for floats 1/100th of the step size"
+#+ * Property|PointerProperty.fixed_type -> fixed_type: pointer, "(read-only) Fixed pointer type, empty if variable type"
+#+ * Property|StringProperty.default -> default: string, "(read-only) string default value"
+#Property|StringProperty.length_max -> length_max: int, "(read-only) Maximum length of the string, 0 means unlimited"
+#+ * RGBANodeSocket.default_value -> default_value: float[4] "Default value of the socket when no link is attached"
+#+ * RGBANodeSocket.name -> name: string, "(read-only) Socket name"
+#+ * Region.height -> height: int, "(read-only) Region height"
+#+ * Region.id -> id: int, "(read-only) Unique ID for this region"
+#+ * Region.type -> type: enum, "(read-only) Type of this region"
+#+ * Region.width -> width: int, "(read-only) Region width"
+#+ * RegionView3D.lock_rotation -> lock_rotation: boolean "Lock view rotation in side views"
+#+ * RegionView3D.perspective_matrix -> perspective_matrix: float[16], "(read-only) Current perspective matrix of the 3D region"
+#RegionView3D.show_sync_view -> show_sync_view: boolean "Sync view position between side views"
+#RegionView3D.use_box_clip -> use_box_clip: boolean "Clip objects based on whats visible in other side views"
+#+ * RegionView3D.view_distance -> view_distance: float "Distance to the view location"
+#+ * RegionView3D.view_location -> view_location: float[3] "View pivot location"
+#+ * RegionView3D.view_matrix -> view_matrix: float[16], "(read-only) Current view matrix of the 3D region"
+#+ * RegionView3D.view_perspective -> view_perspective: enum "View Perspective"
+#RegionView3D.view_rotate_method -> view_rotate_method: float[4] "Rotation in quaternions (keep normalized)"
+#+ * RenderEngine.bl_idname -> bl_idname: string "NO DESCRIPTION"
+#+ * RenderEngine.bl_label -> bl_label: string "NO DESCRIPTION"
+#RenderEngine.bl_use_postprocess -> bl_use_postprocess: boolean "NO DESCRIPTION"
+#RenderEngine.bl_use_preview -> bl_use_preview: boolean "NO DESCRIPTION"
+#RenderLayer.exclude_ambient_occlusion -> exclude_ambient_occlusion: boolean, "(read-only) Exclude AO pass from combined"
+#RenderLayer.exclude_emit -> exclude_emit: boolean, "(read-only) Exclude emission pass from combined"
+#RenderLayer.exclude_environment -> exclude_environment: boolean, "(read-only) Exclude environment pass from combined"
+#RenderLayer.exclude_indirect -> exclude_indirect: boolean, "(read-only) Exclude indirect pass from combined"
+#RenderLayer.exclude_reflection -> exclude_reflection: boolean, "(read-only) Exclude raytraced reflection pass from combined"
+#RenderLayer.exclude_refraction -> exclude_refraction: boolean, "(read-only) Exclude raytraced refraction pass from combined"
+#RenderLayer.exclude_shadow -> exclude_shadow: boolean, "(read-only) Exclude shadow pass from combined"
+#RenderLayer.exclude_specular -> exclude_specular: boolean, "(read-only) Exclude specular pass from combined"
+#RenderLayer.invert_zmask -> invert_zmask: boolean, "(read-only) For Zmask, only render what is behind solid z values instead of in front"
+#RenderLayer.layers -> layers: boolean[20], "(read-only) Scene layers included in this render layer"
+#RenderLayer.layers_zmask -> layers_zmask: boolean[20], "(read-only) Zmask scene layers"
+#+ * RenderLayer.light_override -> light_override: pointer, "(read-only) Group to override all other lights in this render layer"
+#+ * RenderLayer.material_override -> material_override: pointer, "(read-only) Material to override all other materials in this render layer"
+#+ * RenderLayer.name -> name: string, "(read-only) Render layer name"
+#+ * RenderLayer.passes -> passes: collection, "(read-only)"
+#+ * RenderLayer.rect -> rect: float "NO DESCRIPTION"
+#+ * RenderLayer.use -> use: boolean, "(read-only) Disable or enable the render layer"
+#RenderLayer.use_all_z -> use_all_z: boolean, "(read-only) Fill in Z values for solid faces in invisible layers, for masking"
+#RenderLayer.use_edge_enhance -> use_edge_enhance: boolean, "(read-only) Render Edge-enhance in this Layer (only works for Solid faces)"
+#RenderLayer.use_halo -> use_halo: boolean, "(read-only) Render Halos in this Layer (on top of Solid)"
+#RenderLayer.use_pass_ambient_occlusion -> use_pass_ambient_occlusion: boolean, "(read-only) Deliver AO pass"
+#RenderLayer.use_pass_color -> use_pass_color: boolean, "(read-only) Deliver shade-less color pass"
+#RenderLayer.use_pass_combined -> use_pass_combined: boolean, "(read-only) Deliver full combined RGBA buffer"
+#RenderLayer.use_pass_diffuse -> use_pass_diffuse: boolean, "(read-only) Deliver diffuse pass"
+#RenderLayer.use_pass_emit -> use_pass_emit: boolean, "(read-only) Deliver emission pass"
+#RenderLayer.use_pass_environment -> use_pass_environment: boolean, "(read-only) Deliver environment lighting pass"
+#RenderLayer.use_pass_indirect -> use_pass_indirect: boolean, "(read-only) Deliver indirect lighting pass"
+#RenderLayer.use_pass_mist -> use_pass_mist: boolean, "(read-only) Deliver mist factor pass (0.0-1.0)"
+#RenderLayer.use_pass_normal -> use_pass_normal: boolean, "(read-only) Deliver normal pass"
+#RenderLayer.use_pass_object_index -> use_pass_object_index: boolean, "(read-only) Deliver object index pass"
+#RenderLayer.use_pass_reflection -> use_pass_reflection: boolean, "(read-only) Deliver raytraced reflection pass"
+#RenderLayer.use_pass_refraction -> use_pass_refraction: boolean, "(read-only) Deliver raytraced refraction pass"
+#RenderLayer.use_pass_shadow -> use_pass_shadow: boolean, "(read-only) Deliver shadow pass"
+#RenderLayer.use_pass_specular -> use_pass_specular: boolean, "(read-only) Deliver specular pass"
+#RenderLayer.use_pass_uv -> use_pass_uv: boolean, "(read-only) Deliver texture UV pass"
+#RenderLayer.use_pass_vector -> use_pass_vector: boolean, "(read-only) Deliver speed vector pass"
+#RenderLayer.use_pass_z -> use_pass_z: boolean, "(read-only) Deliver Z values pass"
+#RenderLayer.use_sky -> use_sky: boolean, "(read-only) Render Sky in this Layer"
+#RenderLayer.use_solid -> use_solid: boolean, "(read-only) Render Solid faces in this Layer"
+#RenderLayer.use_strand -> use_strand: boolean, "(read-only) Render Strands in this Layer"
+#RenderLayer.use_zmask -> use_zmask: boolean, "(read-only) Only render whats in front of the solid z values"
+#RenderLayer.use_ztransp -> use_ztransp: boolean, "(read-only) Render Z-Transparent faces in this Layer (On top of Solid and Halos)"
+#+ * RenderPass.channel_id -> channel_id: string, "(read-only)"
+#+ * RenderPass.channels -> channels: int, "(read-only)"
+#+ * RenderPass.name -> name: string, "(read-only)"
+#+ * RenderPass.rect -> rect: float "NO DESCRIPTION"
+#+ * RenderPass.type -> type: enum, "(read-only)"
+#+ * RenderResult.layers -> layers: collection, "(read-only)"
+#+ * RenderResult.resolution_x -> resolution_x: int, "(read-only)"
+#+ * RenderResult.resolution_y -> resolution_y: int, "(read-only)"
+#+ * RenderSettings.active_layer_index -> active_layer_index: int "Active index in render layer array"
+#+ * RenderSettings.alpha_mode -> alpha_mode: enum "Representation of alpha information in the RGBA pixels"
+#+ * RenderSettings.antialiasing_samples -> antialiasing_samples: enum "Amount of anti-aliasing samples per pixel"
+#+ * RenderSettings.bake_aa_mode -> bake_aa_mode: enum "NO DESCRIPTION"
+#+ * RenderSettings.bake_bias -> bake_bias: float "Bias towards faces further away from the object (in blender units)"
+#+ * RenderSettings.bake_distance -> bake_distance: float "Maximum distance from active object to other object (in blender units"
+#+ * RenderSettings.bake_margin -> bake_margin: int "Amount of pixels to extend the baked result with, as post process filter"
+#+ * RenderSettings.bake_normal_space -> bake_normal_space: enum "Choose normal space for baking"
+#+ * RenderSettings.bake_quad_split -> bake_quad_split: enum "Choose the method used to split a quad into 2 triangles for baking"
+#+ * RenderSettings.bake_type -> bake_type: enum "Choose shading information to bake into the image"
+#+ * RenderSettings.border_max_x -> border_max_x: float "Sets maximum X value for the render border"
+#+ * RenderSettings.border_max_y -> border_max_y: float "Sets maximum Y value for the render border"
+#+ * RenderSettings.border_min_x -> border_min_x: float "Sets minimum X value to for the render border"
+#+ * RenderSettings.border_min_y -> border_min_y: float "Sets minimum Y value for the render border"
+#+ * RenderSettings.cineon_black -> cineon_black: int "Log conversion reference blackpoint"
+#+ * RenderSettings.cineon_gamma -> cineon_gamma: float "Log conversion gamma"
+#+ * RenderSettings.cineon_white -> cineon_white: int "Log conversion reference whitepoint"
+#+ * RenderSettings.color_mode -> color_mode: enum "Choose BW for saving greyscale images, RGB for saving red, green and blue channels, AND RGBA for saving red, green, blue + alpha channels"
+#+ * RenderSettings.display_mode -> display_mode: enum "Select where rendered images will be displayed"
+#+ * RenderSettings.dither_intensity -> dither_intensity: float "Amount of dithering noise added to the rendered image to break up banding"
+#+ * RenderSettings.edge_color -> edge_color: float[3] "NO DESCRIPTION"
+#+ * RenderSettings.edge_threshold -> edge_threshold: int "Threshold for drawing outlines on geometry edges"
+#+ * RenderSettings.engine -> engine: enum "Engine to use for rendering"
+#+ * RenderSettings.field_order -> field_order: enum "Order of video fields. Select which lines get rendered first, to create smooth motion for TV output"
+#+ * RenderSettings.file_extension -> file_extension: string, "(read-only) The file extension used for saving renders"
+#+ * RenderSettings.file_format -> file_format: enum "File format to save the rendered images as"
+#+ * RenderSettings.file_quality -> file_quality: int "Quality of JPEG images, AVI Jpeg and SGI movies, Compression for PNGs"
+#RenderSettings.filepath -> filepath: string "Directory/name to save animations, # characters defines the position and length of frame numbers"
+#+ * RenderSettings.filter_size -> filter_size: float "Pixel width over which the reconstruction filter combines samples"
+#+ * RenderSettings.fps -> fps: int "Framerate, expressed in frames per second"
+#+ * RenderSettings.fps_base -> fps_base: float "Framerate base"
+#RenderSettings.has_multiple_engines -> has_multiple_engines: boolean, "(read-only) More than one rendering engine is available"
+#+ * RenderSettings.is_movie_format -> is_movie_format: boolean, "(read-only) When true the format is a movie"
+#+ * RenderSettings.layers -> layers: collection, "(read-only)"
+#+ * RenderSettings.motion_blur_samples -> motion_blur_samples: int "Number of scene samples to take with motion blur"
+#+ * RenderSettings.motion_blur_shutter -> motion_blur_shutter: float "Time taken in frames between shutter open and close"
+#+ * RenderSettings.octree_resolution -> octree_resolution: enum "Resolution of raytrace accelerator. Use higher resolutions for larger scenes"
+#+ * RenderSettings.parts_x -> parts_x: int "Number of horizontal tiles to use while rendering"
+#+ * RenderSettings.parts_y -> parts_y: int "Number of vertical tiles to use while rendering"
+#+ * RenderSettings.pixel_aspect_x -> pixel_aspect_x: float "Horizontal aspect ratio - for anamorphic or non-square pixel output"
+#+ * RenderSettings.pixel_aspect_y -> pixel_aspect_y: float "Vertical aspect ratio - for anamorphic or non-square pixel output"
+#RenderSettings.pixel_filter_type -> pixel_filter_type: enum "Reconstruction filter used for combining anti-aliasing samples"
+#RenderSettings.raytrace_method -> raytrace_method: enum "Type of raytrace accelerator structure"
+#+ * RenderSettings.resolution_percentage -> resolution_percentage: int "Percentage scale for render resolution"
+#+ * RenderSettings.resolution_x -> resolution_x: int "Number of horizontal pixels in the rendered image"
+#+ * RenderSettings.resolution_y -> resolution_y: int "Number of vertical pixels in the rendered image"
+#+ * RenderSettings.sequencer_gl_preview -> sequencer_gl_preview: enum "Method to draw in the sequencer view"
+#+ * RenderSettings.sequencer_gl_render -> sequencer_gl_render: enum "Method to draw in the sequencer view"
+#+ * RenderSettings.simplify_ao_sss -> simplify_ao_sss: float "Global approximate AA and SSS quality factor"
+#+ * RenderSettings.simplify_child_particles -> simplify_child_particles: float "Global child particles percentage"
+#+ * RenderSettings.simplify_shadow_samples -> simplify_shadow_samples: int "Global maximum shadow samples"
+#+ * RenderSettings.simplify_subdivision -> simplify_subdivision: int "Global maximum subdivision level"
+#+ * RenderSettings.stamp_background -> stamp_background: float[4] "Color to use behind stamp text"
+#+ * RenderSettings.stamp_font_size -> stamp_font_size: int "Size of the font used when rendering stamp text"
+#+ * RenderSettings.stamp_foreground -> stamp_foreground: float[4] "Color to use for stamp text"
+#+ * RenderSettings.stamp_note_text -> stamp_note_text: string "Custom text to appear in the stamp note"
+#+ * RenderSettings.threads -> threads: int "Number of CPU threads to use simultaneously while rendering (for multi-core/CPU systems)"
+#+ * RenderSettings.threads_mode -> threads_mode: enum "Determine the amount of render threads used"
+#RenderSettings.use_antialiasing -> use_antialiasing: boolean "Render and combine multiple samples per pixel to prevent jagged edges"
+#RenderSettings.use_backbuf -> use_backbuf: boolean "Render backbuffer image"
+#RenderSettings.use_bake_antialiasing -> use_bake_antialiasing: boolean "Enables Anti-aliasing"
+#RenderSettings.use_bake_clear -> use_bake_clear: boolean "Clear Images before baking"
+#RenderSettings.use_bake_normalize -> use_bake_normalize: boolean "With displacement normalize to the distance, with ambient occlusion normalize without using material settings"
+#RenderSettings.use_bake_selected_to_active -> use_bake_selected_to_active: boolean "Bake shading on the surface of selected objects to the active object"
+#+ * RenderSettings.use_border -> use_border: boolean "Render a user-defined border region, within the frame size. Note, this disables save_buffers and full_sample"
+#RenderSettings.use_cineon_log -> use_cineon_log: boolean "Convert to logarithmic color space"
+#RenderSettings.use_color_management -> use_color_management: boolean "Use linear workflow - gamma corrected imaging pipeline"
+#+ * RenderSettings.use_compositing -> use_compositing: boolean "Process the render result through the compositing pipeline, if compositing nodes are enabled"
+#RenderSettings.use_crop_to_border -> use_crop_to_border: boolean "Crop the rendered frame to the defined border size"
+#RenderSettings.use_edge_enhance -> use_edge_enhance: boolean "Create a toon outline around the edges of geometry"
+#+ * RenderSettings.use_envmaps -> use_envmaps: boolean "Calculate environment maps while rendering"
+#RenderSettings.use_fields -> use_fields: boolean "Render image to two fields per frame, for interlaced TV output"
+#RenderSettings.use_fields_still -> use_fields_still: boolean "Disable the time difference between fields"
+#+ * RenderSettings.use_file_extension -> use_file_extension: boolean "Add the file format extensions to the rendered file name (eg: filename + .jpg)"
+#RenderSettings.use_free_image_textures -> use_free_image_textures: boolean "Free all image texture from memory after render, to save memory before compositing"
+#RenderSettings.use_free_unused_nodes -> use_free_unused_nodes: boolean "Free Nodes that are not used while compositing, to save memory"
+#RenderSettings.use_full_sample -> use_full_sample: boolean "Save for every anti-aliasing sample the entire RenderLayer results. This solves anti-aliasing issues with compositing"
+#+ * RenderSettings.use_game_engine -> use_game_engine: boolean, "(read-only) Current rendering engine is a game engine"
+#+ * RenderSettings.use_instances -> use_instances: boolean "Instance support leads to effective memory reduction when using duplicates"
+#+ * RenderSettings.use_local_coords -> use_local_coords: boolean "Vertex coordinates are stored localy on each primitive. Increases memory usage, but may have impact on speed"
+#RenderSettings.use_motion_blur -> use_motion_blur: boolean "Use multi-sampled 3D scene motion blur"
+#+ * RenderSettings.use_overwrite -> use_overwrite: boolean "Overwrite existing files while rendering"
+#+ * RenderSettings.use_placeholder -> use_placeholder: boolean "Create empty placeholder files while rendering frames (similar to Unix touch)"
+#+ * RenderSettings.use_radiosity -> use_radiosity: boolean "Calculate radiosity in a pre-process before rendering"
+#RenderSettings.use_raytrace -> use_raytrace: boolean "Pre-calculate the raytrace accelerator and render raytracing effects"
+#RenderSettings.use_save_buffers -> use_save_buffers: boolean "Save tiles for all RenderLayers and SceneNodes to files in the temp directory (saves memory, required for Full Sample)"
+#+ * RenderSettings.use_sequencer -> use_sequencer: boolean "Process the render (and composited) result through the video sequence editor pipeline, if sequencer strips exist"
+#+ * RenderSettings.use_sequencer_gl_preview -> use_sequencer_gl_preview: boolean "NO DESCRIPTION"
+#+ * RenderSettings.use_sequencer_gl_render -> use_sequencer_gl_render: boolean "NO DESCRIPTION"
+#+ * RenderSettings.use_shadows -> use_shadows: boolean "Calculate shadows while rendering"
+#+ * RenderSettings.use_simplify -> use_simplify: boolean "Enable simplification of scene for quicker preview renders"
+#RenderSettings.use_simplify_triangulate -> use_simplify_triangulate: boolean "Disables non-planer quads being triangulated"
+#RenderSettings.use_single_layer -> use_single_layer: boolean "Only render the active layer"
+#+ * RenderSettings.use_sss -> use_sss: boolean "Calculate sub-surface scattering in materials rendering"
+#RenderSettings.use_stamp -> use_stamp: boolean "Render the stamp info text in the rendered image"
+#RenderSettings.use_stamp_camera -> use_stamp_camera: boolean "Include the name of the active camera in image metadata"
+#RenderSettings.use_stamp_date -> use_stamp_date: boolean "Include the current date in image metadata"
+#RenderSettings.use_stamp_filename -> use_stamp_filename: boolean "Include the filename of the .blend file in image metadata"
+#RenderSettings.use_stamp_frame -> use_stamp_frame: boolean "Include the frame number in image metadata"
+#RenderSettings.use_stamp_marker -> use_stamp_marker: boolean "Include the name of the last marker in image metadata"
+#RenderSettings.use_stamp_note -> use_stamp_note: boolean "Include a custom note in image metadata"
+#RenderSettings.use_stamp_render_time -> use_stamp_render_time: boolean "Include the render time in the stamp image"
+#RenderSettings.use_stamp_scene -> use_stamp_scene: boolean "Include the name of the active scene in image metadata"
+#RenderSettings.use_stamp_sequencer_strip -> use_stamp_sequencer_strip: boolean "Include the name of the foreground sequence strip in image metadata"
+#RenderSettings.use_stamp_time -> use_stamp_time: boolean "Include the render frame as HH:MM:SS.FF in image metadata"
+#+ * RenderSettings.use_textures -> use_textures: boolean "Use textures to affect material properties"
+#RenderSettings.use_tiff_16bit -> use_tiff_16bit: boolean "Save TIFF with 16 bits per channel"
+#+ * SPHFluidSettings.buoyancy -> buoyancy: float "NO DESCRIPTION"
+#+ * SPHFluidSettings.fluid_radius -> fluid_radius: float "Fluid interaction Radius"
+#+ * SPHFluidSettings.rest_density -> rest_density: float "Density"
+#+ * SPHFluidSettings.rest_length -> rest_length: float "The Spring Rest Length (factor of interaction radius)"
+#SPHFluidSettings.spring_force -> spring_force: float "Spring force constant"
+#SPHFluidSettings.stiffness -> stiffness: float "Constant K - Stiffness"
+#SPHFluidSettings.stiffness_near -> stiffness_near: float "Repulsion factor: stiffness_knear"
+#+ * SPHFluidSettings.viscosity_beta -> viscosity_beta: float "Square viscosity factor"
+#+ * SPHFluidSettings.viscosity_omega -> viscosity_omega: float "Linear viscosity"
+#+ * SceneBases.active -> active: pointer "Active object base in the scene"
+#+ * SceneGameData.activity_culling_box_radius -> activity_culling_box_radius: float "Radius of the activity bubble, in Manhattan length. Objects outside the box are activity-culled"
+#+ * SceneGameData.depth -> depth: int "Displays bit depth of full screen display"
+#+ * SceneGameData.dome_angle -> dome_angle: int "Field of View of the Dome - it only works in mode Fisheye and Truncated"
+#+ * SceneGameData.dome_buffer_resolution -> dome_buffer_resolution: float "Buffer Resolution - decrease it to increase speed"
+#+ * SceneGameData.dome_mode -> dome_mode: enum "Dome physical configurations"
+#+ * SceneGameData.dome_tesselation -> dome_tesselation: int "Tessellation level - check the generated mesh in wireframe mode"
+#+ * SceneGameData.dome_text -> dome_text: pointer "Custom Warp Mesh data file"
+#+ * SceneGameData.dome_tilt -> dome_tilt: int "Camera rotation in horizontal axis"
+#+ * SceneGameData.fps -> fps: int "The nominal number of game frames per second. Physics fixed timestep = 1/fps, independently of actual frame rate"
+#SceneGameData.frame_color -> frame_color: float[3] "Set colour of the bars"
+#SceneGameData.frame_type -> frame_type: enum "Select the type of Framing you want"
+#+ * SceneGameData.frequency -> frequency: int "Displays clock frequency of fullscreen display"
+#+ * SceneGameData.logic_step_max -> logic_step_max: int "Sets the maximum number of logic frame per game frame if graphics slows down the game, higher value allows better synchronization with physics"
+#+ * SceneGameData.material_mode -> material_mode: enum "Material mode to use for rendering"
+#+ * SceneGameData.occlusion_culling_resolution -> occlusion_culling_resolution: float "The size of the occlusion buffer in pixel, use higher value for better precision (slower)"
+#+ * SceneGameData.physics_engine -> physics_engine: enum "Physics engine used for physics simulation in the game engine"
+#+ * SceneGameData.physics_gravity -> physics_gravity: float "Gravitational constant used for physics simulation in the game engine"
+#+ * SceneGameData.physics_step_max -> physics_step_max: int "Sets the maximum number of physics step per game frame if graphics slows down the game, higher value allows physics to keep up with realtime"
+#+ * SceneGameData.physics_step_sub -> physics_step_sub: int "Sets the number of simulation substep per physic timestep, higher value give better physics precision"
+#+ * SceneGameData.resolution_x -> resolution_x: int "Number of horizontal pixels in the screen"
+#+ * SceneGameData.resolution_y -> resolution_y: int "Number of vertical pixels in the screen"
+#+ * SceneGameData.show_debug_properties -> show_debug_properties: boolean "Show properties marked for debugging while the game runs"
+#+ * SceneGameData.show_framerate_profile -> show_framerate_profile: boolean "Show framerate and profiling information while the game runs"
+#SceneGameData.show_fullscreen -> show_fullscreen: boolean "Starts player in a new fullscreen display"
+#+ * SceneGameData.show_physics_visualization -> show_physics_visualization: boolean "Show a visualization of physics bounds and interactions"
+#+ * SceneGameData.stereo -> stereo: enum "NO DESCRIPTION"
+#SceneGameData.stereo_eye_separation -> stereo_eye_separation: float "Set the distance between the eyes - the camera focal length/30 should be fine"
+#+ * SceneGameData.stereo_mode -> stereo_mode: enum "Stereographic techniques"
+#SceneGameData.use_activity_culling -> use_activity_culling: boolean "Activity culling is enabled"
+#+ * SceneGameData.use_animation_record -> use_animation_record: boolean "Record animation to fcurves"
+#SceneGameData.use_auto_start -> use_auto_start: boolean "Automatically start game at load time"
+#+ * SceneGameData.use_deprecation_warnings -> use_deprecation_warnings: boolean "Print warnings when using deprecated features in the python API"
+#+ * SceneGameData.use_display_lists -> use_display_lists: boolean "Use display lists to speed up rendering by keeping geometry on the GPU"
+#+ * SceneGameData.use_frame_rate -> use_frame_rate: boolean "Respect the frame rate rather than rendering as many frames as possible"
+#SceneGameData.use_glsl_extra_textures -> use_glsl_extra_textures: boolean "Use extra textures like normal or specular maps for GLSL rendering"
+#SceneGameData.use_glsl_lights -> use_glsl_lights: boolean "Use lights for GLSL rendering"
+#SceneGameData.use_glsl_nodes -> use_glsl_nodes: boolean "Use nodes for GLSL rendering"
+#SceneGameData.use_glsl_ramps -> use_glsl_ramps: boolean "Use ramps for GLSL rendering"
+#SceneGameData.use_glsl_shaders -> use_glsl_shaders: boolean "Use shaders for GLSL rendering"
+#SceneGameData.use_glsl_shadows -> use_glsl_shadows: boolean "Use shadows for GLSL rendering"
+#+ * SceneGameData.use_occlusion_culling -> use_occlusion_culling: boolean "Use optimized Bullet DBVT tree for view frustum and occlusion culling"
+#+ * SceneObjects.active -> active: pointer "Active object for this scene"
+#SceneRenderLayer.exclude_ambient_occlusion -> exclude_ambient_occlusion: boolean "Exclude AO pass from combined"
+#SceneRenderLayer.exclude_emit -> exclude_emit: boolean "Exclude emission pass from combined"
+#SceneRenderLayer.exclude_environment -> exclude_environment: boolean "Exclude environment pass from combined"
+#SceneRenderLayer.exclude_indirect -> exclude_indirect: boolean "Exclude indirect pass from combined"
+#SceneRenderLayer.exclude_reflection -> exclude_reflection: boolean "Exclude raytraced reflection pass from combined"
+#SceneRenderLayer.exclude_refraction -> exclude_refraction: boolean "Exclude raytraced refraction pass from combined"
+#SceneRenderLayer.exclude_shadow -> exclude_shadow: boolean "Exclude shadow pass from combined"
+#SceneRenderLayer.exclude_specular -> exclude_specular: boolean "Exclude specular pass from combined"
+#SceneRenderLayer.invert_zmask -> invert_zmask: boolean "For Zmask, only render what is behind solid z values instead of in front"
+#SceneRenderLayer.layers -> layers: boolean[20] "Scene layers included in this render layer"
+#SceneRenderLayer.layers_zmask -> layers_zmask: boolean[20] "Zmask scene layers"
+#+ * SceneRenderLayer.light_override -> light_override: pointer "Group to override all other lights in this render layer"
+#+ * SceneRenderLayer.material_override -> material_override: pointer "Material to override all other materials in this render layer"
+#+ * SceneRenderLayer.name -> name: string "Render layer name"
+#+ * SceneRenderLayer.use -> use: boolean "Disable or enable the render layer"
+#SceneRenderLayer.use_all_z -> use_all_z: boolean "Fill in Z values for solid faces in invisible layers, for masking"
+#SceneRenderLayer.use_edge_enhance -> use_edge_enhance: boolean "Render Edge-enhance in this Layer (only works for Solid faces)"
+#SceneRenderLayer.use_halo -> use_halo: boolean "Render Halos in this Layer (on top of Solid)"
+#SceneRenderLayer.use_pass_ambient_occlusion -> use_pass_ambient_occlusion: boolean "Deliver AO pass"
+#SceneRenderLayer.use_pass_color -> use_pass_color: boolean "Deliver shade-less color pass"
+#SceneRenderLayer.use_pass_combined -> use_pass_combined: boolean "Deliver full combined RGBA buffer"
+#SceneRenderLayer.use_pass_diffuse -> use_pass_diffuse: boolean "Deliver diffuse pass"
+#SceneRenderLayer.use_pass_emit -> use_pass_emit: boolean "Deliver emission pass"
+#SceneRenderLayer.use_pass_environment -> use_pass_environment: boolean "Deliver environment lighting pass"
+#SceneRenderLayer.use_pass_indirect -> use_pass_indirect: boolean "Deliver indirect lighting pass"
+#SceneRenderLayer.use_pass_mist -> use_pass_mist: boolean "Deliver mist factor pass (0.0-1.0)"
+#SceneRenderLayer.use_pass_normal -> use_pass_normal: boolean "Deliver normal pass"
+#SceneRenderLayer.use_pass_object_index -> use_pass_object_index: boolean "Deliver object index pass"
+#SceneRenderLayer.use_pass_reflection -> use_pass_reflection: boolean "Deliver raytraced reflection pass"
+#SceneRenderLayer.use_pass_refraction -> use_pass_refraction: boolean "Deliver raytraced refraction pass"
+#SceneRenderLayer.use_pass_shadow -> use_pass_shadow: boolean "Deliver shadow pass"
+#SceneRenderLayer.use_pass_specular -> use_pass_specular: boolean "Deliver specular pass"
+#SceneRenderLayer.use_pass_uv -> use_pass_uv: boolean "Deliver texture UV pass"
+#SceneRenderLayer.use_pass_vector -> use_pass_vector: boolean "Deliver speed vector pass"
+#SceneRenderLayer.use_pass_z -> use_pass_z: boolean "Deliver Z values pass"
+#SceneRenderLayer.use_sky -> use_sky: boolean "Render Sky in this Layer"
+#SceneRenderLayer.use_solid -> use_solid: boolean "Render Solid faces in this Layer"
+#SceneRenderLayer.use_strand -> use_strand: boolean "Render Strands in this Layer"
+#SceneRenderLayer.use_zmask -> use_zmask: boolean "Only render whats in front of the solid z values"
+#SceneRenderLayer.use_ztransp -> use_ztransp: boolean "Render Z-Transparent faces in this Layer (On top of Solid and Halos)"
+#+ * Scopes.accuracy -> accuracy: float "Proportion of original image source pixel lines to sample"
+#+ * Scopes.histogram -> histogram: pointer, "(read-only) Histogram for viewing image statistics"
+#+ * Scopes.use_full_resolution -> use_full_resolution: boolean "Sample every pixel of the image"
+#+ * Scopes.vectorscope_alpha -> vectorscope_alpha: float "Opacity of the points"
+#+ * Scopes.waveform_alpha -> waveform_alpha: float "Opacity of the points"
+#+ * Scopes.waveform_mode -> waveform_mode: enum "NO DESCRIPTION"
+#+ * Sensor.frequency -> frequency: int "Delay between repeated pulses(in logic tics, 0=no delay)"
+#+ * Sensor.invert -> invert: boolean "Invert the level(output) of this sensor"
+#+ * Sensor.name -> name: string "Sensor name"
+#Sensor.pin -> pin: boolean "Display when not linked to a visible states controller"
+#Sensor.show_expanded -> show_expanded: boolean "Set sensor expanded in the user interface"
+#+ * Sensor.type -> type: enum "NO DESCRIPTION"
+#Sensor.use_level -> use_level: boolean "Level detector, trigger controllers of new states(only applicable upon logic state transition)"
+#Sensor.use_pulse_false_level -> use_pulse_false_level: boolean "Activate FALSE level triggering (pulse mode)"
+#Sensor.use_pulse_true_level -> use_pulse_true_level: boolean "Activate TRUE level triggering (pulse mode)"
+#Sensor.use_tap -> use_tap: boolean "Trigger controllers only for an instant, even while the sensor remains true"
+#+ * Sensor|ActuatorSensor.actuator -> actuator: string "Actuator name, actuator active state modifications will be detected"
+#+ * Sensor|ArmatureSensor.bone -> bone: string "Identify the bone to check value from"
+#+ * Sensor|ArmatureSensor.constraint -> constraint: string "Identify the bone constraint to check value from"
+#+ * Sensor|ArmatureSensor.test_type -> test_type: enum "Type of value and test"
+#+ * Sensor|ArmatureSensor.value -> value: float "Specify value to be used in comparison"
+#+ * Sensor|CollisionSensor.material -> material: string "Only look for Objects with this material"
+#+ * Sensor|CollisionSensor.property -> property: string "Only look for Objects with this property"
+#Sensor|CollisionSensor.use_material -> use_material: boolean "Toggle collision on material or property"
+#Sensor|CollisionSensor.use_pulse -> use_pulse: boolean "Changes to the set of colliding objects generates pulse"
+#+ * Sensor|DelaySensor.delay -> delay: int "Delay in number of logic tics before the positive trigger (default 60 per second)"
+#+ * Sensor|DelaySensor.duration -> duration: int "If >0, delay in number of logic tics before the negative trigger following the positive trigger"
+#Sensor|DelaySensor.use_repeat -> use_repeat: boolean "Toggle repeat option. If selected, the sensor restarts after Delay+Dur logic tics"
+#+ * Sensor|JoystickSensor.axis_direction -> axis_direction: enum "The direction of the axis"
+#+ * Sensor|JoystickSensor.axis_number -> axis_number: int "Specify which axis pair to use, 1 is usually the main direction input"
+#+ * Sensor|JoystickSensor.axis_threshold -> axis_threshold: int "Specify the precision of the axis"
+#+ * Sensor|JoystickSensor.button_number -> button_number: int "Specify which button to use"
+#+ * Sensor|JoystickSensor.event_type -> event_type: enum "The type of event this joystick sensor is triggered on"
+#+ * Sensor|JoystickSensor.hat_direction -> hat_direction: enum "Specify hat direction"
+#+ * Sensor|JoystickSensor.hat_number -> hat_number: int "Specify which hat to use"
+#+ * Sensor|JoystickSensor.joystick_index -> joystick_index: int "Specify which joystick to use"
+#+ * Sensor|JoystickSensor.single_axis_number -> single_axis_number: int "Specify a single axis (verticle/horizontal/other) to detect"
+#Sensor|JoystickSensor.use_all_events -> use_all_events: boolean "Triggered by all events on this joysticks current type (axis/button/hat)"
+#+ * Sensor|KeyboardSensor.key -> key: enum "NO DESCRIPTION"
+#+ * Sensor|KeyboardSensor.log -> log: string "Property that receive the keystrokes in case a string is logged"
+#Sensor|KeyboardSensor.modifier_key_1 -> modifier_key_1: enum "Modifier key code"
+#Sensor|KeyboardSensor.modifier_key_2 -> modifier_key_2: enum "Modifier key code"
+#+ * Sensor|KeyboardSensor.target -> target: string "Property that indicates whether to log keystrokes as a string"
+#Sensor|KeyboardSensor.use_all_keys -> use_all_keys: boolean "Trigger this sensor on any keystroke"
+#+ * Sensor|MessageSensor.subject -> subject: string "Optional subject filter: only accept messages with this subject, or empty for all"
+#+ * Sensor|MouseSensor.mouse_event -> mouse_event: enum "Specify the type of event this mouse sensor should trigger on"
+#+ * Sensor|NearSensor.distance -> distance: float "Trigger distance"
+#+ * Sensor|NearSensor.property -> property: string "Only look for objects with this property"
+#+ * Sensor|NearSensor.reset_distance -> reset_distance: float "NO DESCRIPTION"
+#+ * Sensor|PropertySensor.evaluation_type -> evaluation_type: enum "Type of property evaluation"
+#+ * Sensor|PropertySensor.property -> property: string "NO DESCRIPTION"
+#+ * Sensor|PropertySensor.value -> value: string "Check for this value in types in Equal or Not Equal types"
+#Sensor|PropertySensor.value_max -> value_max: string "Specify maximum value in Interval type"
+#Sensor|PropertySensor.value_min -> value_min: string "Specify minimum value in Interval type"
+#+ * Sensor|RadarSensor.angle -> angle: float "Opening angle of the radar cone"
+#+ * Sensor|RadarSensor.axis -> axis: enum "Specify along which axis the radar cone is cast"
+#+ * Sensor|RadarSensor.distance -> distance: float "Depth of the radar cone"
+#+ * Sensor|RadarSensor.property -> property: string "Only look for Objects with this property"
+#+ * Sensor|RandomSensor.seed -> seed: int "Initial seed of the generator. (Choose 0 for not random)"
+#+ * Sensor|RaySensor.axis -> axis: enum "Specify along which axis the ray is cast"
+#+ * Sensor|RaySensor.material -> material: string "Only look for Objects with this material"
+#+ * Sensor|RaySensor.property -> property: string "Only look for Objects with this property"
+#+ * Sensor|RaySensor.range -> range: float "Sense objects no farther than this distance"
+#+ * Sensor|RaySensor.ray_type -> ray_type: enum "Toggle collision on material or property"
+#Sensor|RaySensor.use_x_ray -> use_x_ray: boolean "Toggle X-Ray option (see through objects that dont have the property)"
+#+ * Sensor|TouchSensor.material -> material: pointer "Only look for objects with this material"
+#Sequence.blend_alpha -> blend_alpha: float "NO DESCRIPTION"
+#Sequence.blend_type -> blend_type: enum "NO DESCRIPTION"
+#+ * Sequence.channel -> channel: int "Y position of the sequence strip"
+#+ * Sequence.effect_fader -> effect_fader: float "NO DESCRIPTION"
+#Sequence.frame_duration -> frame_duration: int, "(read-only) The length of the contents of this strip before the handles are applied"
+#Sequence.frame_final_duration -> frame_final_duration: int "The length of the contents of this strip before the handles are applied"
+#+ * Sequence.frame_final_end -> frame_final_end: int "End frame displayed in the sequence editor after offsets are applied"
+#+ * Sequence.frame_final_start -> frame_final_start: int "Start frame displayed in the sequence editor after offsets are applied, setting this is equivalent to moving the handle, not the actual start frame"
+#+ * Sequence.frame_offset_end -> frame_offset_end: int, "(read-only)"
+#+ * Sequence.frame_offset_start -> frame_offset_start: int, "(read-only)"
+#+ * Sequence.frame_start -> frame_start: int "NO DESCRIPTION"
+#+ * Sequence.frame_still_end -> frame_still_end: int, "(read-only)"
+#+ * Sequence.frame_still_start -> frame_still_start: int, "(read-only)"
+#+ * Sequence.lock -> lock: boolean "Lock strip so that it cant be transformed"
+#+ * Sequence.mute -> mute: boolean "NO DESCRIPTION"
+#+ * Sequence.name -> name: string "NO DESCRIPTION"
+#+ * Sequence.select -> select: boolean "NO DESCRIPTION"
+#+ * Sequence.select_left_handle -> select_left_handle: boolean "NO DESCRIPTION"
+#+ * Sequence.select_right_handle -> select_right_handle: boolean "NO DESCRIPTION"
+#+ * Sequence.speed_fader -> speed_fader: float "NO DESCRIPTION"
+#+ * Sequence.type -> type: enum, "(read-only)"
+#Sequence.use_default_fade -> use_default_fade: boolean "Fade effect using the built-in default (usually make transition as long as effect strip)"
+#+ * SequenceColorBalance.gain -> gain: float[3] "Color balance gain (highlights)"
+#+ * SequenceColorBalance.gamma -> gamma: float[3] "Color balance gamma (midtones)"
+#SequenceColorBalance.invert_gain -> invert_gain: boolean "NO DESCRIPTION"
+#SequenceColorBalance.invert_gamma -> invert_gamma: boolean "NO DESCRIPTION"
+#SequenceColorBalance.invert_lift -> invert_lift: boolean "NO DESCRIPTION"
+#+ * SequenceColorBalance.lift -> lift: float[3] "Color balance lift (shadows)"
+#SequenceCrop.max_x -> max_x: int "NO DESCRIPTION"
+#SequenceCrop.max_y -> max_y: int "NO DESCRIPTION"
+#SequenceCrop.min_x -> min_x: int "NO DESCRIPTION"
+#SequenceCrop.min_y -> min_y: int "NO DESCRIPTION"
+#+ * SequenceEditor.active_strip -> active_strip: pointer "NO DESCRIPTION"
+#+ * SequenceEditor.meta_stack -> meta_stack: collection, "(read-only) Meta strip stack, last is currently edited meta strip"
+#+ * SequenceEditor.overlay_frame -> overlay_frame: int "Sequencers active strip"
+#+ * SequenceEditor.overlay_lock -> overlay_lock: boolean "NO DESCRIPTION"
+#+ * SequenceEditor.sequences -> sequences: collection, "(read-only)"
+#+ * SequenceEditor.sequences_all -> sequences_all: collection, "(read-only)"
+#+ * SequenceEditor.show_overlay -> show_overlay: boolean "Partial overlay ontop of the sequencer"
+#+ * SequenceElement.filename -> filename: string "NO DESCRIPTION"
+#+ * SequenceProxy.directory -> directory: string "Location to store the proxy files"
+#+ * SequenceProxy.filepath -> filepath: string "Location of custom proxy file"
+#+ * SequenceTransform.offset_x -> offset_x: int "NO DESCRIPTION"
+#+ * SequenceTransform.offset_y -> offset_y: int "NO DESCRIPTION"
+#+ * Sequence|EffectSequence.color_balance -> color_balance: pointer, "(read-only)"
+#Sequence|EffectSequence.color_multiply -> color_multiply: float "NO DESCRIPTION"
+#+ * Sequence|EffectSequence.color_saturation -> color_saturation: float "NO DESCRIPTION"
+#+ * Sequence|EffectSequence.crop -> crop: pointer, "(read-only)"
+#+ * Sequence|EffectSequence.proxy -> proxy: pointer, "(read-only)"
+#+ * Sequence|EffectSequence.strobe -> strobe: float "Only display every nth frame"
+#+ * Sequence|EffectSequence.transform -> transform: pointer, "(read-only)"
+#+ * Sequence|EffectSequence.use_color_balance -> use_color_balance: boolean "(3-Way color correction) on input"
+#+ * Sequence|EffectSequence.use_crop -> use_crop: boolean "Crop image before processing"
+#Sequence|EffectSequence.use_deinterlace -> use_deinterlace: boolean "For video movies to remove fields"
+#Sequence|EffectSequence.use_flip_x -> use_flip_x: boolean "Flip on the X axis"
+#Sequence|EffectSequence.use_flip_y -> use_flip_y: boolean "Flip on the Y axis"
+#Sequence|EffectSequence.use_float -> use_float: boolean "Convert input to float data"
+#Sequence|EffectSequence.use_premultiply -> use_premultiply: boolean "Convert RGB from key alpha to premultiplied alpha"
+#+ * Sequence|EffectSequence.use_proxy -> use_proxy: boolean "Use a preview proxy for this strip"
+#Sequence|EffectSequence.use_proxy_custom_directory -> use_proxy_custom_directory: boolean "Use a custom directory to store data"
+#Sequence|EffectSequence.use_proxy_custom_file -> use_proxy_custom_file: boolean "Use a custom file to read proxy data from"
+#Sequence|EffectSequence.use_reverse_frames -> use_reverse_frames: boolean "Reverse frame order"
+#+ * Sequence|EffectSequence.use_translation -> use_translation: boolean "Translate image before processing"
+#+ * Sequence|EffectSequence|ColorSequence.color -> color: float[3] "NO DESCRIPTION"
+#Sequence|EffectSequence|GlowSequence.blur_radius -> blur_radius: float "Radius of glow effect"
+#+ * Sequence|EffectSequence|GlowSequence.boost_factor -> boost_factor: float "Brightness multiplier"
+#+ * Sequence|EffectSequence|GlowSequence.clamp -> clamp: float "rightness limit of intensity"
+#+ * Sequence|EffectSequence|GlowSequence.quality -> quality: int "Accuracy of the blur effect"
+#+ * Sequence|EffectSequence|GlowSequence.threshold -> threshold: float "Minimum intensity to trigger a glow"
+#Sequence|EffectSequence|GlowSequence.use_only_boost -> use_only_boost: boolean "Show the glow buffer only"
+#+ * Sequence|EffectSequence|PluginSequence.filename -> filename: string, "(read-only)"
+#+ * Sequence|EffectSequence|SpeedControlSequence.global_speed -> global_speed: float "NO DESCRIPTION"
+#Sequence|EffectSequence|SpeedControlSequence.use_curve_compress_y -> use_curve_compress_y: boolean "Scale F-Curve value to get the target frame number, F-Curve value runs from 0.0 to 1.0"
+#Sequence|EffectSequence|SpeedControlSequence.use_curve_velocity -> use_curve_velocity: boolean "Interpret the F-Curve value as a velocity instead of a frame number"
+#Sequence|EffectSequence|SpeedControlSequence.use_frame_blend -> use_frame_blend: boolean "Blend two frames into the target for a smoother result"
+#+ * Sequence|EffectSequence|TransformSequence.interpolation -> interpolation: enum "NO DESCRIPTION"
+#+ * Sequence|EffectSequence|TransformSequence.rotation_start -> rotation_start: float "NO DESCRIPTION"
+#+ * Sequence|EffectSequence|TransformSequence.scale_start_x -> scale_start_x: float "NO DESCRIPTION"
+#+ * Sequence|EffectSequence|TransformSequence.scale_start_y -> scale_start_y: float "NO DESCRIPTION"
+#+ * Sequence|EffectSequence|TransformSequence.translate_start_x -> translate_start_x: float "NO DESCRIPTION"
+#+ * Sequence|EffectSequence|TransformSequence.translate_start_y -> translate_start_y: float "NO DESCRIPTION"
+#+ * Sequence|EffectSequence|TransformSequence.translation_unit -> translation_unit: enum "NO DESCRIPTION"
+#Sequence|EffectSequence|TransformSequence.use_uniform_scale -> use_uniform_scale: boolean "Scale uniformly, preserving aspect ratio"
+#+ * Sequence|EffectSequence|WipeSequence.angle -> angle: float "Edge angle"
+#+ * Sequence|EffectSequence|WipeSequence.blur_width -> blur_width: float "Width of the blur edge, in percentage relative to the image size"
+#+ * Sequence|EffectSequence|WipeSequence.direction -> direction: enum "Wipe direction"
+#+ * Sequence|EffectSequence|WipeSequence.transition_type -> transition_type: enum "NO DESCRIPTION"
+#Sequence|ImageSequence.animation_offset_end -> animation_offset_end: int "Animation end offset (trim end)"
+#Sequence|ImageSequence.animation_offset_start -> animation_offset_start: int "Animation start offset (trim start)"
+#+ * Sequence|ImageSequence.color_balance -> color_balance: pointer, "(read-only)"
+#Sequence|ImageSequence.color_multiply -> color_multiply: float "NO DESCRIPTION"
+#+ * Sequence|ImageSequence.color_saturation -> color_saturation: float "NO DESCRIPTION"
+#+ * Sequence|ImageSequence.crop -> crop: pointer, "(read-only)"
+#+ * Sequence|ImageSequence.directory -> directory: string "NO DESCRIPTION"
+#+ * Sequence|ImageSequence.elements -> elements: collection, "(read-only)"
+#+ * Sequence|ImageSequence.proxy -> proxy: pointer, "(read-only)"
+#+ * Sequence|ImageSequence.strobe -> strobe: float "Only display every nth frame"
+#+ * Sequence|ImageSequence.transform -> transform: pointer, "(read-only)"
+#+ * Sequence|ImageSequence.use_color_balance -> use_color_balance: boolean "(3-Way color correction) on input"
+#+ * Sequence|ImageSequence.use_crop -> use_crop: boolean "Crop image before processing"
+#Sequence|ImageSequence.use_deinterlace -> use_deinterlace: boolean "For video movies to remove fields"
+#Sequence|ImageSequence.use_flip_x -> use_flip_x: boolean "Flip on the X axis"
+#Sequence|ImageSequence.use_flip_y -> use_flip_y: boolean "Flip on the Y axis"
+#Sequence|ImageSequence.use_float -> use_float: boolean "Convert input to float data"
+#Sequence|ImageSequence.use_premultiply -> use_premultiply: boolean "Convert RGB from key alpha to premultiplied alpha"
+#+ * Sequence|ImageSequence.use_proxy -> use_proxy: boolean "Use a preview proxy for this strip"
+#Sequence|ImageSequence.use_proxy_custom_directory -> use_proxy_custom_directory: boolean "Use a custom directory to store data"
+#Sequence|ImageSequence.use_proxy_custom_file -> use_proxy_custom_file: boolean "Use a custom file to read proxy data from"
+#Sequence|ImageSequence.use_reverse_frames -> use_reverse_frames: boolean "Reverse frame order"
+#+ * Sequence|ImageSequence.use_translation -> use_translation: boolean "Translate image before processing"
+#Sequence|MetaSequence.animation_offset_end -> animation_offset_end: int "Animation end offset (trim end)"
+#Sequence|MetaSequence.animation_offset_start -> animation_offset_start: int "Animation start offset (trim start)"
+#+ * Sequence|MetaSequence.color_balance -> color_balance: pointer, "(read-only)"
+#Sequence|MetaSequence.color_multiply -> color_multiply: float "NO DESCRIPTION"
+#+ * Sequence|MetaSequence.color_saturation -> color_saturation: float "NO DESCRIPTION"
+#+ * Sequence|MetaSequence.crop -> crop: pointer, "(read-only)"
+#+ * Sequence|MetaSequence.proxy -> proxy: pointer, "(read-only)"
+#+ * Sequence|MetaSequence.sequences -> sequences: collection, "(read-only)"
+#+ * Sequence|MetaSequence.strobe -> strobe: float "Only display every nth frame"
+#+ * Sequence|MetaSequence.transform -> transform: pointer, "(read-only)"
+#+ * Sequence|MetaSequence.use_color_balance -> use_color_balance: boolean "(3-Way color correction) on input"
+#+ * Sequence|MetaSequence.use_crop -> use_crop: boolean "Crop image before processing"
+#Sequence|MetaSequence.use_deinterlace -> use_deinterlace: boolean "For video movies to remove fields"
+#Sequence|MetaSequence.use_flip_x -> use_flip_x: boolean "Flip on the X axis"
+#Sequence|MetaSequence.use_flip_y -> use_flip_y: boolean "Flip on the Y axis"
+#Sequence|MetaSequence.use_float -> use_float: boolean "Convert input to float data"
+#Sequence|MetaSequence.use_premultiply -> use_premultiply: boolean "Convert RGB from key alpha to premultiplied alpha"
+#+ * Sequence|MetaSequence.use_proxy -> use_proxy: boolean "Use a preview proxy for this strip"
+#Sequence|MetaSequence.use_proxy_custom_directory -> use_proxy_custom_directory: boolean "Use a custom directory to store data"
+#Sequence|MetaSequence.use_proxy_custom_file -> use_proxy_custom_file: boolean "Use a custom file to read proxy data from"
+#Sequence|MetaSequence.use_reverse_frames -> use_reverse_frames: boolean "Reverse frame order"
+#+ * Sequence|MetaSequence.use_translation -> use_translation: boolean "Translate image before processing"
+#Sequence|MovieSequence.animation_offset_end -> animation_offset_end: int "Animation end offset (trim end)"
+#Sequence|MovieSequence.animation_offset_start -> animation_offset_start: int "Animation start offset (trim start)"
+#+ * Sequence|MovieSequence.color_balance -> color_balance: pointer, "(read-only)"
+#Sequence|MovieSequence.color_multiply -> color_multiply: float "NO DESCRIPTION"
+#+ * Sequence|MovieSequence.color_saturation -> color_saturation: float "NO DESCRIPTION"
+#+ * Sequence|MovieSequence.crop -> crop: pointer, "(read-only)"
+#+ * Sequence|MovieSequence.filepath -> filepath: string "NO DESCRIPTION"
+#+ * Sequence|MovieSequence.mpeg_preseek -> mpeg_preseek: int "For MPEG movies, preseek this many frames"
+#+ * Sequence|MovieSequence.proxy -> proxy: pointer, "(read-only)"
+#+ * Sequence|MovieSequence.strobe -> strobe: float "Only display every nth frame"
+#+ * Sequence|MovieSequence.transform -> transform: pointer, "(read-only)"
+#+ * Sequence|MovieSequence.use_color_balance -> use_color_balance: boolean "(3-Way color correction) on input"
+#+ * Sequence|MovieSequence.use_crop -> use_crop: boolean "Crop image before processing"
+#Sequence|MovieSequence.use_deinterlace -> use_deinterlace: boolean "For video movies to remove fields"
+#Sequence|MovieSequence.use_flip_x -> use_flip_x: boolean "Flip on the X axis"
+#Sequence|MovieSequence.use_flip_y -> use_flip_y: boolean "Flip on the Y axis"
+#Sequence|MovieSequence.use_float -> use_float: boolean "Convert input to float data"
+#Sequence|MovieSequence.use_premultiply -> use_premultiply: boolean "Convert RGB from key alpha to premultiplied alpha"
+#+ * Sequence|MovieSequence.use_proxy -> use_proxy: boolean "Use a preview proxy for this strip"
+#Sequence|MovieSequence.use_proxy_custom_directory -> use_proxy_custom_directory: boolean "Use a custom directory to store data"
+#Sequence|MovieSequence.use_proxy_custom_file -> use_proxy_custom_file: boolean "Use a custom file to read proxy data from"
+#Sequence|MovieSequence.use_reverse_frames -> use_reverse_frames: boolean "Reverse frame order"
+#+ * Sequence|MovieSequence.use_translation -> use_translation: boolean "Translate image before processing"
+#Sequence|MulticamSequence.animation_offset_end -> animation_offset_end: int "Animation end offset (trim end)"
+#Sequence|MulticamSequence.animation_offset_start -> animation_offset_start: int "Animation start offset (trim start)"
+#+ * Sequence|MulticamSequence.color_balance -> color_balance: pointer, "(read-only)"
+#Sequence|MulticamSequence.color_multiply -> color_multiply: float "NO DESCRIPTION"
+#+ * Sequence|MulticamSequence.color_saturation -> color_saturation: float "NO DESCRIPTION"
+#+ * Sequence|MulticamSequence.crop -> crop: pointer, "(read-only)"
+#+ * Sequence|MulticamSequence.multicam_source -> multicam_source: int "NO DESCRIPTION"
+#+ * Sequence|MulticamSequence.proxy -> proxy: pointer, "(read-only)"
+#+ * Sequence|MulticamSequence.strobe -> strobe: float "Only display every nth frame"
+#+ * Sequence|MulticamSequence.transform -> transform: pointer, "(read-only)"
+#+ * Sequence|MulticamSequence.use_color_balance -> use_color_balance: boolean "(3-Way color correction) on input"
+#+ * Sequence|MulticamSequence.use_crop -> use_crop: boolean "Crop image before processing"
+#Sequence|MulticamSequence.use_deinterlace -> use_deinterlace: boolean "For video movies to remove fields"
+#Sequence|MulticamSequence.use_flip_x -> use_flip_x: boolean "Flip on the X axis"
+#Sequence|MulticamSequence.use_flip_y -> use_flip_y: boolean "Flip on the Y axis"
+#Sequence|MulticamSequence.use_float -> use_float: boolean "Convert input to float data"
+#Sequence|MulticamSequence.use_premultiply -> use_premultiply: boolean "Convert RGB from key alpha to premultiplied alpha"
+#+ * Sequence|MulticamSequence.use_proxy -> use_proxy: boolean "Use a preview proxy for this strip"
+#Sequence|MulticamSequence.use_proxy_custom_directory -> use_proxy_custom_directory: boolean "Use a custom directory to store data"
+#Sequence|MulticamSequence.use_proxy_custom_file -> use_proxy_custom_file: boolean "Use a custom file to read proxy data from"
+#Sequence|MulticamSequence.use_reverse_frames -> use_reverse_frames: boolean "Reverse frame order"
+#+ * Sequence|MulticamSequence.use_translation -> use_translation: boolean "Translate image before processing"
+#Sequence|SceneSequence.animation_offset_end -> animation_offset_end: int "Animation end offset (trim end)"
+#Sequence|SceneSequence.animation_offset_start -> animation_offset_start: int "Animation start offset (trim start)"
+#+ * Sequence|SceneSequence.color_balance -> color_balance: pointer, "(read-only)"
+#Sequence|SceneSequence.color_multiply -> color_multiply: float "NO DESCRIPTION"
+#+ * Sequence|SceneSequence.color_saturation -> color_saturation: float "NO DESCRIPTION"
+#+ * Sequence|SceneSequence.crop -> crop: pointer, "(read-only)"
+#+ * Sequence|SceneSequence.proxy -> proxy: pointer, "(read-only)"
+#+ * Sequence|SceneSequence.scene -> scene: pointer "Scene that this sequence uses"
+#+ * Sequence|SceneSequence.scene_camera -> scene_camera: pointer "Override the scenes active camera"
+#+ * Sequence|SceneSequence.strobe -> strobe: float "Only display every nth frame"
+#+ * Sequence|SceneSequence.transform -> transform: pointer, "(read-only)"
+#+ * Sequence|SceneSequence.use_color_balance -> use_color_balance: boolean "(3-Way color correction) on input"
+#+ * Sequence|SceneSequence.use_crop -> use_crop: boolean "Crop image before processing"
+#Sequence|SceneSequence.use_deinterlace -> use_deinterlace: boolean "For video movies to remove fields"
+#Sequence|SceneSequence.use_flip_x -> use_flip_x: boolean "Flip on the X axis"
+#Sequence|SceneSequence.use_flip_y -> use_flip_y: boolean "Flip on the Y axis"
+#Sequence|SceneSequence.use_float -> use_float: boolean "Convert input to float data"
+#Sequence|SceneSequence.use_premultiply -> use_premultiply: boolean "Convert RGB from key alpha to premultiplied alpha"
+#+ * Sequence|SceneSequence.use_proxy -> use_proxy: boolean "Use a preview proxy for this strip"
+#Sequence|SceneSequence.use_proxy_custom_directory -> use_proxy_custom_directory: boolean "Use a custom directory to store data"
+#Sequence|SceneSequence.use_proxy_custom_file -> use_proxy_custom_file: boolean "Use a custom file to read proxy data from"
+#Sequence|SceneSequence.use_reverse_frames -> use_reverse_frames: boolean "Reverse frame order"
+#+ * Sequence|SceneSequence.use_translation -> use_translation: boolean "Translate image before processing"
+#Sequence|SoundSequence.animation_offset_end -> animation_offset_end: int "Animation end offset (trim end)"
+#Sequence|SoundSequence.animation_offset_start -> animation_offset_start: int "Animation start offset (trim start)"
+#+ * Sequence|SoundSequence.attenuation -> attenuation: float "Attenuation in dezibel"
+#+ * Sequence|SoundSequence.filepath -> filepath: string "NO DESCRIPTION"
+#+ * Sequence|SoundSequence.sound -> sound: pointer, "(read-only) Sound datablock used by this sequence"
+#+ * Sequence|SoundSequence.volume -> volume: float "Playback volume of the sound"
+#+ * ShapeKey.data -> data: collection, "(read-only)"
+#+ * ShapeKey.frame -> frame: float, "(read-only) Frame for absolute keys"
+#+ * ShapeKey.interpolation -> interpolation: enum "Interpolation type"
+#+ * ShapeKey.mute -> mute: boolean "Mute this shape key"
+#+ * ShapeKey.name -> name: string "NO DESCRIPTION"
+#+ * ShapeKey.relative_key -> relative_key: pointer "Shape used as a relative key"
+#+ * ShapeKey.slider_max -> slider_max: float "Maximum for slider"
+#+ * ShapeKey.slider_min -> slider_min: float "Minimum for slider"
+#+ * ShapeKey.value -> value: float "Value of shape key at the current frame"
+#+ * ShapeKey.vertex_group -> vertex_group: string "Vertex weight group, to blend with basis shape"
+#+ * ShapeKeyBezierPoint.co -> co: float[3] "NO DESCRIPTION"
+#ShapeKeyBezierPoint.handle_left -> handle_left: float[3] "NO DESCRIPTION"
+#ShapeKeyBezierPoint.handle_right -> handle_right: float[3] "NO DESCRIPTION"
+#+ * ShapeKeyCurvePoint.co -> co: float[3] "NO DESCRIPTION"
+#+ * ShapeKeyCurvePoint.tilt -> tilt: float "NO DESCRIPTION"
+#+ * ShapeKeyPoint.co -> co: float[3] "NO DESCRIPTION"
+#TODO BETTER NAME * SmokeDomainSettings.alpha -> alpha: float "Higher value results in sinking smoke"
+#+ * SmokeDomainSettings.amplify -> amplify: int "Enhance the resolution of smoke by this factor using noise"
+#TODO BETTER NAME * SmokeDomainSettings.beta -> beta: float "Higher value results in faster rising smoke"
+#SmokeDomainSettings.collision_extents -> collision_extents: enum "Selects which domain border will be treated as collision object."
+#SmokeDomainSettings.collision_group -> collision_group: pointer "Limit collisions to this group"
+#+ * SmokeDomainSettings.dissolve_speed -> dissolve_speed: int "Dissolve Speed"
+#SmokeDomainSettings.effector_group -> effector_group: pointer "Limit effectors to this group"
+#+ * SmokeDomainSettings.effector_weights -> effector_weights: pointer, "(read-only)"
+#+ * SmokeDomainSettings.fluid_group -> fluid_group: pointer "Limit fluid objects to this group"
+#+ * SmokeDomainSettings.noise_type -> noise_type: enum "Noise method which is used for creating the high resolution"
+#SmokeDomainSettings.point_cache_compress_high_type -> point_cache_compress_high_type: enum "Compression method to be used"
+#SmokeDomainSettings.point_cache_compress_type -> point_cache_compress_type: enum "Compression method to be used"
+#+ * SmokeDomainSettings.point_cache_high -> point_cache_high: pointer, "(read-only)"
+#+ * SmokeDomainSettings.point_cache_low -> point_cache_low: pointer, "(read-only)"
+#SmokeDomainSettings.resolution_max -> resolution_max: int "Maximal resolution used in the fluid domain"
+#SmokeDomainSettings.show_high_resolution -> show_high_resolution: boolean "Show high resolution (using amplification)"
+#SmokeDomainSettings.smooth_emitter -> smooth_emitter: boolean "Smoothens emitted smoke to avoid blockiness."
+#+ * SmokeDomainSettings.strength -> strength: float "Strength of wavelet noise"
+#+ * SmokeDomainSettings.time_scale -> time_scale: float "Adjust simulation speed."
+#SmokeDomainSettings.use_dissolve_smoke -> use_dissolve_smoke: boolean "Enable smoke to disappear over time"
+#SmokeDomainSettings.use_dissolve_smoke_log -> use_dissolve_smoke_log: boolean "Using 1/x"
+#SmokeDomainSettings.use_high_resolution -> use_high_resolution: boolean "Enable high resolution (using amplification)"
+#+ * SmokeDomainSettings.vorticity -> vorticity: float "Amount of turbulence/rotation in fluid."
+#+ * SmokeFlowSettings.density -> density: float "NO DESCRIPTION"
+#+ * SmokeFlowSettings.initial_velocity -> initial_velocity: boolean "Smoke inherits its velocity from the emitter particle"
+#SmokeFlowSettings.particle_system -> particle_system: pointer "Particle systems emitted from the object"
+#+ * SmokeFlowSettings.temperature -> temperature: float "Temperature difference to ambient temperature"
+#SmokeFlowSettings.use_absolute -> use_absolute: boolean "Only allows given density value in emitter area."
+#SmokeFlowSettings.use_outflow -> use_outflow: boolean "Deletes smoke from simulation"
+#SmokeFlowSettings.velocity_factor -> velocity_factor: float "Multiplier to adjust velocity passed to smoke"
+#+ * SoftBodySettings.aero -> aero: float "Make edges sail"
+#+ * SoftBodySettings.aerodynamics_type -> aerodynamics_type: enum "Method of calculating aerodynamic interaction"
+#+ * SoftBodySettings.ball_damp -> ball_damp: float "Blending to inelastic collision"
+#+ * SoftBodySettings.ball_size -> ball_size: float "Absolute ball size or factor if not manual adjusted"
+#+ * SoftBodySettings.ball_stiff -> ball_stiff: float "Ball inflating pressure"
+#SoftBodySettings.bend -> bend: float "Bending Stiffness"
+#+ * SoftBodySettings.choke -> choke: int "Viscosity inside collision target"
+#+ * SoftBodySettings.collision_type -> collision_type: enum "Choose Collision Type"
+#SoftBodySettings.damping -> damping: float "Edge spring friction"
+#+ * SoftBodySettings.effector_weights -> effector_weights: pointer, "(read-only)"
+#SoftBodySettings.error_threshold -> error_threshold: float "The Runge-Kutta ODE solver error limit, low value gives more precision, high values speed"
+#+ * SoftBodySettings.friction -> friction: float "General media friction for point movements"
+#+ * SoftBodySettings.fuzzy -> fuzzy: int "Fuzziness while on collision, high values make collsion handling faster but less stable"
+#+ * SoftBodySettings.goal_default -> goal_default: float "Default Goal (vertex target position) value, when no Vertex Group used"
+#+ * SoftBodySettings.goal_friction -> goal_friction: float "Goal (vertex target position) friction"
+#+ * SoftBodySettings.goal_max -> goal_max: float "Goal maximum, vertex weights are scaled to match this range"
+#+ * SoftBodySettings.goal_min -> goal_min: float "Goal minimum, vertex weights are scaled to match this range"
+#+ * SoftBodySettings.goal_spring -> goal_spring: float "Goal (vertex target position) spring stiffness"
+#+ * SoftBodySettings.goal_vertex_group -> goal_vertex_group: string "Control point weight values"
+#+ * SoftBodySettings.gravity -> gravity: float "Apply gravitation to point movement"
+#SoftBodySettings.location_mass_center -> location_mass_center: float[3] "Location of Center of mass"
+#+ * SoftBodySettings.mass -> mass: float "General Mass value"
+#+ * SoftBodySettings.mass_vertex_group -> mass_vertex_group: string "Control point mass values"
+#+ * SoftBodySettings.plastic -> plastic: float "Permanent deform"
+#+ * SoftBodySettings.pull -> pull: float "Edge spring stiffness when longer than rest length"
+#+ * SoftBodySettings.push -> push: float "Edge spring stiffness when shorter than rest length"
+#SoftBodySettings.rotation_estimate -> rotation_estimate: float[9] "Estimated rotation matrix"
+#SoftBodySettings.scale_estimate -> scale_estimate: float[9] "Estimated scale matrix"
+#+ * SoftBodySettings.shear -> shear: float "Shear Stiffness"
+#+ * SoftBodySettings.speed -> speed: float "Tweak timing for physics to control frequency and speed"
+#+ * SoftBodySettings.spring_length -> spring_length: float "Alter spring length to shrink/blow up (unit %) 0 to disable"
+#+ * SoftBodySettings.spring_vertex_group -> spring_vertex_group: string "Control point spring strength values"
+#SoftBodySettings.step_max -> step_max: int "Maximal # solver steps/frame"
+#SoftBodySettings.step_min -> step_min: int "Minimal # solver steps/frame"
+#SoftBodySettings.use_auto_step -> use_auto_step: boolean "Use velocities for automagic step sizes"
+#SoftBodySettings.use_diagnose -> use_diagnose: boolean "Turn on SB diagnose console prints"
+#SoftBodySettings.use_edge_collision -> use_edge_collision: boolean "Edges collide too"
+#+ * SoftBodySettings.use_edges -> use_edges: boolean "Use Edges as springs"
+#SoftBodySettings.use_estimate_matrix -> use_estimate_matrix: boolean "estimate matrix .. split to COM , ROT ,SCALE"
+#SoftBodySettings.use_face_collision -> use_face_collision: boolean "Faces collide too, can be very slow"
+#+ * SoftBodySettings.use_goal -> use_goal: boolean "Define forces for vertices to stick to animated position"
+#SoftBodySettings.use_self_collision -> use_self_collision: boolean "Enable naive vertex ball self collision"
+#SoftBodySettings.use_stiff_quads -> use_stiff_quads: boolean "Adds diagonal springs on 4-gons"
+#+ * Space.type -> type: enum, "(read-only) Space data type"
+#+ * SpaceUVEditor.cursor_location -> cursor_location: float[2] "2D cursor location for this view"
+#+ * SpaceUVEditor.draw_stretch_type -> draw_stretch_type: enum "Type of stretch to draw"
+#+ * SpaceUVEditor.edge_draw_type -> edge_draw_type: enum "Draw type for drawing UV edges"
+#SpaceUVEditor.lock_bounds -> lock_bounds: boolean "Constraint to stay within the image bounds while editing"
+#SpaceUVEditor.pivot_point -> pivot_point: enum "Rotation/Scaling Pivot"
+#SpaceUVEditor.show_modified_edges -> show_modified_edges: boolean "Draw edges after modifiers are applied"
+#SpaceUVEditor.show_normalized_coords -> show_normalized_coords: boolean "Display UV coordinates from 0.0 to 1.0 rather than in pixels"
+#SpaceUVEditor.show_other_objects -> show_other_objects: boolean "Draw other selected objects that share the same image"
+#SpaceUVEditor.show_smooth_edges -> show_smooth_edges: boolean "Draw UV edges anti-aliased"
+#SpaceUVEditor.show_stretch -> show_stretch: boolean "Draw faces colored according to the difference in shape between UVs and their 3D coordinates (blue for low distortion, red for high distortion)"
+#SpaceUVEditor.sticky_select_mode -> sticky_select_mode: enum "Automatically select also UVs sharing the same vertex as the ones being selected"
+#SpaceUVEditor.use_live_unwrap -> use_live_unwrap: boolean "Continuously unwrap the selected UV island while transforming pinned vertices"
+#SpaceUVEditor.use_snap_to_pixels -> use_snap_to_pixels: boolean "Snap UVs to pixel locations while editing"
+#+ * Space|SpaceConsole.console_type -> console_type: enum "Console type"
+#+ * Space|SpaceConsole.font_size -> font_size: int "Font size to use for displaying the text"
+#+ * Space|SpaceConsole.history -> history: collection, "(read-only) Command history"
+#+ * Space|SpaceConsole.language -> language: string "Command line prompt language"
+#+ * Space|SpaceConsole.prompt -> prompt: string "Command line prompt"
+#+ * Space|SpaceConsole.scrollback -> scrollback: collection, "(read-only) Command output"
+#Space|SpaceConsole.select_end -> select_end: int "NO DESCRIPTION"
+#Space|SpaceConsole.select_start -> select_start: int "NO DESCRIPTION"
+#+ * Space|SpaceConsole.show_report_debug -> show_report_debug: boolean "Display debug reporting info"
+#+ * Space|SpaceConsole.show_report_error -> show_report_error: boolean "Display error text"
+#+ * Space|SpaceConsole.show_report_info -> show_report_info: boolean "Display general information"
+#+ * Space|SpaceConsole.show_report_operator -> show_report_operator: boolean "Display the operator log"
+#Space|SpaceConsole.show_report_warning -> show_report_warning: boolean "Display warnings"
+#+ * Space|SpaceDopeSheetEditor.action -> action: pointer "Action displayed and edited in this space"
+#Space|SpaceDopeSheetEditor.auto_snap -> auto_snap: enum "Automatic time snapping settings for transformations"
+#+ * Space|SpaceDopeSheetEditor.dopesheet -> dopesheet: pointer, "(read-only) Settings for filtering animation data"
+#+ * Space|SpaceDopeSheetEditor.mode -> mode: enum "Editing context being displayed"
+#Space|SpaceDopeSheetEditor.show_frame_indicator -> show_frame_indicator: boolean "Show frame number beside the current frame indicator line"
+#+ * Space|SpaceDopeSheetEditor.show_seconds -> show_seconds: boolean, "(read-only) Show timing in seconds not frames"
+#+ * Space|SpaceDopeSheetEditor.show_sliders -> show_sliders: boolean "Show sliders beside F-Curve channels"
+#Space|SpaceDopeSheetEditor.use_auto_merge_keyframes -> use_auto_merge_keyframes: boolean "Automatically merge nearby keyframes"
+#+ * Space|SpaceDopeSheetEditor.use_marker_sync -> use_marker_sync: boolean "Sync Markers with keyframe edits"
+#Space|SpaceDopeSheetEditor.use_realtime_update -> use_realtime_update: boolean "When transforming keyframes, changes to the animation data are flushed to other views"
+#+ * Space|SpaceFileBrowser.params -> params: pointer, "(read-only) Parameters and Settings for the Filebrowser"
+#Space|SpaceGraphEditor.auto_snap -> auto_snap: enum "Automatic time snapping settings for transformations"
+#Space|SpaceGraphEditor.cursor_position_y -> cursor_position_y: float "Graph Editor 2D-Value cursor - Y-Value component"
+#+ * Space|SpaceGraphEditor.dopesheet -> dopesheet: pointer, "(read-only) Settings for filtering animation data"
+#+ * Space|SpaceGraphEditor.has_ghost_curves -> has_ghost_curves: boolean "Graph Editor instance has some ghost curves stored"
+#+ * Space|SpaceGraphEditor.mode -> mode: enum "Editing context being displayed"
+#+ * Space|SpaceGraphEditor.pivot_point -> pivot_point: enum "Pivot center for rotation/scaling"
+#+ * Space|SpaceGraphEditor.show_cursor -> show_cursor: boolean "Show 2D cursor"
+#Space|SpaceGraphEditor.show_frame_indicator -> show_frame_indicator: boolean "Show frame number beside the current frame indicator line"
+#+ * Space|SpaceGraphEditor.show_handles -> show_handles: boolean "Show handles of Bezier control points"
+#+ * Space|SpaceGraphEditor.show_seconds -> show_seconds: boolean, "(read-only) Show timing in seconds not frames"
+#+ * Space|SpaceGraphEditor.show_sliders -> show_sliders: boolean "Show sliders beside F-Curve channels"
+#Space|SpaceGraphEditor.use_auto_merge_keyframes -> use_auto_merge_keyframes: boolean "Automatically merge nearby keyframes"
+#Space|SpaceGraphEditor.use_only_selected_curves_handles -> use_only_selected_curves_handles: boolean "Only keyframes of selected F-Curves are visible and editable"
+#Space|SpaceGraphEditor.use_only_selected_keyframe_handles -> use_only_selected_keyframe_handles: boolean "Only show and edit handles of selected keyframes"
+#Space|SpaceGraphEditor.use_realtime_update -> use_realtime_update: boolean "When transforming keyframes, changes to the animation data are flushed to other views"
+#+ * Space|SpaceImageEditor.curves -> curves: pointer, "(read-only) Color curve mapping to use for displaying the image"
+#+ * Space|SpaceImageEditor.draw_channels -> draw_channels: enum "Channels of the image to draw"
+#+ * Space|SpaceImageEditor.grease_pencil -> grease_pencil: pointer "Grease pencil data for this space"
+#+ * Space|SpaceImageEditor.image -> image: pointer "Image displayed and edited in this space"
+#+ * Space|SpaceImageEditor.image_user -> image_user: pointer, "(read-only) Parameters defining which layer, pass and frame of the image is displayed"
+#+ * Space|SpaceImageEditor.sample_histogram -> sample_histogram: pointer, "(read-only) Sampled colors along line"
+#+ * Space|SpaceImageEditor.scopes -> scopes: pointer, "(read-only) Scopes to visualize image statistics."
+#+ * Space|SpaceImageEditor.show_paint -> show_paint: boolean, "(read-only) Show paint related properties"
+#+ * Space|SpaceImageEditor.show_render -> show_render: boolean, "(read-only) Show render related properties"
+#Space|SpaceImageEditor.show_repeat -> show_repeat: boolean "Draw the image repeated outside of the main view"
+#+ * Space|SpaceImageEditor.show_uvedit -> show_uvedit: boolean, "(read-only) Show UV editing related properties"
+#+ * Space|SpaceImageEditor.use_grease_pencil -> use_grease_pencil: boolean "Display and edit the grease pencil freehand annotations overlay"
+#Space|SpaceImageEditor.use_image_paint -> use_image_paint: boolean "Enable image painting mode"
+#Space|SpaceImageEditor.use_image_pin -> use_image_pin: boolean "Display current image regardless of object selection"
+#Space|SpaceImageEditor.use_realtime_update -> use_realtime_update: boolean "Update other affected window spaces automatically to reflect changes during interactive operations such as transform"
+#+ * Space|SpaceImageEditor.uv_editor -> uv_editor: pointer, "(read-only) UV editor settings"
+#Space|SpaceLogicEditor.show_actuators_active_object -> show_actuators_active_object: boolean "Show actuators of active object"
+#Space|SpaceLogicEditor.show_actuators_active_states -> show_actuators_active_states: boolean "Show only actuators connected to active states"
+#Space|SpaceLogicEditor.show_actuators_linked_controller -> show_actuators_linked_controller: boolean "Show linked objects to the actuator"
+#Space|SpaceLogicEditor.show_actuators_selected_objects -> show_actuators_selected_objects: boolean "Show actuators of all selected objects"
+#Space|SpaceLogicEditor.show_controllers_active_object -> show_controllers_active_object: boolean "Show controllers of active object"
+#Space|SpaceLogicEditor.show_controllers_linked_controller -> show_controllers_linked_controller: boolean "Show linked objects to sensor/actuator"
+#Space|SpaceLogicEditor.show_controllers_selected_objects -> show_controllers_selected_objects: boolean "Show controllers of all selected objects"
+#Space|SpaceLogicEditor.show_sensors_active_object -> show_sensors_active_object: boolean "Show sensors of active object"
+#Space|SpaceLogicEditor.show_sensors_active_states -> show_sensors_active_states: boolean "Show only sensors connected to active states"
+#Space|SpaceLogicEditor.show_sensors_linked_controller -> show_sensors_linked_controller: boolean "Show linked objects to the controller"
+#Space|SpaceLogicEditor.show_sensors_selected_objects -> show_sensors_selected_objects: boolean "Show sensors of all selected objects"
+#Space|SpaceNLA.auto_snap -> auto_snap: enum "Automatic time snapping settings for transformations"
+#+ * Space|SpaceNLA.dopesheet -> dopesheet: pointer, "(read-only) Settings for filtering animation data"
+#Space|SpaceNLA.show_frame_indicator -> show_frame_indicator: boolean "Show frame number beside the current frame indicator line"
+#+ * Space|SpaceNLA.show_seconds -> show_seconds: boolean, "(read-only) Show timing in seconds not frames"
+#+ * Space|SpaceNLA.show_strip_curves -> show_strip_curves: boolean "Show influence curves on strips"
+#Space|SpaceNLA.use_realtime_update -> use_realtime_update: boolean "When transforming strips, changes to the animation data are flushed to other views"
+#+ * Space|SpaceNodeEditor.id -> id: pointer, "(read-only) Datablock whose nodes are being edited"
+#+ * Space|SpaceNodeEditor.id_from -> id_from: pointer, "(read-only) Datablock from which the edited datablock is linked"
+#+ * Space|SpaceNodeEditor.nodetree -> nodetree: pointer, "(read-only) Node tree being displayed and edited"
+#Space|SpaceNodeEditor.show_backdrop -> show_backdrop: boolean "Use active Viewer Node output as backdrop for compositing nodes"
+#+ * Space|SpaceNodeEditor.texture_type -> texture_type: enum "Type of data to take texture from"
+#+ * Space|SpaceNodeEditor.tree_type -> tree_type: enum "Node tree type to display and edit"
+#+ * Space|SpaceOutliner.display_mode -> display_mode: enum "Type of information to display"
+#Space|SpaceOutliner.filter_text -> filter_text: string "Live search filtering string"
+#Space|SpaceOutliner.show_restrict_columns -> show_restrict_columns: boolean "Show column"
+#Space|SpaceOutliner.use_filter_case_sensitive -> use_filter_case_sensitive: boolean "Only use case sensitive matches of search string"
+#Space|SpaceOutliner.use_filter_complete -> use_filter_complete: boolean "Only use complete matches of search string"
+#+ * Space|SpaceProperties.align -> align: enum "Arrangement of the panels"
+#+ * Space|SpaceProperties.context -> context: enum "Type of active data to display and edit"
+#+ * Space|SpaceProperties.pin_id -> pin_id: pointer "NO DESCRIPTION"
+#Space|SpaceProperties.show_brush_texture -> show_brush_texture: boolean "Show brush textures"
+#+ * Space|SpaceProperties.use_pin_id -> use_pin_id: boolean "Use the pinned context"
+#+ * Space|SpaceSequenceEditor.display_channel -> display_channel: int "The channel number shown in the image preview. 0 is the result of all strips combined"
+#+ * Space|SpaceSequenceEditor.display_mode -> display_mode: enum "The view mode to use for displaying sequencer output"
+#+ * Space|SpaceSequenceEditor.draw_overexposed -> draw_overexposed: int "Show overexposed areas with zebra stripes"
+#+ * Space|SpaceSequenceEditor.grease_pencil -> grease_pencil: pointer, "(read-only) Grease pencil data for this space"
+#+ * Space|SpaceSequenceEditor.offset_x -> offset_x: float "Offsets image horizontally from the view center"
+#+ * Space|SpaceSequenceEditor.offset_y -> offset_y: float "Offsets image horizontally from the view center"
+#+ * Space|SpaceSequenceEditor.proxy_render_size -> proxy_render_size: enum "Draw preview using full resolution or different proxy resolutions"
+#Space|SpaceSequenceEditor.show_frame_indicator -> show_frame_indicator: boolean "Show frame number beside the current frame indicator line"
+#Space|SpaceSequenceEditor.show_frames -> show_frames: boolean "Draw frames rather than seconds"
+#Space|SpaceSequenceEditor.show_safe_margin -> show_safe_margin: boolean "Draw title safe margins in preview"
+#Space|SpaceSequenceEditor.show_separate_color -> show_separate_color: boolean "Separate color channels in preview"
+#+ * Space|SpaceSequenceEditor.use_grease_pencil -> use_grease_pencil: boolean "Display and edit the grease pencil freehand annotations overlay"
+#+ * Space|SpaceSequenceEditor.use_marker_sync -> use_marker_sync: boolean "Transform markers as well as strips"
+#+ * Space|SpaceSequenceEditor.view_type -> view_type: enum "The type of the Sequencer view (sequencer, preview or both)"
+#+ * Space|SpaceSequenceEditor.zoom -> zoom: float "Display zoom level"
+#+ * Space|SpaceTextEditor.find_text -> find_text: string "Text to search for with the find tool"
+#+ * Space|SpaceTextEditor.font_size -> font_size: int "Font size to use for displaying the text"
+#+ * Space|SpaceTextEditor.replace_text -> replace_text: string "Text to replace selected text with using the replace tool"
+#Space|SpaceTextEditor.show_line_highlight -> show_line_highlight: boolean "Highlight the current line"
+#+ * Space|SpaceTextEditor.show_line_numbers -> show_line_numbers: boolean "Show line numbers next to the text"
+#+ * Space|SpaceTextEditor.show_syntax_highlight -> show_syntax_highlight: boolean "Syntax highlight for scripting"
+#+ * Space|SpaceTextEditor.show_word_wrap -> show_word_wrap: boolean "Wrap words if there is not enough horizontal space"
+#+ * Space|SpaceTextEditor.tab_width -> tab_width: int "Number of spaces to display tabs with"
+#+ * Space|SpaceTextEditor.text -> text: pointer "Text displayed and edited in this space"
+#Space|SpaceTextEditor.use_find_all -> use_find_all: boolean "Search in all text datablocks, instead of only the active one"
+#Space|SpaceTextEditor.use_find_wrap -> use_find_wrap: boolean "Search again from the start of the file when reaching the end"
+#Space|SpaceTextEditor.use_live_edit -> use_live_edit: boolean "Run python while editing"
+#Space|SpaceTextEditor.use_overwrite -> use_overwrite: boolean "Overwrite characters when typing rather than inserting them"
+#+ * Space|SpaceTimeline.cache_cloth -> cache_cloth: boolean "Show the active objects cloth point cache"
+#+ * Space|SpaceTimeline.cache_particles -> cache_particles: boolean "Show the active objects particle point cache"
+#+ * Space|SpaceTimeline.cache_smoke -> cache_smoke: boolean "Show the active objects smoke cache"
+#+ * Space|SpaceTimeline.cache_softbody -> cache_softbody: boolean "Show the active objects softbody point cache"
+#+ * Space|SpaceTimeline.show_cache -> show_cache: boolean "Show the status of cached frames in the timeline"
+#Space|SpaceTimeline.show_frame_indicator -> show_frame_indicator: boolean "Show frame number beside the current frame indicator line"
+#Space|SpaceTimeline.show_only_selected -> show_only_selected: boolean "Show keyframes for active Object and/or its selected channels only"
+#Space|SpaceTimeline.use_play_3d_editors -> use_play_3d_editors: boolean "NO DESCRIPTION"
+#Space|SpaceTimeline.use_play_animation_editors -> use_play_animation_editors: boolean "NO DESCRIPTION"
+#Space|SpaceTimeline.use_play_image_editors -> use_play_image_editors: boolean "NO DESCRIPTION"
+#Space|SpaceTimeline.use_play_node_editors -> use_play_node_editors: boolean "NO DESCRIPTION"
+#Space|SpaceTimeline.use_play_properties_editors -> use_play_properties_editors: boolean "NO DESCRIPTION"
+#Space|SpaceTimeline.use_play_sequence_editors -> use_play_sequence_editors: boolean "NO DESCRIPTION"
+#Space|SpaceTimeline.use_play_top_left_3d_editor -> use_play_top_left_3d_editor: boolean "NO DESCRIPTION"
+#Space|SpaceUserPreferences.filter_text -> filter_text: string "Search term for filtering in the UI"
+#+ * Space|SpaceView3D.background_images -> background_images: collection, "(read-only) List of background images"
+#+ * Space|SpaceView3D.camera -> camera: pointer "Active camera used in this view (when unlocked from the scenes active camera)"
+#+ * Space|SpaceView3D.clip_end -> clip_end: float "3D View far clipping distance"
+#+ * Space|SpaceView3D.clip_start -> clip_start: float "3D View near clipping distance"
+#+ * Space|SpaceView3D.current_orientation -> current_orientation: pointer, "(read-only) Current Transformation orientation"
+#+ * Space|SpaceView3D.cursor_location -> cursor_location: float[3] "3D cursor location for this view (dependent on local view setting)"
+#+ * Space|SpaceView3D.grid_lines -> grid_lines: int "The number of grid lines to display in perspective view"
+#+ * Space|SpaceView3D.grid_spacing -> grid_spacing: float "The distance between 3D View grid lines"
+#+ * Space|SpaceView3D.grid_subdivisions -> grid_subdivisions: int "The number of subdivisions between grid lines"
+#+ * Space|SpaceView3D.layers -> layers: boolean[20] "Layers visible in this 3D View"
+#Space|SpaceView3D.layers_used -> layers_used: boolean[20], "(read-only) Layers that contain something"
+#+ * Space|SpaceView3D.lens -> lens: float "Lens angle (mm) in perspective view"
+#+ * Space|SpaceView3D.local_view -> local_view: pointer, "(read-only) Display an isolated sub-set of objects, apart from the scene visibility"
+#+ * Space|SpaceView3D.lock_bone -> lock_bone: string "3D View center is locked to this bones position"
+#+ * Space|SpaceView3D.lock_camera_and_layers -> lock_camera_and_layers: boolean "Use the scenes active camera and layers in this view, rather than local layers"
+#+ * Space|SpaceView3D.lock_object -> lock_object: pointer "3D View center is locked to this objects position"
+#+ * Space|SpaceView3D.pivot_point -> pivot_point: enum "Pivot center for rotation/scaling"
+#+ * Space|SpaceView3D.region_3d -> region_3d: pointer, "(read-only) 3D region in this space, in case of quad view the camera region"
+#+ * Space|SpaceView3D.region_quadview -> region_quadview: pointer, "(read-only) 3D region that defines the quad view settings"
+#Space|SpaceView3D.show_all_objects_origin -> show_all_objects_origin: boolean "Show the object origin center dot for all (selected and unselected) objects"
+#Space|SpaceView3D.show_axis_x -> show_axis_x: boolean "Show the X axis line in perspective view"
+#Space|SpaceView3D.show_axis_y -> show_axis_y: boolean "Show the Y axis line in perspective view"
+#Space|SpaceView3D.show_axis_z -> show_axis_z: boolean "Show the Z axis line in perspective view"
+#Space|SpaceView3D.show_background_images -> show_background_images: boolean "Display reference images behind objects in the 3D View"
+#Space|SpaceView3D.show_floor -> show_floor: boolean "Show the ground plane grid in perspective view"
+#Space|SpaceView3D.show_manipulator -> show_manipulator: boolean "Use a 3D manipulator widget for controlling transforms"
+#Space|SpaceView3D.show_only_render -> show_only_render: boolean "Display only objects which will be rendered"
+#Space|SpaceView3D.show_outline_selected -> show_outline_selected: boolean "Show an outline highlight around selected objects in non-wireframe views"
+#Space|SpaceView3D.show_relationship_lines -> show_relationship_lines: boolean "Show dashed lines indicating parent or constraint relationships"
+#Space|SpaceView3D.show_textured_solid -> show_textured_solid: boolean "Display face-assigned textures in solid view"
+#+ * Space|SpaceView3D.transform_orientation -> transform_orientation: enum "Transformation orientation"
+#Space|SpaceView3D.use_manipulator_rotate -> use_manipulator_rotate: boolean "Use the manipulator for rotation transformations"
+#Space|SpaceView3D.use_manipulator_scale -> use_manipulator_scale: boolean "Use the manipulator for scale transformations"
+#Space|SpaceView3D.use_manipulator_translate -> use_manipulator_translate: boolean "Use the manipulator for movement transformations"
+#Space|SpaceView3D.use_occlude_geometry -> use_occlude_geometry: boolean "Limit selection to visible (clipped with depth buffer)"
+#Space|SpaceView3D.use_pivot_point_align -> use_pivot_point_align: boolean "Manipulate object centers only"
+#Space|SpaceView3D.viewport_shade -> viewport_shade: enum "Method to display/shade objects in the 3D View"
+#+ * Spline.bezier_points -> bezier_points: collection, "(read-only) Collection of points for bezier curves only"
+#+ * Spline.character_index -> character_index: int, "(read-only) Location of this character in the text data (only for text curves)"
+#+ * Spline.hide -> hide: boolean "Hide this curve in editmode"
+#+ * Spline.material_index -> material_index: int "NO DESCRIPTION"
+#+ * Spline.order_u -> order_u: int "Nurbs order in the U direction (For splines and surfaces), Higher values let points influence a greater area"
+#+ * Spline.order_v -> order_v: int "Nurbs order in the V direction (For surfaces only), Higher values let points influence a greater area"
+#+ * Spline.point_count_u -> point_count_u: int, "(read-only) Total number points for the curve or surface in the U direction"
+#+ * Spline.point_count_v -> point_count_v: int, "(read-only) Total number points for the surface on the V direction"
+#+ * Spline.points -> points: collection, "(read-only) Collection of points that make up this poly or nurbs spline"
+#+ * Spline.radius_interpolation -> radius_interpolation: enum "The type of radius interpolation for Bezier curves"
+#+ * Spline.resolution_u -> resolution_u: int "Curve or Surface subdivisions per segment"
+#+ * Spline.resolution_v -> resolution_v: int "Surface subdivisions per segment"
+#+ * Spline.tilt_interpolation -> tilt_interpolation: enum "The type of tilt interpolation for 3D, Bezier curves"
+#+ * Spline.type -> type: enum "The interpolation type for this curve element"
+#Spline.use_bezier_u -> use_bezier_u: boolean "Make this nurbs curve or surface act like a bezier spline in the U direction (Order U must be 3 or 4, Cyclic U must be disabled)"
+#Spline.use_bezier_v -> use_bezier_v: boolean "Make this nurbs surface act like a bezier spline in the V direction (Order V must be 3 or 4, Cyclic V must be disabled)"
+#Spline.use_cyclic_u -> use_cyclic_u: boolean "Make this curve or surface a closed loop in the U direction"
+#Spline.use_cyclic_v -> use_cyclic_v: boolean "Make this surface a closed loop in the V direction"
+#Spline.use_endpoint_u -> use_endpoint_u: boolean "Make this nurbs curve or surface meet the endpoints in the U direction (Cyclic U must be disabled)"
+#Spline.use_endpoint_v -> use_endpoint_v: boolean "Make this nurbs surface meet the endpoints in the V direction (Cyclic V must be disabled)"
+#Spline.use_smooth -> use_smooth: boolean "Smooth the normals of the surface or beveled curve"
+#+ * SplinePoint.co -> co: float[4] "Point coordinates"
+#+ * SplinePoint.hide -> hide: boolean "Visibility status"
+#+ * SplinePoint.radius -> radius: float, "(read-only) Radius for bevelling"
+#+ * SplinePoint.select -> select: boolean "Selection status"
+#+ * SplinePoint.tilt -> tilt: float "Tilt in 3D View"
+#+ * SplinePoint.weight -> weight: float "Nurbs weight"
+#+ * SplinePoint.weight_softbody -> weight_softbody: float "Softbody goal weight"
+#+ * Struct.base -> base: pointer, "(read-only) Struct definition this is derived from"
+#+ * Struct.description -> description: string, "(read-only) Description of the Structs purpose"
+#+ * Struct.functions -> functions: collection, "(read-only)"
+#+ * Struct.identifier -> identifier: string, "(read-only) Unique name used in the code and scripting"
+#+ * Struct.name -> name: string, "(read-only) Human readable name"
+#+ * Struct.name_property -> name_property: pointer, "(read-only) Property that gives the name of the struct"
+#+ * Struct.nested -> nested: pointer, "(read-only) Struct in which this struct is always nested, and to which it logically belongs"
+#+ * Struct.properties -> properties: collection, "(read-only) Properties in the struct"
+#+ * TexMapping.location -> location: float[3] "NO DESCRIPTION"
+#TexMapping.max -> max: float[3] "Maximum value for clipping"
+#TexMapping.min -> min: float[3] "Minimum value for clipping"
+#+ * TexMapping.rotation -> rotation: float[3] "NO DESCRIPTION"
+#+ * TexMapping.scale -> scale: float[3] "NO DESCRIPTION"
+#TexMapping.use_max -> use_max: boolean "Whether to use maximum clipping value"
+#TexMapping.use_min -> use_min: boolean "Whether to use minimum clipping value"
+#+ * TextBox.height -> height: float "NO DESCRIPTION"
+#+ * TextBox.width -> width: float "NO DESCRIPTION"
+#+ * TextBox.x -> x: float "NO DESCRIPTION"
+#+ * TextBox.y -> y: float "NO DESCRIPTION"
+#TextCharacterFormat.use_bold -> use_bold: boolean "NO DESCRIPTION"
+#TextCharacterFormat.use_italic -> use_italic: boolean "NO DESCRIPTION"
+#+ * TextCharacterFormat.use_small_caps -> use_small_caps: boolean "NO DESCRIPTION"
+#TextCharacterFormat.use_underline -> use_underline: boolean "NO DESCRIPTION"
+#+ * TextLine.body -> body: string "Text in the line"
+#TextMarker.character_index_end -> character_index_end: int, "(read-only) Start position of the marker in the line"
+#TextMarker.character_index_start -> character_index_start: int, "(read-only) Start position of the marker in the line"
+#+ * TextMarker.color -> color: float[4] "Color to display the marker with"
+#+ * TextMarker.group -> group: int, "(read-only)"
+#TextMarker.is_temporary -> is_temporary: boolean, "(read-only) Marker is temporary"
+#+ * TextMarker.line -> line: int, "(read-only) Line in which the marker is located"
+#TextMarker.use_edit_all -> use_edit_all: boolean, "(read-only) Edit all markers of the same group as one"
+#+ * TextureSlot.blend_type -> blend_type: enum "NO DESCRIPTION"
+#+ * TextureSlot.color -> color: float[3] "The default color for textures that dont return RGB"
+#+ * TextureSlot.default_value -> default_value: float "Value to use for Ref, Spec, Amb, Emit, Alpha, RayMir, TransLu and Hard"
+#TextureSlot.invert -> invert: boolean "Inverts the values of the texture to reverse its effect"
+#+ * TextureSlot.name -> name: string, "(read-only) Texture slot name"
+#+ * TextureSlot.offset -> offset: float[3] "Fine tunes texture mapping X, Y and Z locations"
+#+ * TextureSlot.output_node -> output_node: enum "Which output node to use, for node-based textures"
+#TextureSlot.scale -> scale: float[3] "Sets scaling for the textures X, Y and Z sizes"
+#+ * TextureSlot.texture -> texture: pointer "Texture datablock used by this texture slot"
+#TextureSlot.use_rgb_to_intensity -> use_rgb_to_intensity: boolean "Converts texture RGB values to intensity (gray) values"
+#TextureSlot.use_stencil -> use_stencil: boolean "Use this texture as a blending value on the next texture"
+#+ * TextureSlot|BrushTextureSlot.angle -> angle: float "Defines brush texture rotation"
+#+ * TextureSlot|BrushTextureSlot.map_mode -> map_mode: enum "NO DESCRIPTION"
+#+ * TextureSlot|LampTextureSlot.color_factor -> color_factor: float "Amount texture affects color values"
+#+ * TextureSlot|LampTextureSlot.object -> object: pointer "Object to use for mapping with Object texture coordinates"
+#+ * TextureSlot|LampTextureSlot.shadow_factor -> shadow_factor: float "Amount texture affects shadow"
+#TextureSlot|LampTextureSlot.texture_coords -> texture_coords: enum "NO DESCRIPTION"
+#TextureSlot|LampTextureSlot.use_map_color -> use_map_color: boolean "Lets the texture affect the basic color of the lamp"
+#TextureSlot|LampTextureSlot.use_map_shadow -> use_map_shadow: boolean "Lets the texture affect the shadow color of the lamp"
+#+ * TextureSlot|MaterialTextureSlot.alpha_factor -> alpha_factor: float "Amount texture affects alpha"
+#+ * TextureSlot|MaterialTextureSlot.ambient_factor -> ambient_factor: float "Amount texture affects ambient"
+#TextureSlot|MaterialTextureSlot.color_emission_factor -> color_emission_factor: float "Amount texture affects emission color"
+#+ * TextureSlot|MaterialTextureSlot.density_factor -> density_factor: float "Amount texture affects density"
+#TextureSlot|MaterialTextureSlot.diffuse_color_factor -> diffuse_color_factor: float "Amount texture affects diffuse color"
+#+ * TextureSlot|MaterialTextureSlot.diffuse_factor -> diffuse_factor: float "Amount texture affects diffuse reflectivity"
+#+ * TextureSlot|MaterialTextureSlot.displacement_factor -> displacement_factor: float "Amount texture displaces the surface"
+#+ * TextureSlot|MaterialTextureSlot.emission_factor -> emission_factor: float "Amount texture affects emission"
+#+ * TextureSlot|MaterialTextureSlot.emit_factor -> emit_factor: float "Amount texture affects emission"
+#+ * TextureSlot|MaterialTextureSlot.hardness_factor -> hardness_factor: float "Amount texture affects hardness"
+#+ * TextureSlot|MaterialTextureSlot.mapping -> mapping: enum "NO DESCRIPTION"
+#TextureSlot|MaterialTextureSlot.mapping_x -> mapping_x: enum "NO DESCRIPTION"
+#TextureSlot|MaterialTextureSlot.mapping_y -> mapping_y: enum "NO DESCRIPTION"
+#TextureSlot|MaterialTextureSlot.mapping_z -> mapping_z: enum "NO DESCRIPTION"
+#+ * TextureSlot|MaterialTextureSlot.mirror_factor -> mirror_factor: float "Amount texture affects mirror color"
+#+ * TextureSlot|MaterialTextureSlot.normal_factor -> normal_factor: float "Amount texture affects normal values"
+#+ * TextureSlot|MaterialTextureSlot.normal_map_space -> normal_map_space: enum "NO DESCRIPTION"
+#+ * TextureSlot|MaterialTextureSlot.object -> object: pointer "Object to use for mapping with Object texture coordinates"
+#+ * TextureSlot|MaterialTextureSlot.raymir_factor -> raymir_factor: float "Amount texture affects ray mirror"
+#TextureSlot|MaterialTextureSlot.reflection_color_factor -> reflection_color_factor: float "Amount texture affects color of out-scattered light"
+#+ * TextureSlot|MaterialTextureSlot.reflection_factor -> reflection_factor: float "Amount texture affects brightness of out-scattered light"
+#+ * TextureSlot|MaterialTextureSlot.scattering_factor -> scattering_factor: float "Amount texture affects scattering"
+#TextureSlot|MaterialTextureSlot.specular_color_factor -> specular_color_factor: float "Amount texture affects specular color"
+#+ * TextureSlot|MaterialTextureSlot.specular_factor -> specular_factor: float "Amount texture affects specular reflectivity"
+#TextureSlot|MaterialTextureSlot.texture_coords -> texture_coords: enum "NO DESCRIPTION"
+#+ * TextureSlot|MaterialTextureSlot.translucency_factor -> translucency_factor: float "Amount texture affects translucency"
+#TextureSlot|MaterialTextureSlot.transmission_color_factor -> transmission_color_factor: float "Amount texture affects result color after light has been scattered/absorbed"
+#+ * TextureSlot|MaterialTextureSlot.use -> use: boolean "Enable this material texture slot"
+#TextureSlot|MaterialTextureSlot.use_from_dupli -> use_from_dupli: boolean "Duplis instanced from verts, faces or particles, inherit texture coordinate from their parent"
+#TextureSlot|MaterialTextureSlot.use_from_original -> use_from_original: boolean "Duplis derive their object coordinates from the original objects transformation"
+#TextureSlot|MaterialTextureSlot.use_map_alpha -> use_map_alpha: boolean "Causes the texture to affect the alpha value"
+#TextureSlot|MaterialTextureSlot.use_map_ambient -> use_map_ambient: boolean "Causes the texture to affect the value of ambient"
+#TextureSlot|MaterialTextureSlot.use_map_color_diffuse -> use_map_color_diffuse: boolean "Causes the texture to affect basic color of the material"
+#TextureSlot|MaterialTextureSlot.use_map_color_emission -> use_map_color_emission: boolean "Causes the texture to affect the color of emission"
+#TextureSlot|MaterialTextureSlot.use_map_color_reflection -> use_map_color_reflection: boolean "Causes the texture to affect the color of scattered light"
+#TextureSlot|MaterialTextureSlot.use_map_color_spec -> use_map_color_spec: boolean "Causes the texture to affect the specularity color"
+#TextureSlot|MaterialTextureSlot.use_map_color_transmission -> use_map_color_transmission: boolean "Causes the texture to affect the result color after other light has been scattered/absorbed"
+#TextureSlot|MaterialTextureSlot.use_map_density -> use_map_density: boolean "Causes the texture to affect the volumes density"
+#TextureSlot|MaterialTextureSlot.use_map_diffuse -> use_map_diffuse: boolean "Causes the texture to affect the value of the materials diffuse reflectivity"
+#TextureSlot|MaterialTextureSlot.use_map_displacement -> use_map_displacement: boolean "Let the texture displace the surface"
+#TextureSlot|MaterialTextureSlot.use_map_emission -> use_map_emission: boolean "Causes the texture to affect the volumes emission"
+#TextureSlot|MaterialTextureSlot.use_map_emit -> use_map_emit: boolean "Causes the texture to affect the emit value"
+#TextureSlot|MaterialTextureSlot.use_map_hardness -> use_map_hardness: boolean "Causes the texture to affect the hardness value"
+#TextureSlot|MaterialTextureSlot.use_map_mirror -> use_map_mirror: boolean "Causes the texture to affect the mirror color"
+#TextureSlot|MaterialTextureSlot.use_map_normal -> use_map_normal: boolean "Causes the texture to affect the rendered normal"
+#TextureSlot|MaterialTextureSlot.use_map_raymir -> use_map_raymir: boolean "Causes the texture to affect the ray-mirror value"
+#TextureSlot|MaterialTextureSlot.use_map_reflect -> use_map_reflect: boolean "Causes the texture to affect the reflected lights brightness"
+#TextureSlot|MaterialTextureSlot.use_map_scatter -> use_map_scatter: boolean "Causes the texture to affect the volumes scattering"
+#TextureSlot|MaterialTextureSlot.use_map_specular -> use_map_specular: boolean "Causes the texture to affect the value of specular reflectivity"
+#TextureSlot|MaterialTextureSlot.use_map_translucency -> use_map_translucency: boolean "Causes the texture to affect the translucency value"
+#TextureSlot|MaterialTextureSlot.use_map_warp -> use_map_warp: boolean "Let the texture warp texture coordinates of next channels"
+#TextureSlot|MaterialTextureSlot.use_old_bump -> use_old_bump: boolean "Use old bump mapping (backwards compatibility option)"
+#+ * TextureSlot|MaterialTextureSlot.uv_layer -> uv_layer: string "UV layer to use for mapping with UV texture coordinates"
+#+ * TextureSlot|MaterialTextureSlot.warp_factor -> warp_factor: float "Amount texture affects texture coordinates of next channels"
+#+ * TextureSlot|WorldTextureSlot.blend_factor -> blend_factor: float "Amount texture affects color progression of the background"
+#+ * TextureSlot|WorldTextureSlot.horizon_factor -> horizon_factor: float "Amount texture affects color of the horizon"
+#+ * TextureSlot|WorldTextureSlot.object -> object: pointer "Object to use for mapping with Object texture coordinates"
+#TextureSlot|WorldTextureSlot.texture_coords -> texture_coords: enum "Texture coordinates used to map the texture onto the background"
+#TextureSlot|WorldTextureSlot.use_map_blend -> use_map_blend: boolean "Affect the color progression of the background"
+#TextureSlot|WorldTextureSlot.use_map_horizon -> use_map_horizon: boolean "Affect the color of the horizon"
+#TextureSlot|WorldTextureSlot.use_map_zenith_down -> use_map_zenith_down: boolean "Affect the color of the zenith below"
+#TextureSlot|WorldTextureSlot.use_map_zenith_up -> use_map_zenith_up: boolean "Affect the color of the zenith above"
+#+ * TextureSlot|WorldTextureSlot.zenith_down_factor -> zenith_down_factor: float "Amount texture affects color of the zenith below"
+#+ * TextureSlot|WorldTextureSlot.zenith_up_factor -> zenith_up_factor: float "Amount texture affects color of the zenith above"
+#+ * Theme.bone_color_sets -> bone_color_sets: collection, "(read-only)"
+#+ * Theme.console -> console: pointer, "(read-only)"
+#+ * Theme.dopesheet_editor -> dopesheet_editor: pointer, "(read-only)"
+#+ * Theme.file_browser -> file_browser: pointer, "(read-only)"
+#+ * Theme.graph_editor -> graph_editor: pointer, "(read-only)"
+#+ * Theme.image_editor -> image_editor: pointer, "(read-only)"
+#+ * Theme.info -> info: pointer, "(read-only)"
+#+ * Theme.logic_editor -> logic_editor: pointer, "(read-only)"
+#+ * Theme.name -> name: string "Name of the theme"
+#+ * Theme.nla_editor -> nla_editor: pointer, "(read-only)"
+#+ * Theme.node_editor -> node_editor: pointer, "(read-only)"
+#+ * Theme.outliner -> outliner: pointer, "(read-only)"
+#+ * Theme.properties -> properties: pointer, "(read-only)"
+#+ * Theme.sequence_editor -> sequence_editor: pointer, "(read-only)"
+#+ * Theme.text_editor -> text_editor: pointer, "(read-only)"
+#+ * Theme.theme_area -> theme_area: enum "NO DESCRIPTION"
+#+ * Theme.timeline -> timeline: pointer, "(read-only)"
+#+ * Theme.user_interface -> user_interface: pointer, "(read-only)"
+#+ * Theme.user_preferences -> user_preferences: pointer, "(read-only)"
+#+ * Theme.view_3d -> view_3d: pointer, "(read-only)"
+#+ * ThemeAudioWindow.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeAudioWindow.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeAudioWindow.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeAudioWindow.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeAudioWindow.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeAudioWindow.frame_current -> frame_current: float[3] "NO DESCRIPTION"
+#+ * ThemeAudioWindow.grid -> grid: float[3] "NO DESCRIPTION"
+#+ * ThemeAudioWindow.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeAudioWindow.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeAudioWindow.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeAudioWindow.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeAudioWindow.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeAudioWindow.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeAudioWindow.window_sliders -> window_sliders: float[3] "NO DESCRIPTION"
+#+ * ThemeBoneColorSet.active -> active: float[3] "Color used for active bones"
+#+ * ThemeBoneColorSet.normal -> normal: float[3] "Color used for the surface of bones"
+#+ * ThemeBoneColorSet.select -> select: float[3] "Color used for selected bones"
+#ThemeBoneColorSet.show_colored_constraints -> show_colored_constraints: boolean "Allow the use of colors indicating constraints/keyed status"
+#+ * ThemeConsole.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeConsole.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeConsole.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeConsole.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeConsole.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeConsole.cursor -> cursor: float[3] "NO DESCRIPTION"
+#+ * ThemeConsole.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeConsole.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeConsole.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeConsole.line_error -> line_error: float[3] "NO DESCRIPTION"
+#+ * ThemeConsole.line_info -> line_info: float[3] "NO DESCRIPTION"
+#+ * ThemeConsole.line_input -> line_input: float[3] "NO DESCRIPTION"
+#+ * ThemeConsole.line_output -> line_output: float[3] "NO DESCRIPTION"
+#+ * ThemeConsole.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeConsole.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeConsole.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.active_channels_group -> active_channels_group: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.channel_group -> channel_group: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.channels -> channels: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.channels_selected -> channels_selected: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.dopesheet_channel -> dopesheet_channel: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.dopesheet_subchannel -> dopesheet_subchannel: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.frame_current -> frame_current: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.grid -> grid: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.list -> list: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.list_text -> list_text: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.list_text_hi -> list_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.list_title -> list_title: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.long_key -> long_key: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.long_key_selected -> long_key_selected: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.value_sliders -> value_sliders: float[3] "NO DESCRIPTION"
+#+ * ThemeDopeSheet.view_sliders -> view_sliders: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.active_file -> active_file: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.active_file_text -> active_file_text: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.list -> list: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.list_text -> list_text: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.list_text_hi -> list_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.list_title -> list_title: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.scroll_handle -> scroll_handle: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.scrollbar -> scrollbar: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.selected_file -> selected_file: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.tiles -> tiles: float[3] "NO DESCRIPTION"
+#+ * ThemeFileBrowser.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeFontStyle.font_kerning_style -> font_kerning_style: enum "Which style to use for font kerning"
+#+ * ThemeFontStyle.points -> points: int "NO DESCRIPTION"
+#+ * ThemeFontStyle.shadow -> shadow: int "Shadow size in pixels (0, 3 and 5 supported)"
+#ThemeFontStyle.shadow_offset_x -> shadow_offset_x: int "Shadow offset in pixels"
+#ThemeFontStyle.shadow_offset_y -> shadow_offset_y: int "Shadow offset in pixels"
+#+ * ThemeFontStyle.shadowalpha -> shadowalpha: float "NO DESCRIPTION"
+#+ * ThemeFontStyle.shadowcolor -> shadowcolor: float "Shadow color in grey value"
+#+ * ThemeGraphEditor.active_channels_group -> active_channels_group: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.channel_group -> channel_group: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.channels_region -> channels_region: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.dopesheet_channel -> dopesheet_channel: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.dopesheet_subchannel -> dopesheet_subchannel: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.frame_current -> frame_current: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.grid -> grid: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.handle_align -> handle_align: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.handle_auto -> handle_auto: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.handle_free -> handle_free: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.handle_sel_align -> handle_sel_align: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.handle_sel_auto -> handle_sel_auto: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.handle_sel_free -> handle_sel_free: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.handle_sel_vect -> handle_sel_vect: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.handle_vect -> handle_vect: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.handle_vertex -> handle_vertex: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.handle_vertex_select -> handle_vertex_select: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.handle_vertex_size -> handle_vertex_size: int "NO DESCRIPTION"
+#+ * ThemeGraphEditor.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.lastsel_point -> lastsel_point: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.list -> list: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.list_text -> list_text: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.list_text_hi -> list_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.list_title -> list_title: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.panel -> panel: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.vertex -> vertex: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.vertex_select -> vertex_select: float[3] "NO DESCRIPTION"
+#+ * ThemeGraphEditor.vertex_size -> vertex_size: int "NO DESCRIPTION"
+#+ * ThemeGraphEditor.window_sliders -> window_sliders: float[3] "NO DESCRIPTION"
+#+ * ThemeImageEditor.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeImageEditor.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeImageEditor.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeImageEditor.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeImageEditor.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeImageEditor.editmesh_active -> editmesh_active: float[4] "NO DESCRIPTION"
+#+ * ThemeImageEditor.face -> face: float[4] "NO DESCRIPTION"
+#+ * ThemeImageEditor.face_dot -> face_dot: float[3] "NO DESCRIPTION"
+#+ * ThemeImageEditor.face_select -> face_select: float[4] "NO DESCRIPTION"
+#+ * ThemeImageEditor.facedot_size -> facedot_size: int "NO DESCRIPTION"
+#+ * ThemeImageEditor.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeImageEditor.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeImageEditor.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeImageEditor.scope_back -> scope_back: float[4] "NO DESCRIPTION"
+#+ * ThemeImageEditor.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeImageEditor.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeImageEditor.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeImageEditor.vertex -> vertex: float[3] "NO DESCRIPTION"
+#+ * ThemeImageEditor.vertex_select -> vertex_select: float[3] "NO DESCRIPTION"
+#+ * ThemeImageEditor.vertex_size -> vertex_size: int "NO DESCRIPTION"
+#+ * ThemeInfo.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeInfo.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeInfo.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeInfo.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeInfo.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeInfo.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeInfo.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeInfo.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeInfo.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeInfo.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeInfo.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeLogicEditor.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeLogicEditor.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeLogicEditor.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeLogicEditor.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeLogicEditor.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeLogicEditor.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeLogicEditor.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeLogicEditor.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeLogicEditor.panel -> panel: float[3] "NO DESCRIPTION"
+#+ * ThemeLogicEditor.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeLogicEditor.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeLogicEditor.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.bars -> bars: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.bars_selected -> bars_selected: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.frame_current -> frame_current: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.grid -> grid: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.list -> list: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.list_text -> list_text: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.list_text_hi -> list_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.list_title -> list_title: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.strips -> strips: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.strips_selected -> strips_selected: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeNLAEditor.view_sliders -> view_sliders: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.converter_node -> converter_node: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.group_node -> group_node: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.in_out_node -> in_out_node: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.list -> list: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.list_text -> list_text: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.list_text_hi -> list_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.list_title -> list_title: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.node_backdrop -> node_backdrop: float[4] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.operator_node -> operator_node: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.selected_text -> selected_text: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.title -> title: float[3] "NO DESCRIPTION"
+#ThemeNodeEditor.wire -> wire: float[3] "NO DESCRIPTION"
+#+ * ThemeNodeEditor.wire_select -> wire_select: float[3] "NO DESCRIPTION"
+#+ * ThemeOutliner.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeOutliner.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeOutliner.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeOutliner.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeOutliner.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeOutliner.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeOutliner.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeOutliner.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeOutliner.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeOutliner.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeOutliner.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeProperties.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeProperties.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeProperties.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeProperties.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeProperties.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeProperties.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeProperties.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeProperties.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeProperties.panel -> panel: float[3] "NO DESCRIPTION"
+#+ * ThemeProperties.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeProperties.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeProperties.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.audio_strip -> audio_strip: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.draw_action -> draw_action: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.effect_strip -> effect_strip: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.frame_current -> frame_current: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.grid -> grid: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.image_strip -> image_strip: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.keyframe -> keyframe: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.meta_strip -> meta_strip: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.movie_strip -> movie_strip: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.plugin_strip -> plugin_strip: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.scene_strip -> scene_strip: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.transition_strip -> transition_strip: float[3] "NO DESCRIPTION"
+#+ * ThemeSequenceEditor.window_sliders -> window_sliders: float[3] "NO DESCRIPTION"
+#ThemeStyle.group_label -> group_label: pointer, "(read-only)"
+#ThemeStyle.panel_title -> panel_title: pointer, "(read-only)"
+#+ * ThemeStyle.panelzoom -> panelzoom: float "Default zoom level for panel areas"
+#+ * ThemeStyle.widget -> widget: pointer, "(read-only)"
+#ThemeStyle.widget_label -> widget_label: pointer, "(read-only)"
+#+ * ThemeTextEditor.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.cursor -> cursor: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.line_numbers_background -> line_numbers_background: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.scroll_bar -> scroll_bar: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.selected_text -> selected_text: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.syntax_builtin -> syntax_builtin: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.syntax_comment -> syntax_comment: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.syntax_numbers -> syntax_numbers: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.syntax_special -> syntax_special: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.syntax_string -> syntax_string: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeTextEditor.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeTimeline.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeTimeline.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeTimeline.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeTimeline.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeTimeline.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeTimeline.frame_current -> frame_current: float[3] "NO DESCRIPTION"
+#+ * ThemeTimeline.grid -> grid: float[3] "NO DESCRIPTION"
+#+ * ThemeTimeline.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeTimeline.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeTimeline.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeTimeline.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeTimeline.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeTimeline.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeUserInterface.icon_file -> icon_file: string "NO DESCRIPTION"
+#+ * ThemeUserInterface.wcol_box -> wcol_box: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_list_item -> wcol_list_item: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_menu -> wcol_menu: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_menu_back -> wcol_menu_back: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_menu_item -> wcol_menu_item: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_num -> wcol_num: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_numslider -> wcol_numslider: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_option -> wcol_option: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_progress -> wcol_progress: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_pulldown -> wcol_pulldown: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_radio -> wcol_radio: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_regular -> wcol_regular: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_scroll -> wcol_scroll: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_state -> wcol_state: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_text -> wcol_text: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_toggle -> wcol_toggle: pointer, "(read-only)"
+#+ * ThemeUserInterface.wcol_tool -> wcol_tool: pointer, "(read-only)"
+#+ * ThemeUserPreferences.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeUserPreferences.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeUserPreferences.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeUserPreferences.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeUserPreferences.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeUserPreferences.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeUserPreferences.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeUserPreferences.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeUserPreferences.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeUserPreferences.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeUserPreferences.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.act_spline -> act_spline: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.back -> back: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.bone_pose -> bone_pose: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.bone_solid -> bone_solid: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.button -> button: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.button_text -> button_text: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.button_text_hi -> button_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.button_title -> button_title: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.edge_crease -> edge_crease: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.edge_facesel -> edge_facesel: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.edge_seam -> edge_seam: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.edge_select -> edge_select: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.edge_sharp -> edge_sharp: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.editmesh_active -> editmesh_active: float[4] "NO DESCRIPTION"
+#+ * ThemeView3D.face -> face: float[4] "NO DESCRIPTION"
+#+ * ThemeView3D.face_dot -> face_dot: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.face_select -> face_select: float[4] "NO DESCRIPTION"
+#+ * ThemeView3D.facedot_size -> facedot_size: int "NO DESCRIPTION"
+#+ * ThemeView3D.frame_current -> frame_current: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.grid -> grid: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.handle_align -> handle_align: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.handle_auto -> handle_auto: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.handle_free -> handle_free: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.handle_sel_align -> handle_sel_align: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.handle_sel_auto -> handle_sel_auto: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.handle_sel_free -> handle_sel_free: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.handle_sel_vect -> handle_sel_vect: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.handle_vect -> handle_vect: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.header -> header: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.header_text -> header_text: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.header_text_hi -> header_text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.lamp -> lamp: float[4] "NO DESCRIPTION"
+#+ * ThemeView3D.lastsel_point -> lastsel_point: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.normal -> normal: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.nurb_sel_uline -> nurb_sel_uline: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.nurb_sel_vline -> nurb_sel_vline: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.nurb_uline -> nurb_uline: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.nurb_vline -> nurb_vline: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.object_active -> object_active: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.object_grouped -> object_grouped: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.object_grouped_active -> object_grouped_active: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.object_selected -> object_selected: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.panel -> panel: float[4] "NO DESCRIPTION"
+#+ * ThemeView3D.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.text_hi -> text_hi: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.title -> title: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.transform -> transform: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.vertex -> vertex: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.vertex_normal -> vertex_normal: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.vertex_select -> vertex_select: float[3] "NO DESCRIPTION"
+#+ * ThemeView3D.vertex_size -> vertex_size: int "NO DESCRIPTION"
+#+ * ThemeView3D.wire -> wire: float[3] "NO DESCRIPTION"
+#+ * ThemeWidgetColors.inner -> inner: float[4] "NO DESCRIPTION"
+#+ * ThemeWidgetColors.inner_sel -> inner_sel: float[4] "NO DESCRIPTION"
+#+ * ThemeWidgetColors.item -> item: float[4] "NO DESCRIPTION"
+#+ * ThemeWidgetColors.outline -> outline: float[3] "NO DESCRIPTION"
+#+ * ThemeWidgetColors.shadedown -> shadedown: int "NO DESCRIPTION"
+#+ * ThemeWidgetColors.shadetop -> shadetop: int "NO DESCRIPTION"
+#ThemeWidgetColors.show_shaded -> show_shaded: boolean "NO DESCRIPTION"
+#+ * ThemeWidgetColors.text -> text: float[3] "NO DESCRIPTION"
+#+ * ThemeWidgetColors.text_sel -> text_sel: float[3] "NO DESCRIPTION"
+#+ * ThemeWidgetStateColors.blend -> blend: float "NO DESCRIPTION"
+#+ * ThemeWidgetStateColors.inner_anim -> inner_anim: float[3] "NO DESCRIPTION"
+#+ * ThemeWidgetStateColors.inner_anim_sel -> inner_anim_sel: float[3] "NO DESCRIPTION"
+#+ * ThemeWidgetStateColors.inner_driven -> inner_driven: float[3] "NO DESCRIPTION"
+#+ * ThemeWidgetStateColors.inner_driven_sel -> inner_driven_sel: float[3] "NO DESCRIPTION"
+#+ * ThemeWidgetStateColors.inner_key -> inner_key: float[3] "NO DESCRIPTION"
+#+ * ThemeWidgetStateColors.inner_key_sel -> inner_key_sel: float[3] "NO DESCRIPTION"
+#+ * TimelineMarker.camera -> camera: pointer "Camera this timeline sets to active"
+#+ * TimelineMarker.frame -> frame: int "The frame on which the timeline marker appears"
+#+ * TimelineMarker.name -> name: string "NO DESCRIPTION"
+#+ * TimelineMarker.select -> select: boolean "Marker selection state"
+#ToolSettings.auto_keying_mode -> auto_keying_mode: enum "Mode of automatic keyframe insertion for Objects and Bones"
+#+ * ToolSettings.edge_path_mode -> edge_path_mode: enum "The edge flag to tag when selecting the shortest path"
+#+ * ToolSettings.etch_adaptive_limit -> etch_adaptive_limit: float "Number of bones in the subdivided stroke"
+#+ * ToolSettings.etch_convert_mode -> etch_convert_mode: enum "Method used to convert stroke to bones"
+#+ * ToolSettings.etch_length_limit -> etch_length_limit: float "Number of bones in the subdivided stroke"
+#+ * ToolSettings.etch_number -> etch_number: string "DOC BROKEN"
+#+ * ToolSettings.etch_roll_mode -> etch_roll_mode: enum "Method used to adjust the roll of bones when retargeting"
+#+ * ToolSettings.etch_side -> etch_side: string "DOC BROKEN"
+#+ * ToolSettings.etch_subdivision_number -> etch_subdivision_number: int "Number of bones in the subdivided stroke"
+#+ * ToolSettings.etch_template -> etch_template: pointer "Template armature that will be retargeted to the stroke"
+#+ * ToolSettings.image_paint -> image_paint: pointer, "(read-only)"
+#ToolSettings.mesh_select_mode -> mesh_select_mode: boolean[3] "Which mesh elements selection works on"
+#+ * ToolSettings.normal_size -> normal_size: float "Display size for normals in the 3D view"
+#+ * ToolSettings.particle_edit -> particle_edit: pointer, "(read-only)"
+#ToolSettings.proportional_edit -> proportional_edit: enum "Proportional editing mode"
+#ToolSettings.proportional_edit_falloff -> proportional_edit_falloff: enum "Falloff type for proportional editing mode"
+#+ * ToolSettings.sculpt -> sculpt: pointer, "(read-only)"
+#+ * ToolSettings.sculpt_paint_use_unified_size -> sculpt_paint_use_unified_size: boolean "Instead of per brush radius, the radius is shared across brushes"
+#+ * ToolSettings.sculpt_paint_use_unified_strength -> sculpt_paint_use_unified_strength: boolean "Instead of per brush strength, the strength is shared across brushes"
+#ToolSettings.show_uv_local_view -> show_uv_local_view: boolean "Draw only faces with the currently displayed image assigned"
+#+ * ToolSettings.snap_element -> snap_element: enum "Type of element to snap to"
+#+ * ToolSettings.snap_target -> snap_target: enum "Which part to snap onto the target"
+#ToolSettings.use_auto_normalize -> use_auto_normalize: boolean "Ensure all bone-deforming vertex groups add up to 1.0 while weight painting"
+#ToolSettings.use_bone_sketching -> use_bone_sketching: boolean "DOC BROKEN"
+#ToolSettings.use_etch_autoname -> use_etch_autoname: boolean "DOC BROKEN"
+#ToolSettings.use_etch_overdraw -> use_etch_overdraw: boolean "DOC BROKEN"
+#ToolSettings.use_etch_quick -> use_etch_quick: boolean "DOC BROKEN"
+#ToolSettings.use_keyframe_insert_auto -> use_keyframe_insert_auto: boolean "Automatic keyframe insertion for Objects and Bones"
+#ToolSettings.use_mesh_automerge -> use_mesh_automerge: boolean "Automatically merge vertices moved to the same location"
+#ToolSettings.use_proportional_edit_objects -> use_proportional_edit_objects: boolean "Proportional editing object mode"
+#ToolSettings.use_record_with_nla -> use_record_with_nla: boolean "Add a new NLA Track + Strip for every loop/pass made over the animation to allow non-destructive tweaking"
+#ToolSettings.use_snap -> use_snap: boolean "Snap during transform"
+#ToolSettings.use_snap_align_rotation -> use_snap_align_rotation: boolean "Align rotation with the snapping target"
+#ToolSettings.use_snap_peel_object -> use_snap_peel_object: boolean "Consider objects as whole when finding volume center"
+#ToolSettings.use_snap_project -> use_snap_project: boolean "Project vertices on the surface of other objects"
+#ToolSettings.use_uv_select_sync -> use_uv_select_sync: boolean "Keep UV and edit mode mesh selection in sync"
+#ToolSettings.uv_select_mode -> uv_select_mode: enum "UV selection and display mode"
+#+ * ToolSettings.vertex_group_weight -> vertex_group_weight: float "Weight to assign in vertex groups"
+#+ * ToolSettings.vertex_paint -> vertex_paint: pointer, "(read-only)"
+#+ * ToolSettings.weight_paint -> weight_paint: pointer, "(read-only)"
+#+ * TransformOrientation.matrix -> matrix: float[9] "NO DESCRIPTION"
+#+ * TransformOrientation.name -> name: string "NO DESCRIPTION"
+#+ * UILayout.alignment -> alignment: enum "NO DESCRIPTION"
+#+ * UILayout.operator_context -> operator_context: enum "NO DESCRIPTION"
+#+ * UILayout.scale_x -> scale_x: float "Scale factor along the X for items in this (sub)layout."
+#+ * UILayout.scale_y -> scale_y: float "Scale factor along the Y for items in this (sub)layout."
+ + * UILayout.active -> show_active: boolean "NO DESCRIPTION"
+ + * UILayout.enabled -> show_enabled: boolean "When false, this (sub)layout is greyed out."
+#+ * UVProjector.object -> object: pointer "Object to use as projector transform"
+#UVTextures.active -> active: pointer "Active UV texture"
+#+ * UnitSettings.rotation_units -> rotation_units: enum "Unit to use for displaying/editing rotation values"
+#+ * UnitSettings.scale_length -> scale_length: float "Scale to use when converting between blender units and dimensions"
+#+ * UnitSettings.system -> system: enum "The unit system to use for button display"
+#+ * UnitSettings.use_separate -> use_separate: boolean "Display units in pairs"
+#+ * UserPreferences.active_section -> active_section: enum "Active section of the user preferences shown in the user interface"
+#+ * UserPreferences.addons -> addons: collection, "(read-only)"
+#+ * UserPreferences.edit -> edit: pointer, "(read-only) Settings for interacting with Blender data"
+#+ * UserPreferences.filepaths -> filepaths: pointer, "(read-only) Default paths for external files"
+#+ * UserPreferences.inputs -> inputs: pointer, "(read-only) Settings for input devices"
+#+ * UserPreferences.system -> system: pointer, "(read-only) Graphics driver and operating system settings"
+#+ * UserPreferences.themes -> themes: collection, "(read-only)"
+#UserPreferences.ui_styles -> ui_styles: collection, "(read-only)"
+#+ * UserPreferences.view -> view: pointer, "(read-only) Preferences related to viewing data"
+#+ * UserPreferencesEdit.auto_keying_mode -> auto_keying_mode: enum "Mode of automatic keyframe insertion for Objects and Bones"
+#+ * UserPreferencesEdit.grease_pencil_eraser_radius -> grease_pencil_eraser_radius: int "Radius of eraser brush"
+#+ * UserPreferencesEdit.grease_pencil_euclidean_distance -> grease_pencil_euclidean_distance: int "Distance moved by mouse when drawing stroke (in pixels) to include"
+#+ * UserPreferencesEdit.grease_pencil_manhattan_distance -> grease_pencil_manhattan_distance: int "Pixels moved by mouse per axis when drawing stroke"
+#+ * UserPreferencesEdit.keyframe_new_handle_type -> keyframe_new_handle_type: enum "NO DESCRIPTION"
+#+ * UserPreferencesEdit.keyframe_new_interpolation_type -> keyframe_new_interpolation_type: enum "NO DESCRIPTION"
+#+ * UserPreferencesEdit.material_link -> material_link: enum "Toggle whether the material is linked to object data or the object block"
+#+ * UserPreferencesEdit.object_align -> object_align: enum "When adding objects from a 3D View menu, either align them to that views direction or the world coordinates"
+#UserPreferencesEdit.sculpt_paint_overlay_color -> sculpt_paint_overlay_color: float[3] "Color of texture overlay"
+#+ * UserPreferencesEdit.undo_memory_limit -> undo_memory_limit: int "Maximum memory usage in megabytes (0 means unlimited)"
+#+ * UserPreferencesEdit.undo_steps -> undo_steps: int "Number of undo steps available (smaller values conserve memory)"
+#+ * UserPreferencesEdit.use_auto_keying -> use_auto_keying: boolean "Automatic keyframe insertion for Objects and Bones"
+#UserPreferencesEdit.use_drag_immediately -> use_drag_immediately: boolean "Moving things with a mouse drag confirms when releasing the button"
+#UserPreferencesEdit.use_duplicate_action -> use_duplicate_action: boolean "Causes actions to be duplicated with the object"
+#UserPreferencesEdit.use_duplicate_armature -> use_duplicate_armature: boolean "Causes armature data to be duplicated with the object"
+#UserPreferencesEdit.use_duplicate_curve -> use_duplicate_curve: boolean "Causes curve data to be duplicated with the object"
+#UserPreferencesEdit.use_duplicate_fcurve -> use_duplicate_fcurve: boolean "Causes F-curve data to be duplicated with the object"
+#UserPreferencesEdit.use_duplicate_lamp -> use_duplicate_lamp: boolean "Causes lamp data to be duplicated with the object"
+#UserPreferencesEdit.use_duplicate_material -> use_duplicate_material: boolean "Causes material data to be duplicated with the object"
+#UserPreferencesEdit.use_duplicate_mesh -> use_duplicate_mesh: boolean "Causes mesh data to be duplicated with the object"
+#UserPreferencesEdit.use_duplicate_metaball -> use_duplicate_metaball: boolean "Causes metaball data to be duplicated with the object"
+#UserPreferencesEdit.use_duplicate_particle -> use_duplicate_particle: boolean "Causes particle systems to be duplicated with the object"
+#UserPreferencesEdit.use_duplicate_surface -> use_duplicate_surface: boolean "Causes surface data to be duplicated with the object"
+#UserPreferencesEdit.use_duplicate_text -> use_duplicate_text: boolean "Causes text data to be duplicated with the object"
+#UserPreferencesEdit.use_duplicate_texture -> use_duplicate_texture: boolean "Causes texture data to be duplicated with the object"
+#UserPreferencesEdit.use_enter_edit_mode -> use_enter_edit_mode: boolean "Enter Edit Mode automatically after adding a new object"
+#UserPreferencesEdit.use_global_undo -> use_global_undo: boolean "Global undo works by keeping a full copy of the file itself in memory, so takes extra memory"
+#UserPreferencesEdit.use_grease_pencil_simplify_stroke -> use_grease_pencil_simplify_stroke: boolean "Simplify the final stroke"
+#UserPreferencesEdit.use_grease_pencil_smooth_stroke -> use_grease_pencil_smooth_stroke: boolean "Smooth the final stroke"
+#UserPreferencesEdit.use_insertkey_xyz_to_rgb -> use_insertkey_xyz_to_rgb: boolean "Color for newly added transformation F-Curves (Location, Rotation, Scale) and also Color is based on the transform axis"
+#UserPreferencesEdit.use_keyframe_insert_available -> use_keyframe_insert_available: boolean "Automatic keyframe insertion in available curves"
+#UserPreferencesEdit.use_keyframe_insert_keyingset -> use_keyframe_insert_keyingset: boolean "Automatic keyframe insertion using active Keying Set"
+#UserPreferencesEdit.use_keyframe_insert_needed -> use_keyframe_insert_needed: boolean "Keyframe insertion only when keyframe needed"
+#+ * UserPreferencesEdit.use_negative_frames -> use_negative_frames: boolean "Current frame number can be manually set to a negative value"
+#+ * UserPreferencesEdit.use_visual_keying -> use_visual_keying: boolean "Use Visual keying automatically for constrained objects"
+#+ * UserPreferencesFilePaths.animation_player -> animation_player: string "Path to a custom animation/frame sequence player"
+#+ * UserPreferencesFilePaths.animation_player_preset -> animation_player_preset: enum "Preset configs for external animation players"
+#+ * UserPreferencesFilePaths.auto_save_time -> auto_save_time: int "The time (in minutes) to wait between automatic temporary saves"
+#UserPreferencesFilePaths.font_directory -> font_directory: string "The default directory to search for loading fonts"
+#+ * UserPreferencesFilePaths.image_editor -> image_editor: string "Path to an image editor"
+#+ * UserPreferencesFilePaths.recent_files -> recent_files: int "Maximum number of recently opened files to remember"
+#+ * UserPreferencesFilePaths.render_output_directory -> render_output_directory: string "The default directory for rendering output"
+#+ * UserPreferencesFilePaths.save_version -> save_version: int "The number of old versions to maintain in the current directory, when manually saving"
+#UserPreferencesFilePaths.script_directory -> script_directory: string "The default directory to search for Python scripts (resets python module search path: sys.path)"
+#+ * UserPreferencesFilePaths.sequence_plugin_directory -> sequence_plugin_directory: string "The default directory to search for sequence plugins"
+#UserPreferencesFilePaths.show_hidden_files_datablocks -> show_hidden_files_datablocks: boolean "Hide files/datablocks that start with a dot(.*)"
+#UserPreferencesFilePaths.sound_directory -> sound_directory: string "The default directory to search for sounds"
+#+ * UserPreferencesFilePaths.temporary_directory -> temporary_directory: string "The directory for storing temporary save files"
+#UserPreferencesFilePaths.texture_directory -> texture_directory: string "The default directory to search for textures"
+#+ * UserPreferencesFilePaths.texture_plugin_directory -> texture_plugin_directory: string "The default directory to search for texture plugins"
+#UserPreferencesFilePaths.use_auto_save_temporary_files -> use_auto_save_temporary_files: boolean "Automatic saving of temporary files"
+#UserPreferencesFilePaths.use_file_compression -> use_file_compression: boolean "Enable file compression when saving .blend files"
+#UserPreferencesFilePaths.use_filter_files -> use_filter_files: boolean "Display only files with extensions in the image select window"
+#UserPreferencesFilePaths.use_load_ui -> use_load_ui: boolean "Load user interface setup when loading .blend files"
+#+ * UserPreferencesFilePaths.use_relative_paths -> use_relative_paths: boolean "Default relative path option for the file selector"
+#UserPreferencesFilePaths.use_save_preview_images -> use_save_preview_images: boolean "Enables automatic saving of preview images in the .blend file"
+#+ * UserPreferencesInput.edited_keymaps -> edited_keymaps: collection, "(read-only)"
+#UserPreferencesInput.invert_mouse_wheel_zoom -> invert_mouse_wheel_zoom: boolean "Invert the axis of mouse movement for zooming"
+#UserPreferencesInput.invert_zoom_wheel -> invert_zoom_wheel: boolean "Swap the Mouse Wheel zoom direction"
+#UserPreferencesInput.mouse_double_click_time -> mouse_double_click_time: int "The time (in ms) for a double click"
+#+ * UserPreferencesInput.ndof_pan_speed -> ndof_pan_speed: int "The overall panning speed of an NDOF device, as percent of standard"
+#+ * UserPreferencesInput.ndof_rotate_speed -> ndof_rotate_speed: int "The overall rotation speed of an NDOF device, as percent of standard"
+#+ * UserPreferencesInput.select_mouse -> select_mouse: enum "The mouse button used for selection"
+#UserPreferencesInput.use_emulate_numpad -> use_emulate_numpad: boolean "Causes the 1 to 0 keys to act as the numpad (useful for laptops)"
+#UserPreferencesInput.use_mouse_continuous -> use_mouse_continuous: boolean "Allow moving the mouse outside the view on some manipulations (transform, ui control drag)"
+#UserPreferencesInput.use_mouse_emulate_3_button -> use_mouse_emulate_3_button: boolean "Emulates Middle Mouse with Alt+LeftMouse (doesnt work with Left Mouse Select option)"
+#UserPreferencesInput.use_mouse_mmb_paste -> use_mouse_mmb_paste: boolean "In text window, paste with middle mouse button instead of panning"
+#UserPreferencesInput.view_rotate_method -> view_rotate_method: enum "Rotation style in the viewport"
+#UserPreferencesInput.view_zoom_axis -> view_zoom_axis: enum "Axis of mouse movement to zoom in or out on"
+#UserPreferencesInput.view_zoom_method -> view_zoom_method: enum "Which style to use for viewport scaling"
+#+ * UserPreferencesInput.wheel_scroll_lines -> wheel_scroll_lines: int "The number of lines scrolled at a time with the mouse wheel"
+#+ * UserPreferencesSystem.audio_channels -> audio_channels: enum "Sets the audio channel count"
+#+ * UserPreferencesSystem.audio_device -> audio_device: enum "Sets the audio output device"
+#+ * UserPreferencesSystem.audio_mixing_buffer -> audio_mixing_buffer: enum "Sets the number of samples used by the audio mixing buffer"
+#+ * UserPreferencesSystem.audio_sample_format -> audio_sample_format: enum "Sets the audio sample format"
+#+ * UserPreferencesSystem.audio_sample_rate -> audio_sample_rate: enum "Sets the audio sample rate"
+#+ * UserPreferencesSystem.color_picker_type -> color_picker_type: enum "Different styles of displaying the color picker widget"
+#+ * UserPreferencesSystem.dpi -> dpi: int "Font size and resolution for display"
+#+ * UserPreferencesSystem.frame_server_port -> frame_server_port: int "Frameserver Port for Frameserver Rendering"
+#UserPreferencesSystem.gl_clip_alpha -> gl_clip_alpha: float "Clip alpha below this threshold in the 3D textured view"
+#+ * UserPreferencesSystem.gl_texture_limit -> gl_texture_limit: enum "Limit the texture size to save graphics memory"
+#+ * UserPreferencesSystem.language -> language: enum "Language use for translation"
+#+ * UserPreferencesSystem.memory_cache_limit -> memory_cache_limit: int "Memory cache limit in sequencer (megabytes)"
+#+ * UserPreferencesSystem.prefetch_frames -> prefetch_frames: int "Number of frames to render ahead during playback"
+#+ * UserPreferencesSystem.screencast_fps -> screencast_fps: int "Frame rate for the screencast to be played back"
+#+ * UserPreferencesSystem.screencast_wait_time -> screencast_wait_time: int "Time in milliseconds between each frame recorded for screencast"
+#+ * UserPreferencesSystem.scrollback -> scrollback: int "Maximum number of lines to store for the console buffer"
+#+ * UserPreferencesSystem.solid_lights -> solid_lights: collection, "(read-only) Lights user to display objects in solid draw mode"
+#+ * UserPreferencesSystem.texture_collection_rate -> texture_collection_rate: int "Number of seconds between each run of the GL texture garbage collector"
+#+ * UserPreferencesSystem.texture_time_out -> texture_time_out: int "Time since last access of a GL texture in seconds after which it is freed. (Set to 0 to keep textures allocated.)"
+#+ * UserPreferencesSystem.use_antialiasing -> use_antialiasing: boolean "Use anti-aliasing for the 3D view (may impact redraw performance)"
+#UserPreferencesSystem.use_international_fonts -> use_international_fonts: boolean "Use international fonts"
+#+ * UserPreferencesSystem.use_mipmaps -> use_mipmaps: boolean "Scale textures for the 3D View (looks nicer but uses more memory and slows image reloading)"
+#UserPreferencesSystem.use_preview_images -> use_preview_images: boolean "Enables automatic saving of preview images in the .blend file (Windows only)"
+#UserPreferencesSystem.use_scripts_auto_execute -> use_scripts_auto_execute: boolean "Allow any .blend file to run scripts automatically (unsafe with blend files from an untrusted source)"
+#UserPreferencesSystem.use_tabs_as_spaces -> use_tabs_as_spaces: boolean "Automatically converts all new tabs into spaces for new and loaded text files"
+#+ * UserPreferencesSystem.use_textured_fonts -> use_textured_fonts: boolean "Use textures for drawing international fonts"
+#UserPreferencesSystem.use_translate_buttons -> use_translate_buttons: boolean "Translate button labels"
+#UserPreferencesSystem.use_translate_toolbox -> use_translate_toolbox: boolean "Translate toolbox menu"
+#UserPreferencesSystem.use_translate_tooltips -> use_translate_tooltips: boolean "Translate Tooltips"
+#UserPreferencesSystem.use_vertex_buffer_objects -> use_vertex_buffer_objects: boolean "Use Vertex Buffer Objects (or Vertex Arrays, if unsupported) for viewport rendering"
+#+ * UserPreferencesSystem.use_weight_color_range -> use_weight_color_range: boolean "Enable color range used for weight visualization in weight painting mode"
+#+ * UserPreferencesSystem.weight_color_range -> weight_color_range: pointer, "(read-only) Color range used for weight visualization in weight painting mode"
+#+ * UserPreferencesSystem.window_draw_method -> window_draw_method: enum "Drawing method used by the window manager"
+#+ * UserPreferencesView.manipulator_handle_size -> manipulator_handle_size: int "Size of widget handles as percentage of widget radius"
+#+ * UserPreferencesView.manipulator_hotspot -> manipulator_hotspot: int "Hotspot in pixels for clicking widget handles"
+#+ * UserPreferencesView.manipulator_size -> manipulator_size: int "Diameter of widget, in 10 pixel units"
+#+ * UserPreferencesView.mini_axis_brightness -> mini_axis_brightness: int "The brightness of the icon"
+#+ * UserPreferencesView.mini_axis_size -> mini_axis_size: int "The axis icons size"
+#+ * UserPreferencesView.object_origin_size -> object_origin_size: int "Diameter in Pixels for Object/Lamp origin display"
+#+ * UserPreferencesView.open_left_mouse_delay -> open_left_mouse_delay: int "Time in 1/10 seconds to hold the Left Mouse Button before opening the toolbox"
+#+ * UserPreferencesView.open_right_mouse_delay -> open_right_mouse_delay: int "Time in 1/10 seconds to hold the Right Mouse Button before opening the toolbox"
+#+ * UserPreferencesView.open_sublevel_delay -> open_sublevel_delay: int "Time delay in 1/10 seconds before automatically opening sub level menus"
+#+ * UserPreferencesView.open_toplevel_delay -> open_toplevel_delay: int "Time delay in 1/10 seconds before automatically opening top level menus"
+#+ * UserPreferencesView.rotation_angle -> rotation_angle: int "The rotation step for numerical pad keys (2 4 6 8)"
+#UserPreferencesView.show_column_layout -> show_column_layout: boolean "Use a column layout for toolbox"
+#UserPreferencesView.show_large_cursors -> show_large_cursors: boolean "Use large mouse cursors when available"
+#UserPreferencesView.show_manipulator -> show_manipulator: boolean "Use 3D transform manipulator"
+#+ * UserPreferencesView.show_mini_axis -> show_mini_axis: boolean "Show a small rotating 3D axis in the bottom left corner of the 3D View"
+#UserPreferencesView.show_object_info -> show_object_info: boolean "Display objects name and frame number in 3D view"
+#+ * UserPreferencesView.show_playback_fps -> show_playback_fps: boolean "Show the frames per second screen refresh rate, while animation is played back"
+#+ * UserPreferencesView.show_splash -> show_splash: boolean "Display splash screen on startup"
+#UserPreferencesView.show_tooltips -> show_tooltips: boolean "Display tooltips"
+#+ * UserPreferencesView.show_view_name -> show_view_name: boolean "Show the name of the views direction in each 3D View"
+#+ * UserPreferencesView.smooth_view -> smooth_view: int "The time to animate the view in milliseconds, zero to disable"
+#+ * UserPreferencesView.timecode_style -> timecode_style: enum "Format of Time Codes displayed when not displaying timing in terms of frames"
+#UserPreferencesView.use_auto_perspective -> use_auto_perspective: boolean "Automatically switch between orthographic and perspective when changing from top/front/side views"
+#UserPreferencesView.use_directional_menus -> use_directional_menus: boolean "Otherwise menus, etc will always be top to bottom, left to right, no matter opening direction"
+#UserPreferencesView.use_global_pivot -> use_global_pivot: boolean "Lock the same rotation/scaling pivot in all 3D Views"
+#UserPreferencesView.use_global_scene -> use_global_scene: boolean "Forces the current Scene to be displayed in all Screens"
+#UserPreferencesView.use_mouse_auto_depth -> use_mouse_auto_depth: boolean "Use the depth under the mouse to improve view pan/rotate/zoom functionality"
+#UserPreferencesView.use_mouse_over_open -> use_mouse_over_open: boolean "Open menu buttons and pulldowns automatically when the mouse is hovering"
+#UserPreferencesView.use_rotate_around_active -> use_rotate_around_active: boolean "Use selection as the pivot point"
+#UserPreferencesView.use_zoom_to_mouse -> use_zoom_to_mouse: boolean "Zoom in towards the mouse pointers position in the 3D view, rather than the 2D window center"
+#UserPreferencesView.view2d_grid_spacing_min -> view2d_grid_spacing_min: int "Minimum number of pixels between each gridline in 2D Viewports"
+#+ * UserSolidLight.diffuse_color -> diffuse_color: float[3] "The diffuse color of the OpenGL light"
+#+ * UserSolidLight.direction -> direction: float[3] "The direction that the OpenGL light is shining"
+#+ * UserSolidLight.specular_color -> specular_color: float[3] "The color of the lights specular highlight"
+#+ * UserSolidLight.use -> use: boolean "Enable this OpenGL light in solid draw mode"
+#+ * ValueNodeSocket.default_value -> default_value: float[1] "Default value of the socket when no link is attached"
+#+ * ValueNodeSocket.name -> name: string, "(read-only) Socket name"
+#+ * VectorNodeSocket.default_value -> default_value: float[3] "Default value of the socket when no link is attached"
+#+ * VectorNodeSocket.name -> name: string, "(read-only) Socket name"
+#VertexColors.active -> active: pointer "Active vertex color layer"
+#+ * VertexGroup.index -> index: int, "(read-only) Index number of the vertex group"
+#+ * VertexGroup.name -> name: string "Vertex group name"
+#+ * VertexGroupElement.group -> group: int, "(read-only)"
+#+ * VertexGroupElement.weight -> weight: float "Vertex Weight"
+#+ * VoxelData.domain_object -> domain_object: pointer "Object used as the smoke simulation domain"
+#+ * VoxelData.extension -> extension: enum "Sets how the texture is extrapolated past its original bounds"
+#+ * VoxelData.file_format -> file_format: enum "Format of the source data set to render"
+#VoxelData.filepath -> filepath: string "The external source data file to use"
+#+ * VoxelData.intensity -> intensity: float "Multiplier for intensity values"
+#+ * VoxelData.interpolation -> interpolation: enum "Method to interpolate/smooth values between voxel cells"
+#+ * VoxelData.resolution -> resolution: int[3] "Resolution of the voxel grid"
+#+ * VoxelData.smoke_data_type -> smoke_data_type: enum "Simulation value to be used as a texture"
+#VoxelData.still_frame -> still_frame: int "The frame number to always use"
+#VoxelData.use_still_frame -> use_still_frame: boolean "Always render a still frame from the voxel data sequence"
+#+ * Window.screen -> screen: pointer "Active screen showing in the window"
+#+ * WorldLighting.adapt_to_speed -> adapt_to_speed: float "Use the speed vector pass to reduce AO samples in fast moving pixels. Higher values result in more aggressive sample reduction. Requires Vec pass enabled (for Raytrace Adaptive QMC)"
+#WorldLighting.ao_blend_type -> ao_blend_type: enum "Defines how AO mixes with material shading"
+#+ * WorldLighting.ao_factor -> ao_factor: float "Factor for ambient occlusion blending"
+#+ * WorldLighting.bias -> bias: float "Bias (in radians) to prevent smoothed faces from showing banding (for Raytrace Constant Jittered)"
+#+ * WorldLighting.correction -> correction: float "Ad-hoc correction for over-occlusion due to the approximation (for Approximate)"
+#+ * WorldLighting.distance -> distance: float "Length of rays, defines how far away other faces give occlusion effect"
+#+ * WorldLighting.environment_color -> environment_color: enum "Defines where the color of the environment light comes from"
+#+ * WorldLighting.environment_energy -> environment_energy: float "Defines the strength of environment light"
+#WorldLighting.error_threshold -> error_threshold: float "Low values are slower and higher quality (for Approximate)"
+#+ * WorldLighting.falloff_strength -> falloff_strength: float "Distance attenuation factor, the higher, the shorter the shadows"
+#+ * WorldLighting.gather_method -> gather_method: enum "NO DESCRIPTION"
+#+ * WorldLighting.indirect_bounces -> indirect_bounces: int "Number of indirect diffuse light bounces to use for approximate ambient occlusion"
+#+ * WorldLighting.indirect_factor -> indirect_factor: float "Factor for how much surrounding objects contribute to light"
+#+ * WorldLighting.passes -> passes: int "Number of preprocessing passes to reduce overocclusion (for approximate ambient occlusion)"
+#+ * WorldLighting.sample_method -> sample_method: enum "Method for generating shadow samples (for Raytrace)"
+#+ * WorldLighting.samples -> samples: int "Amount of ray samples. Higher values give smoother results and longer rendering times"
+#+ * WorldLighting.threshold -> threshold: float "Samples below this threshold will be considered fully shadowed/unshadowed and skipped (for Raytrace Adaptive QMC)"
+#+ * WorldLighting.use_ambient_occlusion -> use_ambient_occlusion: boolean "Use Ambient Occlusion to add shadowing based on distance between objects"
+#WorldLighting.use_cache -> use_cache: boolean "Cache AO results in pixels and interpolate over neighbouring pixels for speedup (for Approximate)"
+#WorldLighting.use_environment_light -> use_environment_light: boolean "Add light coming from the environment"
+#WorldLighting.use_falloff -> use_falloff: boolean "NO DESCRIPTION"
+#WorldLighting.use_indirect_light -> use_indirect_light: boolean "Add indirect light bouncing of surrounding objects"
+#+ * WorldMistSettings.depth -> depth: float "The distance over which the mist effect fades in"
+#+ * WorldMistSettings.falloff -> falloff: enum "Type of transition used to fade mist"
+#+ * WorldMistSettings.height -> height: float "Control how much mist density decreases with height"
+#+ * WorldMistSettings.intensity -> intensity: float "Intensity of the mist effect"
+#+ * WorldMistSettings.start -> start: float "Starting distance of the mist, measured from the camera"
+#+ * WorldMistSettings.use_mist -> use_mist: boolean "Occlude objects with the environment color as they are further away"
+#+ * WorldStarsSettings.average_separation -> average_separation: float "Average distance between any two stars"
+#WorldStarsSettings.color_random -> color_random: float "Randomize star colors"
+#WorldStarsSettings.distance_min -> distance_min: float "Minimum distance to the camera for stars"
+#+ * WorldStarsSettings.size -> size: float "Average screen dimension of stars"
+#+ * WorldStarsSettings.use_stars -> use_stars: boolean "Enable starfield generation"
+=======
# See svn history for example formatting for this file, currently this isnt in use.
+>>>>>>> .merge-right.r35190
diff --git a/source/blender/makesrna/rna_cleanup/rna_update.sh b/source/blender/makesrna/rna_cleanup/rna_update.sh
index a4d686cc482..a35ad6ef6c3 100755
--- a/source/blender/makesrna/rna_cleanup/rna_update.sh
+++ b/source/blender/makesrna/rna_cleanup/rna_update.sh
@@ -1,3 +1,4 @@
+<<<<<<< .working
cd ../../../../
./blender.bin --background --python ./release/scripts/modules/rna_info.py 2> source/blender/makesrna/rna_cleanup/out.txt
cd ./source/blender/makesrna/rna_cleanup/
@@ -11,3 +12,18 @@ mv out_work_lost_work.txt rna_properties_lost.txt
cat rna_properties.txt | grep -v "^#" > rna_properties_edits.txt
./rna_cleaner.py rna_properties.txt
echo "Updated: rna_properties.txt rna_properties_edits.txt rna_properties_lost.txt "
+=======
+cd ../../../../
+./blender.bin --background --python ./release/scripts/modules/rna_info.py 2> source/blender/makesrna/rna_cleanup/out.txt
+cd ./source/blender/makesrna/rna_cleanup/
+./rna_cleaner.py out.txt
+./rna_cleaner.py rna_properties.txt
+./rna_cleaner_merge.py out_work.py rna_properties_work.py
+./rna_cleaner.py out_work_merged.py
+./rna_cleaner.py out_work_lost.py
+mv out_work_merged_work.txt rna_properties.txt # overwrite
+mv out_work_lost_work.txt rna_properties_lost.txt
+cat rna_properties.txt | grep -v "^#" > rna_properties_edits.txt
+./rna_cleaner.py rna_properties.txt
+echo "Updated: rna_properties.txt rna_properties_edits.txt rna_properties_lost.txt "
+>>>>>>> .merge-right.r35190
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index c610a2fbdda..0352aa8c05f 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../makesdna
../blenkernel
../blenkernel/intern
+ ../bmesh
../render/extern/include
../../../intern/guardedalloc
../../../intern/elbeem/extern
diff --git a/source/blender/modifiers/SConscript b/source/blender/modifiers/SConscript
index d1bb95761ff..c4196222ec8 100644
--- a/source/blender/modifiers/SConscript
+++ b/source/blender/modifiers/SConscript
@@ -5,7 +5,11 @@ sources = env.Glob('intern/*.c')
incs = '. ./intern'
incs += ' #/intern/guardedalloc #/intern/decimation/extern #/intern/bsp/extern #/intern/elbeem/extern'
+<<<<<<< .working
+incs += ' ../render/extern/include ../bmesh'
+=======
incs += ' ../render/extern/include ../blenloader'
+>>>>>>> .merge-right.r35190
incs += ' ../include ../blenlib ../makesdna ../blenkernel ../blenkernel/intern'
incs += ' ' + env['BF_ZLIB_INC']
@@ -21,4 +25,8 @@ if env['BF_NO_ELBEEM']:
env.BlenderLib ( libname = 'bf_modifiers', sources = sources,
includes = Split(incs), defines=defs,
+<<<<<<< .working
+ libtype=['core','player'], priority = [161, 20] )
+=======
libtype=['core','player'], priority = [80, 40] )
+>>>>>>> .merge-right.r35190
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 0a8caee5241..f5a276aeadc 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -30,19 +30,14 @@
*
*/
-/** \file blender/modifiers/intern/MOD_array.c
- * \ingroup modifiers
- */
-
-
/* Array modifier: duplicates the object multiple times along an axis */
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
-#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_edgehash.h"
+#include "BLI_utildefines.h"
#include "DNA_curve_types.h"
#include "DNA_meshdata_types.h"
@@ -53,10 +48,13 @@
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
+#include "BKE_tessmesh.h"
#include "depsgraph_private.h"
-#include "MOD_util.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
static void initData(ModifierData *md)
{
@@ -109,8 +107,8 @@ static void foreachObjectLink(
walk(userData, ob, &amd->offset_ob);
}
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Scene *UNUSED(scene), Object *UNUSED(ob), DagNode *obNode)
+static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *scene,
+ Object *ob, DagNode *obNode)
{
ArrayModifierData *amd = (ArrayModifierData*) md;
@@ -159,28 +157,116 @@ static float vertarray_size(MVert *mvert, int numVerts, int axis)
return max_co - min_co;
}
-/* XXX This function fixes bad merging code, in some cases removing vertices creates indices > maxvert */
-
-static int test_index_face_maxvert(MFace *mface, CustomData *fdata, int mfindex, int nr, int maxvert)
+/* finds the best possible flipped name. For renaming; check for unique names afterwards */
+/* if strip_number: removes number extensions */
+void vertgroup_flip_name (char *name, int strip_number)
{
- if(mface->v1 >= maxvert) {
- // printf("bad index in array\n");
- mface->v1= maxvert - 1;
+ int len;
+ char prefix[128]={""}; /* The part before the facing */
+ char suffix[128]={""}; /* The part after the facing */
+ char replace[128]={""}; /* The replacement string */
+ char number[128]={""}; /* The number extension string */
+ char *index=NULL;
+
+ len= strlen(name);
+ if(len<3) return; // we don't do names like .R or .L
+
+ /* We first check the case with a .### extension, let's find the last period */
+ if(isdigit(name[len-1])) {
+ index= strrchr(name, '.'); // last occurrance
+ if (index && isdigit(index[1]) ) { // doesnt handle case bone.1abc2 correct..., whatever!
+ if(strip_number==0)
+ strcpy(number, index);
+ *index= 0;
+ len= strlen(name);
+ }
}
- if(mface->v2 >= maxvert) {
- // printf("bad index in array\n");
- mface->v2= maxvert - 1;
+
+ strcpy (prefix, name);
+
+#define IS_SEPARATOR(a) ((a)=='.' || (a)==' ' || (a)=='-' || (a)=='_')
+
+ /* first case; separator . - _ with extensions r R l L */
+ if( IS_SEPARATOR(name[len-2]) ) {
+ switch(name[len-1]) {
+ case 'l':
+ prefix[len-1]= 0;
+ strcpy(replace, "r");
+ break;
+ case 'r':
+ prefix[len-1]= 0;
+ strcpy(replace, "l");
+ break;
+ case 'L':
+ prefix[len-1]= 0;
+ strcpy(replace, "R");
+ break;
+ case 'R':
+ prefix[len-1]= 0;
+ strcpy(replace, "L");
+ break;
+ }
}
- if(mface->v3 >= maxvert) {
- // printf("bad index in array\n");
- mface->v3= maxvert - 1;
+ /* case; beginning with r R l L , with separator after it */
+ else if( IS_SEPARATOR(name[1]) ) {
+ switch(name[0]) {
+ case 'l':
+ strcpy(replace, "r");
+ strcpy(suffix, name+1);
+ prefix[0]= 0;
+ break;
+ case 'r':
+ strcpy(replace, "l");
+ strcpy(suffix, name+1);
+ prefix[0]= 0;
+ break;
+ case 'L':
+ strcpy(replace, "R");
+ strcpy(suffix, name+1);
+ prefix[0]= 0;
+ break;
+ case 'R':
+ strcpy(replace, "L");
+ strcpy(suffix, name+1);
+ prefix[0]= 0;
+ break;
+ }
}
- if(mface->v4 >= maxvert) {
- // printf("bad index in array\n");
- mface->v4= maxvert - 1;
+ else if(len > 5) {
+ /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
+ index = BLI_strcasestr(prefix, "right");
+ if (index==prefix || index==prefix+len-5) {
+ if(index[0]=='r')
+ strcpy (replace, "left");
+ else {
+ if(index[1]=='I')
+ strcpy (replace, "LEFT");
+ else
+ strcpy (replace, "Left");
+ }
+ *index= 0;
+ strcpy (suffix, index+5);
+ }
+ else {
+ index = BLI_strcasestr(prefix, "left");
+ if (index==prefix || index==prefix+len-4) {
+ if(index[0]=='l')
+ strcpy (replace, "right");
+ else {
+ if(index[1]=='E')
+ strcpy (replace, "RIGHT");
+ else
+ strcpy (replace, "Right");
+ }
+ *index= 0;
+ strcpy (suffix, index+4);
+ }
+ }
}
-
- return test_index_face(mface, fdata, mfindex, nr);
+
+#undef IS_SEPARATOR
+
+ sprintf (name, "%s%s%s%s", prefix, replace, suffix, number);
}
typedef struct IndexMapEntry {
@@ -222,45 +308,37 @@ static int calc_mapping(IndexMapEntry *indexMap, int oldIndex, int copyNum)
}
static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
- struct Scene *scene, Object *ob, DerivedMesh *dm,
- int initFlags)
+ Scene *scene, Object *ob, DerivedMesh *dm,
+ int initFlags)
{
- int i, j;
+ DerivedMesh *cddm = dm; //copying shouldn't be necassary here, as all modifiers return CDDM's
+ BMEditMesh *em = CDDM_To_BMesh(cddm, NULL);
+ BMOperator op, oldop, weldop;
+ int i, j, indexLen;
/* offset matrix */
float offset[4][4];
float final_offset[4][4];
float tmp_mat[4][4];
float length = amd->length;
- int count = amd->count;
- int numVerts, numEdges, numFaces;
- int maxVerts, maxEdges, maxFaces;
+ int count = amd->count, maxVerts;
int finalVerts, finalEdges, finalFaces;
- DerivedMesh *result, *start_cap = NULL, *end_cap = NULL;
- MVert *mvert, *src_mvert;
- MEdge *medge;
- MFace *mface;
-
- IndexMapEntry *indexMap;
-
- EdgeHash *edges;
+ int *indexMap = NULL;
+ DerivedMesh *start_cap = NULL, *end_cap = NULL;
+ MVert *src_mvert;
/* need to avoid infinite recursion here */
if(amd->start_cap && amd->start_cap != ob)
- start_cap = amd->start_cap->derivedFinal;
+ start_cap = mesh_get_derived_final(scene, amd->start_cap, CD_MASK_MESH);
if(amd->end_cap && amd->end_cap != ob)
- end_cap = amd->end_cap->derivedFinal;
+ end_cap = mesh_get_derived_final(scene, amd->end_cap, CD_MASK_MESH);
unit_m4(offset);
- indexMap = MEM_callocN(sizeof(*indexMap) * dm->getNumVerts(dm),
- "indexmap");
-
- src_mvert = dm->getVertArray(dm);
-
- maxVerts = dm->getNumVerts(dm);
+ src_mvert = cddm->getVertArray(dm);
+ maxVerts = cddm->getNumVerts(dm);
if(amd->offset_type & MOD_ARR_OFF_CONST)
- add_v3_v3(offset[3], amd->offset);
+ add_v3_v3v3(offset[3], offset[3], amd->offset);
if(amd->offset_type & MOD_ARR_OFF_RELATIVE) {
for(j = 0; j < 3; j++)
offset[3][j] += amd->scale[j] * vertarray_size(src_mvert,
@@ -278,7 +356,7 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
mul_serie_m4(result_mat, offset,
obinv, amd->offset_ob->obmat,
- NULL, NULL, NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL, NULL);
copy_m4_m4(offset, result_mat);
}
@@ -287,10 +365,10 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
if(cu) {
float tmp_mat[3][3];
float scale;
-
+
object_to_mat3(amd->curve_ob, tmp_mat);
scale = mat3_to_scale(tmp_mat);
-
+
if(!cu->path) {
cu->flag |= CU_PATH; // needed for path & bevlist
makeDispListCurveTypes(scene, amd->curve_ob, 0);
@@ -303,8 +381,9 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
/* calculate the maximum number of copies which will fit within the
prescribed length */
if(amd->fit_type == MOD_ARR_FITLENGTH
- || amd->fit_type == MOD_ARR_FITCURVE) {
- float dist = sqrt(dot_v3v3(offset[3], offset[3]));
+ || amd->fit_type == MOD_ARR_FITCURVE)
+ {
+ float dist = sqrt(INPR(offset[3], offset[3]));
if(dist > 1e-6f)
/* this gives length = first copy start to last copy end
@@ -313,489 +392,147 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
else
/* if the offset has no translation, just make one copy */
count = 1;
- }
+ }
- if(count < 1)
- count = 1;
+ if(count < 1)
+ count = 1;
/* allocate memory for count duplicates (including original) plus
* start and end caps
*/
- finalVerts = dm->getNumVerts(dm) * count;
- finalEdges = dm->getNumEdges(dm) * count;
- finalFaces = dm->getNumFaces(dm) * count;
- if(start_cap) {
- finalVerts += start_cap->getNumVerts(start_cap);
- finalEdges += start_cap->getNumEdges(start_cap);
- finalFaces += start_cap->getNumFaces(start_cap);
- }
- if(end_cap) {
- finalVerts += end_cap->getNumVerts(end_cap);
- finalEdges += end_cap->getNumEdges(end_cap);
- finalFaces += end_cap->getNumFaces(end_cap);
- }
- result = CDDM_from_template(dm, finalVerts, finalEdges, finalFaces);
-
- /* calculate the offset matrix of the final copy (for merging) */
- unit_m4(final_offset);
-
- for(j=0; j < count - 1; j++) {
- mul_m4_m4m4(tmp_mat, final_offset, offset);
- copy_m4_m4(final_offset, tmp_mat);
- }
-
- numVerts = numEdges = numFaces = 0;
- mvert = CDDM_get_verts(result);
-
- for (i = 0; i < maxVerts; i++) {
- indexMap[i].merge = -1; /* default to no merge */
- indexMap[i].merge_final = 0; /* default to no merge */
- }
-
- for (i = 0; i < maxVerts; i++) {
- MVert *inMV;
- MVert *mv = &mvert[numVerts];
- MVert *mv2;
- float co[3];
-
- inMV = &src_mvert[i];
-
- DM_copy_vert_data(dm, result, i, numVerts, 1);
- *mv = *inMV;
- numVerts++;
-
- indexMap[i].new = numVerts - 1;
-
- copy_v3_v3(co, mv->co);
-
- /* Attempts to merge verts from one duplicate with verts from the
- * next duplicate which are closer than amd->merge_dist.
- * Only the first such vert pair is merged.
- * If verts are merged in the first duplicate pair, they are merged
- * in all pairs.
- */
- if((count > 1) && (amd->flags & MOD_ARR_MERGE)) {
- float tmp_co[3];
- mul_v3_m4v3(tmp_co, offset, mv->co);
-
- for(j = 0; j < maxVerts; j++) {
- /* if vertex already merged, don't use it */
- if( indexMap[j].merge != -1 ) continue;
-
- inMV = &src_mvert[j];
- /* if this vert is within merge limit, merge */
- if(compare_len_v3v3(tmp_co, inMV->co, amd->merge_dist)) {
- indexMap[i].merge = j;
-
- /* test for merging with final copy of merge target */
- if(amd->flags & MOD_ARR_MERGEFINAL) {
- copy_v3_v3(tmp_co, inMV->co);
- inMV = &src_mvert[i];
- mul_m4_v3(final_offset, tmp_co);
- if(compare_len_v3v3(tmp_co, inMV->co, amd->merge_dist))
- indexMap[i].merge_final = 1;
- }
- break;
- }
- }
- }
-
- /* if no merging, generate copies of this vert */
- if(indexMap[i].merge < 0) {
- for(j=0; j < count - 1; j++) {
- mv2 = &mvert[numVerts];
-
- DM_copy_vert_data(result, result, numVerts - 1, numVerts, 1);
- *mv2 = *mv;
- numVerts++;
-
- mul_m4_v3(offset, co);
- copy_v3_v3(mv2->co, co);
- }
- } else if(indexMap[i].merge != i && indexMap[i].merge_final) {
- /* if this vert is not merging with itself, and it is merging
- * with the final copy of its merge target, remove the first copy
- */
- numVerts--;
- DM_free_vert_data(result, numVerts, 1);
- }
- }
-
- /* make a hashtable so we can avoid duplicate edges from merging */
- edges = BLI_edgehash_new();
-
- maxEdges = dm->getNumEdges(dm);
- medge = CDDM_get_edges(result);
- for(i = 0; i < maxEdges; i++) {
- MEdge inMED;
- MEdge med;
- MEdge *med2;
- int vert1, vert2;
-
- dm->getEdge(dm, i, &inMED);
-
- med = inMED;
- med.v1 = indexMap[inMED.v1].new;
- med.v2 = indexMap[inMED.v2].new;
-
- /* if vertices are to be merged with the final copies of their
- * merge targets, calculate that final copy
- */
- if(indexMap[inMED.v1].merge_final) {
- med.v1 = calc_mapping(indexMap, indexMap[inMED.v1].merge,
- count - 1);
- }
- if(indexMap[inMED.v2].merge_final) {
- med.v2 = calc_mapping(indexMap, indexMap[inMED.v2].merge,
- count - 1);
- }
-
- if(med.v1 == med.v2) continue;
-
- /* XXX Unfortunately the calc_mapping returns sometimes numVerts... leads to bad crashes */
- if(med.v1 >= numVerts)
- med.v1= numVerts-1;
- if(med.v2 >= numVerts)
- med.v2= numVerts-1;
-
- if (initFlags) {
- med.flag |= ME_EDGEDRAW | ME_EDGERENDER;
- }
-
- if(!BLI_edgehash_haskey(edges, med.v1, med.v2)) {
- DM_copy_edge_data(dm, result, i, numEdges, 1);
- medge[numEdges] = med;
- numEdges++;
-
- BLI_edgehash_insert(edges, med.v1, med.v2, NULL);
- }
-
- for(j = 1; j < count; j++)
- {
- vert1 = calc_mapping(indexMap, inMED.v1, j);
- vert2 = calc_mapping(indexMap, inMED.v2, j);
-
- /* edge could collapse to single point after mapping */
- if(vert1 == vert2) continue;
-
- /* XXX Unfortunately the calc_mapping returns sometimes numVerts... leads to bad crashes */
- if(vert1 >= numVerts)
- vert1= numVerts-1;
- if(vert2 >= numVerts)
- vert2= numVerts-1;
-
- /* avoid duplicate edges */
- if(!BLI_edgehash_haskey(edges, vert1, vert2)) {
- med2 = &medge[numEdges];
-
- DM_copy_edge_data(dm, result, i, numEdges, 1);
- *med2 = med;
- numEdges++;
-
- med2->v1 = vert1;
- med2->v2 = vert2;
-
- BLI_edgehash_insert(edges, med2->v1, med2->v2, NULL);
- }
- }
- }
-
- maxFaces = dm->getNumFaces(dm);
- mface = CDDM_get_faces(result);
- for (i=0; i < maxFaces; i++) {
- MFace inMF;
- MFace *mf = &mface[numFaces];
-
- dm->getFace(dm, i, &inMF);
-
- DM_copy_face_data(dm, result, i, numFaces, 1);
- *mf = inMF;
-
- mf->v1 = indexMap[inMF.v1].new;
- mf->v2 = indexMap[inMF.v2].new;
- mf->v3 = indexMap[inMF.v3].new;
- if(inMF.v4)
- mf->v4 = indexMap[inMF.v4].new;
-
- /* if vertices are to be merged with the final copies of their
- * merge targets, calculate that final copy
- */
- if(indexMap[inMF.v1].merge_final)
- mf->v1 = calc_mapping(indexMap, indexMap[inMF.v1].merge, count-1);
- if(indexMap[inMF.v2].merge_final)
- mf->v2 = calc_mapping(indexMap, indexMap[inMF.v2].merge, count-1);
- if(indexMap[inMF.v3].merge_final)
- mf->v3 = calc_mapping(indexMap, indexMap[inMF.v3].merge, count-1);
- if(inMF.v4 && indexMap[inMF.v4].merge_final)
- mf->v4 = calc_mapping(indexMap, indexMap[inMF.v4].merge, count-1);
-
- if(test_index_face_maxvert(mf, &result->faceData, numFaces, inMF.v4?4:3, numVerts) < 3)
- continue;
-
- numFaces++;
-
- /* if the face has fewer than 3 vertices, don't create it */
- if(mf->v3 == 0 || (mf->v1 && (mf->v1 == mf->v3 || mf->v1 == mf->v4))) {
- numFaces--;
- DM_free_face_data(result, numFaces, 1);
- }
-
- for(j = 1; j < count; j++)
- {
- MFace *mf2 = &mface[numFaces];
-
- DM_copy_face_data(dm, result, i, numFaces, 1);
- *mf2 = *mf;
-
- mf2->v1 = calc_mapping(indexMap, inMF.v1, j);
- mf2->v2 = calc_mapping(indexMap, inMF.v2, j);
- mf2->v3 = calc_mapping(indexMap, inMF.v3, j);
- if (inMF.v4)
- mf2->v4 = calc_mapping(indexMap, inMF.v4, j);
-
- numFaces++;
-
- /* if the face has fewer than 3 vertices, don't create it */
- if(test_index_face_maxvert(mf2, &result->faceData, numFaces-1, inMF.v4?4:3, numVerts) < 3) {
- numFaces--;
- DM_free_face_data(result, numFaces, 1);
- }
- }
- }
-
- /* add start and end caps */
- if(start_cap) {
- float startoffset[4][4];
- MVert *cap_mvert;
- MEdge *cap_medge;
- MFace *cap_mface;
- int *origindex;
- int *vert_map;
- int capVerts, capEdges, capFaces;
-
- capVerts = start_cap->getNumVerts(start_cap);
- capEdges = start_cap->getNumEdges(start_cap);
- capFaces = start_cap->getNumFaces(start_cap);
- cap_mvert = start_cap->getVertArray(start_cap);
- cap_medge = start_cap->getEdgeArray(start_cap);
- cap_mface = start_cap->getFaceArray(start_cap);
-
- invert_m4_m4(startoffset, offset);
-
- vert_map = MEM_callocN(sizeof(*vert_map) * capVerts,
- "arrayModifier_doArray vert_map");
-
- origindex = result->getVertDataArray(result, CD_ORIGINDEX);
- for(i = 0; i < capVerts; i++) {
- MVert *mv = &cap_mvert[i];
- short merged = 0;
-
- if(amd->flags & MOD_ARR_MERGE) {
- float tmp_co[3];
- MVert *in_mv;
- int j;
-
- copy_v3_v3(tmp_co, mv->co);
- mul_m4_v3(startoffset, tmp_co);
-
- for(j = 0; j < maxVerts; j++) {
- in_mv = &src_mvert[j];
- /* if this vert is within merge limit, merge */
- if(compare_len_v3v3(tmp_co, in_mv->co, amd->merge_dist)) {
- vert_map[i] = calc_mapping(indexMap, j, 0);
- merged = 1;
- break;
- }
- }
- }
-
- if(!merged) {
- DM_copy_vert_data(start_cap, result, i, numVerts, 1);
- mvert[numVerts] = *mv;
- mul_m4_v3(startoffset, mvert[numVerts].co);
- origindex[numVerts] = ORIGINDEX_NONE;
-
- vert_map[i] = numVerts;
-
- numVerts++;
- }
- }
- origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
- for(i = 0; i < capEdges; i++) {
- int v1, v2;
-
- v1 = vert_map[cap_medge[i].v1];
- v2 = vert_map[cap_medge[i].v2];
-
- if(!BLI_edgehash_haskey(edges, v1, v2)) {
- DM_copy_edge_data(start_cap, result, i, numEdges, 1);
- medge[numEdges] = cap_medge[i];
- medge[numEdges].v1 = v1;
- medge[numEdges].v2 = v2;
- origindex[numEdges] = ORIGINDEX_NONE;
-
- numEdges++;
- }
- }
- origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
- for(i = 0; i < capFaces; i++) {
- DM_copy_face_data(start_cap, result, i, numFaces, 1);
- mface[numFaces] = cap_mface[i];
- mface[numFaces].v1 = vert_map[mface[numFaces].v1];
- mface[numFaces].v2 = vert_map[mface[numFaces].v2];
- mface[numFaces].v3 = vert_map[mface[numFaces].v3];
- if(mface[numFaces].v4) {
- mface[numFaces].v4 = vert_map[mface[numFaces].v4];
-
- test_index_face_maxvert(&mface[numFaces], &result->faceData,
- numFaces, 4, numVerts);
- }
- else
- {
- test_index_face(&mface[numFaces], &result->faceData,
- numFaces, 3);
- }
-
- origindex[numFaces] = ORIGINDEX_NONE;
-
- numFaces++;
- }
-
- MEM_freeN(vert_map);
- start_cap->release(start_cap);
- }
-
- if(end_cap) {
- float endoffset[4][4];
- MVert *cap_mvert;
- MEdge *cap_medge;
- MFace *cap_mface;
- int *origindex;
- int *vert_map;
- int capVerts, capEdges, capFaces;
-
- capVerts = end_cap->getNumVerts(end_cap);
- capEdges = end_cap->getNumEdges(end_cap);
- capFaces = end_cap->getNumFaces(end_cap);
- cap_mvert = end_cap->getVertArray(end_cap);
- cap_medge = end_cap->getEdgeArray(end_cap);
- cap_mface = end_cap->getFaceArray(end_cap);
-
- mul_m4_m4m4(endoffset, final_offset, offset);
-
- vert_map = MEM_callocN(sizeof(*vert_map) * capVerts,
- "arrayModifier_doArray vert_map");
-
- origindex = result->getVertDataArray(result, CD_ORIGINDEX);
- for(i = 0; i < capVerts; i++) {
- MVert *mv = &cap_mvert[i];
- short merged = 0;
-
- if(amd->flags & MOD_ARR_MERGE) {
- float tmp_co[3];
- MVert *in_mv;
- int j;
-
- copy_v3_v3(tmp_co, mv->co);
- mul_m4_v3(offset, tmp_co);
-
- for(j = 0; j < maxVerts; j++) {
- in_mv = &src_mvert[j];
- /* if this vert is within merge limit, merge */
- if(compare_len_v3v3(tmp_co, in_mv->co, amd->merge_dist)) {
- vert_map[i] = calc_mapping(indexMap, j, count - 1);
- merged = 1;
- break;
- }
- }
- }
-
- if(!merged) {
- DM_copy_vert_data(end_cap, result, i, numVerts, 1);
- mvert[numVerts] = *mv;
- mul_m4_v3(endoffset, mvert[numVerts].co);
- origindex[numVerts] = ORIGINDEX_NONE;
-
- vert_map[i] = numVerts;
-
- numVerts++;
- }
- }
- origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
- for(i = 0; i < capEdges; i++) {
- int v1, v2;
-
- v1 = vert_map[cap_medge[i].v1];
- v2 = vert_map[cap_medge[i].v2];
-
- if(!BLI_edgehash_haskey(edges, v1, v2)) {
- DM_copy_edge_data(end_cap, result, i, numEdges, 1);
- medge[numEdges] = cap_medge[i];
- medge[numEdges].v1 = v1;
- medge[numEdges].v2 = v2;
- origindex[numEdges] = ORIGINDEX_NONE;
-
- numEdges++;
- }
- }
- origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
- for(i = 0; i < capFaces; i++) {
- DM_copy_face_data(end_cap, result, i, numFaces, 1);
- mface[numFaces] = cap_mface[i];
- mface[numFaces].v1 = vert_map[mface[numFaces].v1];
- mface[numFaces].v2 = vert_map[mface[numFaces].v2];
- mface[numFaces].v3 = vert_map[mface[numFaces].v3];
- if(mface[numFaces].v4) {
- mface[numFaces].v4 = vert_map[mface[numFaces].v4];
-
- test_index_face(&mface[numFaces], &result->faceData,
- numFaces, 4);
- }
- else
- {
- test_index_face(&mface[numFaces], &result->faceData,
- numFaces, 3);
- }
- origindex[numFaces] = ORIGINDEX_NONE;
-
- numFaces++;
- }
-
- MEM_freeN(vert_map);
- end_cap->release(end_cap);
- }
-
- BLI_edgehash_free(edges, NULL);
- MEM_freeN(indexMap);
-
- CDDM_lower_num_verts(result, numVerts);
- CDDM_lower_num_edges(result, numEdges);
- CDDM_lower_num_faces(result, numFaces);
-
- return result;
+ finalVerts = dm->getNumVerts(dm) * count;
+ finalEdges = dm->getNumEdges(dm) * count;
+ finalFaces = dm->getNumFaces(dm) * count;
+ if(start_cap) {
+ finalVerts += start_cap->getNumVerts(start_cap);
+ finalEdges += start_cap->getNumEdges(start_cap);
+ finalFaces += start_cap->getNumFaces(start_cap);
+ }
+ if(end_cap) {
+ finalVerts += end_cap->getNumVerts(end_cap);
+ finalEdges += end_cap->getNumEdges(end_cap);
+ finalFaces += end_cap->getNumFaces(end_cap);
+ }
+
+ /* calculate the offset matrix of the final copy (for merging) */
+ unit_m4(final_offset);
+
+ for(j=0; j < count - 1; j++) {
+ mul_m4_m4m4(tmp_mat, final_offset, offset);
+ copy_m4_m4(final_offset, tmp_mat);
+ }
+
+ BMO_Init_Op(&weldop, "weldverts");
+ BMO_InitOpf(em->bm, &op, "dupe geom=%avef");
+ oldop = op;
+ for (j=0; j < count; j++) {
+ BMVert *v, *v2;
+ BMOpSlot *s1;
+ BMOpSlot *s2;
+
+ BMO_InitOpf(em->bm, &op, "dupe geom=%s", &oldop, j==0 ? "geom" : "newout");
+ BMO_Exec_Op(em->bm, &op);
+
+ s1 = BMO_GetSlot(&op, "geom");
+ s2 = BMO_GetSlot(&op, "newout");
+
+ BMO_CallOpf(em->bm, "transform mat=%m4 verts=%s", offset, &op, "newout");
+
+ #define _E(s, i) ((BMVert**)(s)->data.buf)[i]
+
+ /*calculate merge mapping*/
+ if (j == 0) {
+ BMOperator findop;
+ BMOIter oiter;
+ BMVert *v, *v2;
+ BMHeader *h;
+
+ BMO_InitOpf(em->bm, &findop,
+ "finddoubles verts=%av dist=%f keepverts=%s",
+ amd->merge_dist, &op, "geom");
+
+ i = 0;
+ BMO_ITER(h, &oiter, em->bm, &op, "geom", BM_ALL) {
+ BMINDEX_SET(h, i);
+ i++;
+ }
+
+ BMO_ITER(h, &oiter, em->bm, &op, "newout", BM_ALL) {
+ BMINDEX_SET(h, i);
+ i++;
+ }
+
+ BMO_Exec_Op(em->bm, &findop);
+
+ indexLen = i;
+ indexMap = MEM_callocN(sizeof(int)*indexLen, "indexMap");
+
+ /*element type argument doesn't do anything here*/
+ BMO_ITER(v, &oiter, em->bm, &findop, "targetmapout", 0) {
+ v2 = BMO_IterMapValp(&oiter);
+
+ indexMap[BMINDEX_GET(v)] = BMINDEX_GET(v2)+1;
+ }
+
+ BMO_Finish_Op(em->bm, &findop);
+ }
+
+ /*generate merge mappping using index map. we do this by using the
+ operator slots as lookup arrays.*/
+ #define E(i) (i) < s1->len ? _E(s1, i) : _E(s2, (i)-s1->len)
+
+ for (i=0; i<indexLen; i++) {
+ if (!indexMap[i]) continue;
+
+ v = E(i);
+ v2 = E(indexMap[i]-1);
+
+ BMO_Insert_MapPointer(em->bm, &weldop, "targetmap", v, v2);
+ }
+
+ #undef E
+ #undef _E
+
+ BMO_Finish_Op(em->bm, &oldop);
+ oldop = op;
+ }
+
+ if (j > 0) BMO_Finish_Op(em->bm, &op);
+
+ if (amd->flags & MOD_ARR_MERGE)
+ BMO_Exec_Op(em->bm, &weldop);
+
+ BMO_Finish_Op(em->bm, &weldop);
+
+ BMEdit_RecalcTesselation(em);
+ cddm = CDDM_from_BMEditMesh(em, NULL);
+
+ BMEdit_Free(em);
+ MEM_freeN(indexMap);
+
+ return cddm;
}
-static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
- DerivedMesh *dm,
- int UNUSED(useRenderParams),
- int UNUSED(isFinalCalc))
+static DerivedMesh *applyModifier(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ int useRenderParams, int isFinalCalc)
{
DerivedMesh *result;
ArrayModifierData *amd = (ArrayModifierData*) md;
- result = arrayModifier_doArray(amd, md->scene, ob, dm, 0);
+ result = arrayModifier_doArray(amd, md->scene, ob, derivedData, 0);
- if(result != dm)
- CDDM_calc_normals(result);
+ //if(result != derivedData)
+ // CDDM_calc_normals(result);
return result;
}
-static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
- struct EditMesh *UNUSED(editData),
- DerivedMesh *dm)
+static DerivedMesh *applyModifierEM(
+ ModifierData *md, Object *ob, struct EditMesh *editData,
+ DerivedMesh *derivedData)
{
- return applyModifier(md, ob, dm, 0, 1);
+ return applyModifier(md, ob, derivedData, 0, 1);
}
@@ -812,7 +549,7 @@ ModifierTypeInfo modifierType_Array = {
/* copyData */ copyData,
/* deformVerts */ 0,
- /* deformMatrices */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
@@ -823,7 +560,6 @@ ModifierTypeInfo modifierType_Array = {
/* isDisabled */ 0,
/* updateDepgraph */ updateDepgraph,
/* dependsOnTime */ 0,
- /* dependsOnNormals */ 0,
/* foreachObjectLink */ foreachObjectLink,
/* foreachIDLink */ 0,
};
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index a1bd3abc176..8d34fdcb10e 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -91,6 +91,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
int UNUSED(useRenderParams),
int UNUSED(isFinalCalc))
{
+#if 0
DerivedMesh *result;
BME_Mesh *bm;
@@ -113,8 +114,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
BME_free_mesh(bm);
CDDM_calc_normals(result);
+#endif
- return result;
+ return CDDM_copy(derivedData, 0);
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
diff --git a/source/blender/modifiers/intern/MOD_boolean_util.c b/source/blender/modifiers/intern/MOD_boolean_util.c
index 9d83e351b2b..cefad37ea26 100644
--- a/source/blender/modifiers/intern/MOD_boolean_util.c
+++ b/source/blender/modifiers/intern/MOD_boolean_util.c
@@ -174,14 +174,14 @@ static int FaceIt_Done(CSG_IteratorPtr it)
{
// assume CSG_IteratorPtr is of the correct type.
FaceIt * iterator = (FaceIt *)it;
- return(iterator->pos >= iterator->dm->getNumFaces(iterator->dm));
+ return(iterator->pos >= iterator->dm->getNumTessFaces(iterator->dm));
}
static void FaceIt_Fill(CSG_IteratorPtr it, CSG_IFace *face)
{
// assume CSG_IteratorPtr is of the correct type.
FaceIt *face_it = (FaceIt *)it;
- MFace *mfaces = face_it->dm->getFaceArray(face_it->dm);
+ MFace *mfaces = face_it->dm->getTessFaceArray(face_it->dm);
MFace *mface = &mfaces[face_it->pos];
/* reverse face vertices if necessary */
@@ -255,7 +255,7 @@ static void FaceIt_Construct(
output->Fill = FaceIt_Fill;
output->Done = FaceIt_Done;
output->Reset = FaceIt_Reset;
- output->num_elements = it->dm->getNumFaces(it->dm);
+ output->num_elements = it->dm->getNumTessFaces(it->dm);
output->it = it;
}
@@ -305,8 +305,8 @@ static void InterpCSGFace(
MFace *mface, *orig_mface;
int j;
- mface = CDDM_get_face(dm, index);
- orig_mface = orig_dm->getFaceArray(orig_dm) + orig_index;
+ mface = CDDM_get_tessface(dm, index);
+ orig_mface = orig_dm->getTessFaceArray(orig_dm) + orig_index;
// get the vertex coordinates from the original mesh
orig_co[0] = (orig_dm->getVertArray(orig_dm) + orig_mface->v1)->co;
@@ -347,14 +347,14 @@ static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh(
DerivedMesh *dm2,
Object *ob2)
{
- DerivedMesh *result, *orig_dm;
+ DerivedMesh *result, *orig_dm, *dm;
GHash *material_hash = NULL;
Mesh *me1= (Mesh*)ob1->data;
Mesh *me2= (Mesh*)ob2->data;
int i;
// create a new DerivedMesh
- result = CDDM_new(vertex_it->num_elements, 0, face_it->num_elements);
+ result = CDDM_new(vertex_it->num_elements, 0, face_it->num_elements, 0, 0);
CustomData_merge(&dm1->faceData, &result->faceData, CD_MASK_DERIVEDMESH,
CD_DEFAULT, face_it->num_elements);
CustomData_merge(&dm2->faceData, &result->faceData, CD_MASK_DERIVEDMESH,
@@ -394,16 +394,16 @@ static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh(
face_it->Step(face_it->it);
// find the original mesh and data
- orig_ob = (csgface.orig_face < dm1->getNumFaces(dm1))? ob1: ob2;
- orig_dm = (csgface.orig_face < dm1->getNumFaces(dm1))? dm1: dm2;
+ orig_ob = (csgface.orig_face < dm1->getNumTessFaces(dm1))? ob1: ob2;
+ orig_dm = (csgface.orig_face < dm1->getNumTessFaces(dm1))? dm1: dm2;
orig_me = (orig_ob == ob1)? me1: me2;
- orig_index = (orig_ob == ob1)? csgface.orig_face: csgface.orig_face - dm1->getNumFaces(dm1);
+ orig_index = (orig_ob == ob1)? csgface.orig_face: csgface.orig_face - dm1->getNumTessFaces(dm1);
// copy all face layers, including mface
CustomData_copy_data(&orig_dm->faceData, &result->faceData, orig_index, i, 1);
// set mface
- mface = CDDM_get_face(result, i);
+ mface = CDDM_get_tessface(result, i);
mface->v1 = csgface.vertex_index[0];
mface->v2 = csgface.vertex_index[1];
mface->v3 = csgface.vertex_index[2];
@@ -436,7 +436,11 @@ static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh(
CDDM_calc_edges(result);
CDDM_calc_normals(result);
- return result;
+ dm = CDDM_copy(result, 1); /*builds ngon faces from tess (mface) faces*/
+ result->needsFree = 1;
+ result->release(result);
+
+ return dm;
}
static void BuildMeshDescriptors(
@@ -469,7 +473,7 @@ static DerivedMesh *NewBooleanDerivedMesh_intern(
DerivedMesh *result = NULL;
if (dm == NULL || dm_select == NULL) return 0;
- if (!dm->getNumFaces(dm) || !dm_select->getNumFaces(dm_select)) return 0;
+ if (!dm->getNumTessFaces(dm) || !dm_select->getNumTessFaces(dm_select)) return 0;
// we map the final object back into ob's local coordinate space. For this
// we need to compute the inverse transform from global to ob (inv_mat),
@@ -501,7 +505,7 @@ static DerivedMesh *NewBooleanDerivedMesh_intern(
}
BuildMeshDescriptors(dm_select, ob_select, 0, &fd_1, &vd_1);
- BuildMeshDescriptors(dm, ob, dm_select->getNumFaces(dm_select) , &fd_2, &vd_2);
+ BuildMeshDescriptors(dm, ob, dm_select->getNumTessFaces(dm_select) , &fd_2, &vd_2);
bool_op = CSG_NewBooleanFunction();
@@ -555,7 +559,7 @@ int NewBooleanMesh(Scene *scene, Base *base, Base *base_select, int int_op_type)
/* put some checks in for nice user feedback */
if (dm == NULL || dm_select == NULL) return 0;
- if (!dm->getNumFaces(dm) || !dm_select->getNumFaces(dm_select))
+ if (!dm->getNumTessFaces(dm) || !dm_select->getNumTessFaces(dm_select))
{
MEM_freeN(mat);
return -1;
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index 0d04476c618..e2a54648623 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -99,7 +99,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
const int maxVerts= dm->getNumVerts(dm);
const int maxEdges= dm->getNumEdges(dm);
- const int maxFaces= dm->getNumFaces(dm);
+ const int maxFaces= dm->getNumTessFaces(dm);
vertMap = MEM_callocN(sizeof(*vertMap) * maxVerts, "build modifier vertMap");
for(i = 0; i < maxVerts; ++i) vertMap[i] = i;
@@ -116,7 +116,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
CLAMP(frac, 0.0, 1.0);
- numFaces = dm->getNumFaces(dm) * frac;
+ numFaces = dm->getNumTessFaces(dm) * frac;
numEdges = dm->getNumEdges(dm) * frac;
/* if there's at least one face, build based on faces */
@@ -130,7 +130,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
*/
for(i = 0; i < numFaces; ++i) {
MFace mf;
- dm->getFace(dm, faceMap[i], &mf);
+ dm->getTessFace(dm, faceMap[i], &mf);
if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1)))
BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v1),
@@ -205,7 +205,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
* the mesh
*/
result = CDDM_from_template(dm, BLI_ghash_size(vertHash),
- BLI_ghash_size(edgeHash), numFaces);
+ BLI_ghash_size(edgeHash), numFaces, 0, 0);
/* copy the vertices across */
for( hashIter = BLI_ghashIterator_new(vertHash);
@@ -247,8 +247,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
MFace *dest;
int orig_v4;
- dm->getFace(dm, faceMap[i], &source);
- dest = CDDM_get_face(result, i);
+ dm->getTessFace(dm, faceMap[i], &source);
+ dest = CDDM_get_tessface(result, i);
orig_v4 = source.v4;
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index e1371b3b86c..07b35cdf334 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -119,7 +119,7 @@ static void deformVerts(ModifierData *md, Object *ob,
MVert *tempVert = NULL;
/* if possible use/create DerivedMesh */
- if(derivedData) dm = CDDM_copy(derivedData);
+ if(derivedData) dm = CDDM_copy(derivedData, 0);
else if(ob->type==OB_MESH) dm = CDDM_from_mesh(ob->data, ob);
if(!ob->pd)
@@ -168,8 +168,8 @@ static void deformVerts(ModifierData *md, Object *ob,
collmd->numverts = numverts;
- collmd->mfaces = dm->dupFaceArray(dm);
- collmd->numfaces = dm->getNumFaces(dm);
+ collmd->mfaces = dm->dupTessFaceArray(dm);
+ collmd->numfaces = dm->getNumTessFaces(dm);
// create bounding box hierarchy
collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->x, numverts, ob->pd->pdef_sboft);
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index 64d6b72a176..4eae988f92f 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -84,9 +84,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
int a, numTris;
mvert = dm->getVertArray(dm);
- mface = dm->getFaceArray(dm);
+ mface = dm->getTessFaceArray(dm);
totvert = dm->getNumVerts(dm);
- totface = dm->getNumFaces(dm);
+ totface = dm->getNumTessFaces(dm);
numTris = 0;
for (a=0; a<totface; a++) {
@@ -142,11 +142,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
}
if(lod.vertex_num>2) {
- result = CDDM_new(lod.vertex_num, 0, lod.face_num);
+ result = CDDM_new(lod.vertex_num, 0, lod.face_num, 0, 0);
dmd->faceCount = lod.face_num;
}
else
- result = CDDM_new(lod.vertex_num, 0, 0);
+ result = CDDM_new(lod.vertex_num, 0, 0, 0, 0);
mvert = CDDM_get_verts(result);
for(a=0; a<lod.vertex_num; a++) {
@@ -157,7 +157,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
}
if(lod.vertex_num>2) {
- mface = CDDM_get_faces(result);
+ mface = CDDM_get_tessfaces(result);
for(a=0; a<lod.face_num; a++) {
MFace *mf = &mface[a];
int *tri = &lod.triangle_index_buffer[a*3];
@@ -184,7 +184,12 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
MEM_freeN(lod.triangle_index_buffer);
exit:
- return result;
+
+ dm = CDDM_copy(result, 1); /*builds ngon faces from tess (mface) faces*/
+ result->needsFree = 1;
+ result->release(result);
+
+ return dm;
}
#else // WITH_MOD_DECIMATE
static DerivedMesh *applyModifier(ModifierData *UNUSED(md), Object *UNUSED(ob),
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index 2ab6921dc8a..6ae5c14d5ef 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -181,11 +181,11 @@ static void get_texture_coords(DisplaceModifierData *dmd, Object *ob,
/* UVs need special handling, since they come from faces */
if(texmapping == MOD_DISP_MAP_UV) {
if(CustomData_has_layer(&dm->faceData, CD_MTFACE)) {
- MFace *mface = dm->getFaceArray(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
MFace *mf;
char *done = MEM_callocN(sizeof(*done) * numVerts,
"get_texture_coords done");
- int numFaces = dm->getNumFaces(dm);
+ int numFaces = dm->getNumTessFaces(dm);
char uvname[32];
MTFace *tf;
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 05e195d9b8f..4549448f45e 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -20,21 +20,12 @@
* The Original Code is Copyright (C) 2005 by the Blender Foundation.
* All rights reserved.
*
-* Contributor(s): Daniel Dunbar
-* Ton Roosendaal,
-* Ben Batt,
-* Brecht Van Lommel,
-* Campbell Barton
+* Contributor(s): Joseph Eagar
*
* ***** END GPL LICENSE BLOCK *****
*
*/
-/** \file blender/modifiers/intern/MOD_edgesplit.c
- * \ingroup modifiers
- */
-
-
/* EdgeSplit modifier: Splits edges in the mesh according to sharpness flag
* or edge angle (can be used to achieve autosmoothing) */
@@ -44,1218 +35,392 @@
#include "BLI_memarena.h"
#include "BLI_edgehash.h"
#include "BLI_math.h"
+#include "BLI_array.h"
#include "BLI_utildefines.h"
-
#include "BKE_cdderivedmesh.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
+#include "BKE_tessmesh.h"
+#include "BKE_mesh.h"
#include "MEM_guardedalloc.h"
-#include "MOD_util.h"
-
-#if 0
-#define EDGESPLIT_DEBUG_3
-#define EDGESPLIT_DEBUG_2
-#define EDGESPLIT_DEBUG_1
-#define EDGESPLIT_DEBUG_0
-#endif
-
-static void initData(ModifierData *md)
-{
- EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
-
- /* default to 30-degree split angle, sharpness from both angle & flag
- */
- emd->split_angle = 30;
- emd->flags = MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG;
-}
-
-static void copyData(ModifierData *md, ModifierData *target)
-{
- EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
- EdgeSplitModifierData *temd = (EdgeSplitModifierData*) target;
-
- temd->split_angle = emd->split_angle;
- temd->flags = emd->flags;
-}
-
-/* Mesh data for edgesplit operation */
-typedef struct SmoothVert {
- LinkNode *faces; /* all faces which use this vert */
- int oldIndex; /* the index of the original DerivedMesh vert */
- int newIndex; /* the index of the new DerivedMesh vert */
-} SmoothVert;
-
-#define SMOOTHEDGE_NUM_VERTS 2
-
-typedef struct SmoothEdge {
- SmoothVert *verts[SMOOTHEDGE_NUM_VERTS]; /* the verts used by this edge */
- LinkNode *faces; /* all faces which use this edge */
- int oldIndex; /* the index of the original DerivedMesh edge */
- int newIndex; /* the index of the new DerivedMesh edge */
- short flag; /* the flags from the original DerivedMesh edge */
-} SmoothEdge;
-
-#define SMOOTHFACE_MAX_EDGES 4
-
-typedef struct SmoothFace {
- SmoothEdge *edges[SMOOTHFACE_MAX_EDGES]; /* nonexistent edges == NULL */
- int flip[SMOOTHFACE_MAX_EDGES]; /* 1 = flip edge dir, 0 = don't flip */
- float normal[3]; /* the normal of this face */
- int oldIndex; /* the index of the original DerivedMesh face */
- int newIndex; /* the index of the new DerivedMesh face */
-} SmoothFace;
-
-typedef struct SmoothMesh {
- SmoothVert *verts;
- SmoothEdge *edges;
- SmoothFace *faces;
- int num_verts, num_edges, num_faces;
- int max_verts, max_edges, max_faces;
- DerivedMesh *dm;
- float threshold; /* the cosine of the smoothing angle */
- int flags;
- MemArena *arena;
- ListBase propagatestack, reusestack;
-} SmoothMesh;
-
-static SmoothVert *smoothvert_copy(SmoothVert *vert, SmoothMesh *mesh)
-{
- SmoothVert *copy = &mesh->verts[mesh->num_verts];
+/* EdgeSplit */
+/* EdgeSplit modifier: Splits edges in the mesh according to sharpness flag
+ * or edge angle (can be used to achieve autosmoothing)
+*/
- if(mesh->num_verts >= mesh->max_verts) {
- printf("Attempted to add a SmoothMesh vert beyond end of array\n");
+/*new cddm-based edge split code*/
+typedef struct VertUser {
+ int ov, v, done;
+ ListBase users;
+} VertUser;
+
+typedef struct EdgeNode {
+ struct EdgeNode *next, *prev;
+ struct EdgeData *edge;
+} EdgeNode;
+
+typedef struct EdgeData {
+ EdgeNode v1node, v2node;
+ VertUser *v1user, *v2user;
+ float fno[3]; /*used to calculate face angles*/
+ int has_fno;
+ int tag;
+ int v1, v2;
+ int used;
+} EdgeData;
+
+typedef struct MemBase {
+ BLI_mempool *vertuserpool;
+} MemBase;
+
+BM_INLINE EdgeData *edge_get_next(EdgeData *e, int ov) {
+ if (ov == e->v1)
+ return e->v1node.next ? e->v1node.next->edge : NULL;
+ else return e->v2node.next ? e->v2node.next->edge : NULL;
+}
+
+BM_INLINE EdgeNode *edge_get_node(EdgeData *e, int ov)
+{
+ if (ov == e->v1)
+ return &e->v1node;
+ else return &e->v2node;
return NULL;
- }
-
- *copy = *vert;
- copy->faces = NULL;
- copy->newIndex = mesh->num_verts;
- ++mesh->num_verts;
-
-#ifdef EDGESPLIT_DEBUG_2
- printf("copied vert %4d to vert %4d\n", vert->newIndex, copy->newIndex);
-#endif
- return copy;
}
-static SmoothEdge *smoothedge_copy(SmoothEdge *edge, SmoothMesh *mesh)
+BM_INLINE VertUser *edge_get_vuser(MemBase *b, EdgeData *edge, int ov)
{
- SmoothEdge *copy = &mesh->edges[mesh->num_edges];
-
- if(mesh->num_edges >= mesh->max_edges) {
- printf("Attempted to add a SmoothMesh edge beyond end of array\n");
+ if (ov == edge->v1)
+ return edge->v1user;
+ else if (ov == edge->v2)
+ return edge->v2user;
+ else {
+ printf("yeek!!\n");
return NULL;
}
-
- *copy = *edge;
- copy->faces = NULL;
- copy->newIndex = mesh->num_edges;
- ++mesh->num_edges;
-
-#ifdef EDGESPLIT_DEBUG_2
- printf("copied edge %4d to edge %4d\n", edge->newIndex, copy->newIndex);
-#endif
- return copy;
}
-static int smoothedge_has_vert(SmoothEdge *edge, SmoothVert *vert)
-{
- int i;
- for(i = 0; i < SMOOTHEDGE_NUM_VERTS; i++)
- if(edge->verts[i] == vert) return 1;
-
- return 0;
-}
-
-static SmoothMesh *smoothmesh_new(int num_verts, int num_edges, int num_faces,
- int max_verts, int max_edges, int max_faces)
-{
- SmoothMesh *mesh = MEM_callocN(sizeof(*mesh), "smoothmesh");
- mesh->verts = MEM_callocN(sizeof(*mesh->verts) * max_verts,
- "SmoothMesh.verts");
- mesh->edges = MEM_callocN(sizeof(*mesh->edges) * max_edges,
- "SmoothMesh.edges");
- mesh->faces = MEM_callocN(sizeof(*mesh->faces) * max_faces,
- "SmoothMesh.faces");
-
- mesh->num_verts = num_verts;
- mesh->num_edges = num_edges;
- mesh->num_faces = num_faces;
-
- mesh->max_verts = max_verts;
- mesh->max_edges = max_edges;
- mesh->max_faces = max_faces;
-
- return mesh;
-}
+BM_INLINE void edge_set_vuser(MemBase *b, EdgeData *e, int ov, VertUser *vu)
-static void smoothmesh_free(SmoothMesh *mesh)
{
- int i;
-
- for(i = 0; i < mesh->num_verts; ++i)
- BLI_linklist_free(mesh->verts[i].faces, NULL);
-
- for(i = 0; i < mesh->num_edges; ++i)
- BLI_linklist_free(mesh->edges[i].faces, NULL);
-
- if(mesh->arena)
- BLI_memarena_free(mesh->arena);
-
- MEM_freeN(mesh->verts);
- MEM_freeN(mesh->edges);
- MEM_freeN(mesh->faces);
- MEM_freeN(mesh);
-}
-
-static void smoothmesh_resize_verts(SmoothMesh *mesh, int max_verts)
-{
- int i;
- SmoothVert *tmp;
-
- if(max_verts <= mesh->max_verts) return;
-
- tmp = MEM_callocN(sizeof(*tmp) * max_verts, "SmoothMesh.verts");
+ VertUser *olduser = edge_get_vuser(b, e, ov);
- memcpy(tmp, mesh->verts, sizeof(*tmp) * mesh->num_verts);
+ if (vu == olduser)
+ return;
- /* remap vert pointers in edges */
- for(i = 0; i < mesh->num_edges; ++i) {
- int j;
- SmoothEdge *edge = &mesh->edges[i];
+ if (olduser)
+ BLI_remlink(&olduser->users, ov==e->v1 ? &e->v1node : &e->v2node);
+ BLI_addtail(&vu->users, ov==e->v1 ? &e->v1node : &e->v2node);
- for(j = 0; j < SMOOTHEDGE_NUM_VERTS; ++j)
- /* pointer arithmetic to get vert array index */
- edge->verts[j] = &tmp[edge->verts[j] - mesh->verts];
- }
-
- MEM_freeN(mesh->verts);
- mesh->verts = tmp;
- mesh->max_verts = max_verts;
+ if (ov == e->v1)
+ e->v1user = vu;
+ else e->v2user = vu;
}
-static void smoothmesh_resize_edges(SmoothMesh *mesh, int max_edges)
+BM_INLINE VertUser *new_vuser(MemBase *base)
{
- int i;
- SmoothEdge *tmp;
-
- if(max_edges <= mesh->max_edges) return;
-
- tmp = MEM_callocN(sizeof(*tmp) * max_edges, "SmoothMesh.edges");
-
- memcpy(tmp, mesh->edges, sizeof(*tmp) * mesh->num_edges);
+ VertUser *vusr = BLI_mempool_calloc(base->vertuserpool);
- /* remap edge pointers in faces */
- for(i = 0; i < mesh->num_faces; ++i) {
- int j;
- SmoothFace *face = &mesh->faces[i];
-
- for(j = 0; j < SMOOTHFACE_MAX_EDGES; ++j)
- if(face->edges[j])
- /* pointer arithmetic to get edge array index */
- face->edges[j] = &tmp[face->edges[j] - mesh->edges];
- }
-
- MEM_freeN(mesh->edges);
- mesh->edges = tmp;
- mesh->max_edges = max_edges;
+ return vusr;
}
-#ifdef EDGESPLIT_DEBUG_0
-static void smoothmesh_print(SmoothMesh *mesh)
+BM_INLINE MemBase *new_membase(void)
{
- int i, j;
- DerivedMesh *dm = mesh->dm;
-
- printf("--- SmoothMesh ---\n");
- printf("--- Vertices ---\n");
- for(i = 0; i < mesh->num_verts; i++) {
- SmoothVert *vert = &mesh->verts[i];
- LinkNode *node;
- MVert mv;
-
- dm->getVert(dm, vert->oldIndex, &mv);
-
- printf("%3d: ind={%3d, %3d}, pos={% 5.1f, % 5.1f, % 5.1f}",
- i, vert->oldIndex, vert->newIndex,
- mv.co[0], mv.co[1], mv.co[2]);
- printf(", faces={");
- for(node = vert->faces; node != NULL; node = node->next) {
- printf(" %d", ((SmoothFace *)node->link)->newIndex);
- }
- printf("}\n");
- }
-
- printf("\n--- Edges ---\n");
- for(i = 0; i < mesh->num_edges; i++) {
- SmoothEdge *edge = &mesh->edges[i];
- LinkNode *node;
-
- printf("%4d: indices={%4d, %4d}, verts={%4d, %4d}",
- i,
- edge->oldIndex, edge->newIndex,
- edge->verts[0]->newIndex, edge->verts[1]->newIndex);
- if(edge->verts[0] == edge->verts[1]) printf(" <- DUPLICATE VERTEX");
- printf(", faces={");
- for(node = edge->faces; node != NULL; node = node->next) {
- printf(" %d", ((SmoothFace *)node->link)->newIndex);
- }
- printf("}\n");
- }
+ MemBase *b = MEM_callocN(sizeof(MemBase), "MemBase for edgesplit in modifier.c");
+ b->vertuserpool = BLI_mempool_create(sizeof(VertUser), 1, 2048, 1, 0);
- printf("\n--- Faces ---\n");
- for(i = 0; i < mesh->num_faces; i++) {
- SmoothFace *face = &mesh->faces[i];
-
- printf("%4d: indices={%4d, %4d}, edges={", i,
- face->oldIndex, face->newIndex);
- for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
- if(face->flip[j])
- printf(" -%-2d", face->edges[j]->newIndex);
- else
- printf(" %-2d", face->edges[j]->newIndex);
- }
- printf("}, verts={");
- for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
- printf(" %d", face->edges[j]->verts[face->flip[j]]->newIndex);
- }
- printf("}\n");
- }
+ return b;
}
-#endif
-static SmoothMesh *smoothmesh_from_derivedmesh(DerivedMesh *dm)
+BM_INLINE void free_membase(MemBase *b)
{
- SmoothMesh *mesh;
- EdgeHash *edges = BLI_edgehash_new();
- int i;
- int totvert, totedge, totface;
-
- totvert = dm->getNumVerts(dm);
- totedge = dm->getNumEdges(dm);
- totface = dm->getNumFaces(dm);
-
- mesh = smoothmesh_new(totvert, totedge, totface,
- totvert, totedge, totface);
-
- mesh->dm = dm;
-
- for(i = 0; i < totvert; i++) {
- SmoothVert *vert = &mesh->verts[i];
-
- vert->oldIndex = vert->newIndex = i;
- }
-
- for(i = 0; i < totedge; i++) {
- SmoothEdge *edge = &mesh->edges[i];
- MEdge med;
-
- dm->getEdge(dm, i, &med);
- edge->verts[0] = &mesh->verts[med.v1];
- edge->verts[1] = &mesh->verts[med.v2];
- edge->oldIndex = edge->newIndex = i;
- edge->flag = med.flag;
-
- BLI_edgehash_insert(edges, med.v1, med.v2, edge);
- }
-
- for(i = 0; i < totface; i++) {
- SmoothFace *face = &mesh->faces[i];
- MFace mf;
- MVert v1, v2, v3;
- int j;
-
- dm->getFace(dm, i, &mf);
-
- dm->getVert(dm, mf.v1, &v1);
- dm->getVert(dm, mf.v2, &v2);
- dm->getVert(dm, mf.v3, &v3);
- face->edges[0] = BLI_edgehash_lookup(edges, mf.v1, mf.v2);
- if(face->edges[0]->verts[1]->oldIndex == mf.v1) face->flip[0] = 1;
- face->edges[1] = BLI_edgehash_lookup(edges, mf.v2, mf.v3);
- if(face->edges[1]->verts[1]->oldIndex == mf.v2) face->flip[1] = 1;
- if(mf.v4) {
- MVert v4;
- dm->getVert(dm, mf.v4, &v4);
- face->edges[2] = BLI_edgehash_lookup(edges, mf.v3, mf.v4);
- if(face->edges[2]->verts[1]->oldIndex == mf.v3) face->flip[2] = 1;
- face->edges[3] = BLI_edgehash_lookup(edges, mf.v4, mf.v1);
- if(face->edges[3]->verts[1]->oldIndex == mf.v4) face->flip[3] = 1;
- normal_quad_v3( face->normal,v1.co, v2.co, v3.co, v4.co);
- } else {
- face->edges[2] = BLI_edgehash_lookup(edges, mf.v3, mf.v1);
- if(face->edges[2]->verts[1]->oldIndex == mf.v3) face->flip[2] = 1;
- face->edges[3] = NULL;
- normal_tri_v3( face->normal,v1.co, v2.co, v3.co);
- }
-
- for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
- SmoothEdge *edge = face->edges[j];
- BLI_linklist_prepend(&edge->faces, face);
- BLI_linklist_prepend(&edge->verts[face->flip[j]]->faces, face);
- }
-
- face->oldIndex = face->newIndex = i;
- }
-
- BLI_edgehash_free(edges, NULL);
-
- return mesh;
-}
-
-static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh)
-{
- DerivedMesh *result = CDDM_from_template(mesh->dm,
- mesh->num_verts,
- mesh->num_edges,
- mesh->num_faces);
- MVert *new_verts = CDDM_get_verts(result);
- MEdge *new_edges = CDDM_get_edges(result);
- MFace *new_faces = CDDM_get_faces(result);
- int i;
-
- for(i = 0; i < mesh->num_verts; ++i) {
- SmoothVert *vert = &mesh->verts[i];
- MVert *newMV = &new_verts[vert->newIndex];
-
- DM_copy_vert_data(mesh->dm, result,
- vert->oldIndex, vert->newIndex, 1);
- mesh->dm->getVert(mesh->dm, vert->oldIndex, newMV);
- }
-
- for(i = 0; i < mesh->num_edges; ++i) {
- SmoothEdge *edge = &mesh->edges[i];
- MEdge *newME = &new_edges[edge->newIndex];
-
- DM_copy_edge_data(mesh->dm, result,
- edge->oldIndex, edge->newIndex, 1);
- mesh->dm->getEdge(mesh->dm, edge->oldIndex, newME);
- newME->v1 = edge->verts[0]->newIndex;
- newME->v2 = edge->verts[1]->newIndex;
- }
-
- for(i = 0; i < mesh->num_faces; ++i) {
- SmoothFace *face = &mesh->faces[i];
- MFace *newMF = &new_faces[face->newIndex];
-
- DM_copy_face_data(mesh->dm, result,
- face->oldIndex, face->newIndex, 1);
- mesh->dm->getFace(mesh->dm, face->oldIndex, newMF);
-
- newMF->v1 = face->edges[0]->verts[face->flip[0]]->newIndex;
- newMF->v2 = face->edges[1]->verts[face->flip[1]]->newIndex;
- newMF->v3 = face->edges[2]->verts[face->flip[2]]->newIndex;
-
- if(face->edges[3]) {
- newMF->v4 = face->edges[3]->verts[face->flip[3]]->newIndex;
- } else {
- newMF->v4 = 0;
- }
- }
-
- return result;
-}
-
-/* returns the other vert in the given edge
- */
-static SmoothVert *other_vert(SmoothEdge *edge, SmoothVert *vert)
-{
- if(edge->verts[0] == vert) return edge->verts[1];
- else return edge->verts[0];
-}
-
-/* returns the other edge in the given face that uses the given vert
- * returns NULL if no other edge in the given face uses the given vert
- * (this should never happen)
- */
-static SmoothEdge *other_edge(SmoothFace *face, SmoothVert *vert,
- SmoothEdge *edge)
-{
- int i,j;
- for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) {
- SmoothEdge *tmp_edge = face->edges[i];
- if(tmp_edge == edge) continue;
-
- for(j = 0; j < SMOOTHEDGE_NUM_VERTS; j++)
- if(tmp_edge->verts[j] == vert) return tmp_edge;
- }
-
- /* if we get to here, something's wrong (there should always be 2 edges
- * which use the same vert in a face)
- */
- return NULL;
-}
-
-/* returns a face attached to the given edge which is not the given face.
- * returns NULL if no other faces use this edge.
- */
-static SmoothFace *other_face(SmoothEdge *edge, SmoothFace *face)
-{
- LinkNode *node;
-
- for(node = edge->faces; node != NULL; node = node->next)
- if(node->link != face) return node->link;
-
- return NULL;
-}
-
-#if 0
-/* copies source list to target, overwriting target (target is not freed)
- * nodes in the copy will be in the same order as in source
- */
-static void linklist_copy(LinkNode **target, LinkNode *source)
-{
- LinkNode *node = NULL;
- *target = NULL;
-
- for(; source; source = source->next) {
- if(node) {
- node->next = MEM_mallocN(sizeof(*node->next), "nlink_copy");
- node = node->next;
-} else {
- node = *target = MEM_mallocN(sizeof(**target), "nlink_copy");
-}
- node->link = source->link;
- node->next = NULL;
-}
-}
-#endif
-
- /* appends source to target if it's not already in target */
- static void linklist_append_unique(LinkNode **target, void *source)
-{
- LinkNode *node;
- LinkNode *prev = NULL;
-
- /* check if source value is already in the list */
- for(node = *target; node; prev = node, node = node->next)
- if(node->link == source) return;
-
- node = MEM_mallocN(sizeof(*node), "nlink");
- node->next = NULL;
- node->link = source;
-
- if(prev) prev->next = node;
- else *target = node;
-}
-
-/* appends elements of source which aren't already in target to target */
-static void linklist_append_list_unique(LinkNode **target, LinkNode *source)
-{
- for(; source; source = source->next)
- linklist_append_unique(target, source->link);
-}
-
-#if 0 /* this is no longer used, it should possibly be removed */
-/* prepends prepend to list - doesn't copy nodes, just joins the lists */
-static void linklist_prepend_linklist(LinkNode **list, LinkNode *prepend)
-{
- if(prepend) {
- LinkNode *node = prepend;
- while(node->next) node = node->next;
-
- node->next = *list;
- *list = prepend;
+ BLI_mempool_destroy(b->vertuserpool);
+ MEM_freeN(b);
}
-}
-#endif
-/* returns 1 if the linked list contains the given pointer, 0 otherwise
- */
-static int linklist_contains(LinkNode *list, void *ptr)
+BM_INLINE EdgeData *edge_get_first(VertUser *vu)
{
- LinkNode *node;
-
- for(node = list; node; node = node->next)
- if(node->link == ptr) return 1;
-
- return 0;
+ return vu->users.first ? ((EdgeNode*)vu->users.first)->edge : NULL;
}
-/* returns 1 if the first linked list is a subset of the second (comparing
- * pointer values), 0 if not
- */
-static int linklist_subset(LinkNode *list1, LinkNode *list2)
+DerivedMesh *doEdgeSplit(DerivedMesh *dm, EdgeSplitModifierData *emd)
{
- for(; list1; list1 = list1->next)
- if(!linklist_contains(list2, list1->link))
- return 0;
+ DerivedMesh *cddm = CDDM_copy(dm, 0);
+ MEdge *medge;
+ BLI_array_declare(medge);
+ MLoop *mloop, *ml, *prevl;
+ MPoly *mpoly, *mp;
+ MVert *mvert;
+ BLI_array_declare(mvert);
+ EdgeData *etags, *e, *enext;
+ BLI_array_declare(etags);
+ VertUser *vu, *vu2;
+ MemBase *membase;
+ CustomData edata, vdata;
+ int i, j, curv, cure;
+ float threshold = cos((emd->split_angle + 0.00001) * M_PI / 180.0);
+ float no[3], edge_angle_cos;
- return 1;
-}
+ if (!cddm->numVertData || !cddm->numEdgeData)
+ return cddm;
-#if 0
-/* empties the linked list
- * frees pointers with freefunc if freefunc is not NULL
- */
-static void linklist_empty(LinkNode **list, LinkNodeFreeFP freefunc)
-{
- BLI_linklist_free(*list, freefunc);
- *list = NULL;
-}
-#endif
+ membase = new_membase();
-/* removes the first instance of value from the linked list
- * frees the pointer with freefunc if freefunc is not NULL
- */
-static void linklist_remove_first(LinkNode **list, void *value,
- LinkNodeFreeFP freefunc)
-{
- LinkNode *node = *list;
- LinkNode *prev = NULL;
+ etags = MEM_callocN(sizeof(EdgeData)*cddm->numEdgeData, "edgedata tag thingies");
+ BLI_array_set_length(etags, cddm->numEdgeData);
- while(node && node->link != value) {
- prev = node;
- node = node->next;
- }
+ mvert = cddm->getVertArray(cddm);
+ BLI_array_set_length(mvert, cddm->numVertData);
+ medge = cddm->getEdgeArray(cddm);
+ BLI_array_set_length(medge, cddm->numEdgeData);
+ mloop = CustomData_get_layer(&cddm->loopData, CD_MLOOP);
+ mpoly = CustomData_get_layer(&cddm->polyData, CD_MPOLY);
- if(node) {
- if(prev)
- prev->next = node->next;
- else
- *list = node->next;
+ for (i=0; i<cddm->numEdgeData; i++) {
+ etags[i].v1 = medge[i].v1;
+ etags[i].v2 = medge[i].v2;
- if(freefunc)
- freefunc(node->link);
+ etags[i].tag = (medge[i].flag & ME_SHARP) != 0;
- MEM_freeN(node);
+ etags[i].v1node.edge = etags+i;
+ etags[i].v2node.edge = etags+i;
}
-}
-
-/* removes all elements in source from target */
-static void linklist_remove_list(LinkNode **target, LinkNode *source,
- LinkNodeFreeFP freefunc)
-{
- for(; source; source = source->next)
- linklist_remove_first(target, source->link, freefunc);
-}
-
-#ifdef EDGESPLIT_DEBUG_0
-static void print_ptr(void *ptr)
-{
- printf("%p\n", ptr);
-}
-static void print_edge(void *ptr)
-{
- SmoothEdge *edge = ptr;
- printf(" %4d", edge->newIndex);
-}
-
-static void print_face(void *ptr)
-{
- SmoothFace *face = ptr;
- printf(" %4d", face->newIndex);
-}
-#endif
-
-typedef struct ReplaceData {
- void *find;
- void *replace;
-} ReplaceData;
-
-static void edge_replace_vert(void *ptr, void *userdata)
-{
- SmoothEdge *edge = ptr;
- SmoothVert *find = ((ReplaceData *)userdata)->find;
- SmoothVert *replace = ((ReplaceData *)userdata)->replace;
- int i;
-
-#ifdef EDGESPLIT_DEBUG_3
- printf("replacing vert %4d with %4d in edge %4d",
- find->newIndex, replace->newIndex, edge->newIndex);
- printf(": {%4d, %4d}", edge->verts[0]->newIndex, edge->verts[1]->newIndex);
-#endif
-
- for(i = 0; i < SMOOTHEDGE_NUM_VERTS; i++) {
- if(edge->verts[i] == find) {
- linklist_append_list_unique(&replace->faces, edge->faces);
- linklist_remove_list(&find->faces, edge->faces, NULL);
-
- edge->verts[i] = replace;
+ if (emd->flags & MOD_EDGESPLIT_FROMANGLE) {
+ mp = mpoly;
+ for (i=0; i<cddm->numPolyData; i++, mp++) {
+ mesh_calc_poly_normal(mp, mloop+mp->loopstart, mvert, no);
+
+ ml = mloop + mp->loopstart;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ if (!etags[ml->e].has_fno) {
+ VECCOPY(etags[ml->e].fno, no);
+ etags[ml->e].has_fno = 1;
+ } else if (!etags[ml->e].tag) {
+ edge_angle_cos = INPR(etags[ml->e].fno, no);
+ if (edge_angle_cos < threshold) {
+ etags[ml->e].tag = 1;
+ }
+ }
+ }
}
}
-#ifdef EDGESPLIT_DEBUG_3
- printf(" -> {%4d, %4d}\n", edge->verts[0]->newIndex, edge->verts[1]->newIndex);
-#endif
-}
+ mp = mpoly;
+ for (i=0; i<cddm->numPolyData; i++, mp++) {
+ ml = mloop + mp->loopstart;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ if (etags[ml->e].tag)
+ continue;
-static void face_replace_vert(void *ptr, void *userdata)
-{
- SmoothFace *face = ptr;
- int i;
+ prevl = mloop + mp->loopstart + ((j-1)+mp->totloop) % mp->totloop;
- for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++)
- edge_replace_vert(face->edges[i], userdata);
-}
+ if (!edge_get_vuser(membase, etags+prevl->e, ml->v)) {
+ vu = new_vuser(membase);
+ vu->ov = vu->v = ml->v;
+ edge_set_vuser(membase, etags+prevl->e, ml->v, vu);
+ }
-static void face_replace_edge(void *ptr, void *userdata)
-{
- SmoothFace *face = ptr;
- SmoothEdge *find = ((ReplaceData *)userdata)->find;
- SmoothEdge *replace = ((ReplaceData *)userdata)->replace;
- int i;
-
-#ifdef EDGESPLIT_DEBUG_3
- printf("replacing edge %4d with %4d in face %4d",
- find->newIndex, replace->newIndex, face->newIndex);
- if(face->edges[3])
- printf(": {%2d %2d %2d %2d}",
- face->edges[0]->newIndex, face->edges[1]->newIndex,
- face->edges[2]->newIndex, face->edges[3]->newIndex);
- else
- printf(": {%2d %2d %2d}",
- face->edges[0]->newIndex, face->edges[1]->newIndex,
- face->edges[2]->newIndex);
-#endif
+ if (!edge_get_vuser(membase, etags+ml->e, ml->v)) {
+ vu = new_vuser(membase);
+ vu->ov = vu->v = ml->v;
+ edge_set_vuser(membase, etags+ml->e, ml->v, vu);
+ }
- for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) {
- if(face->edges[i] == find) {
- linklist_remove_first(&face->edges[i]->faces, face, NULL);
- BLI_linklist_prepend(&replace->faces, face);
- face->edges[i] = replace;
+ /*continue if previous edge is tagged*/
+ if (etags[prevl->e].tag)
+ continue;
+
+ /*merge together adjacent split vert users*/
+ if (edge_get_vuser(membase, etags+prevl->e, ml->v)
+ != edge_get_vuser(membase, etags+ml->e, ml->v))
+ {
+ vu = edge_get_vuser(membase, etags+prevl->e, ml->v);
+ vu2 = edge_get_vuser(membase, etags+ml->e, ml->v);
+
+ /*remove from vu2's users list and add to vu's*/
+ for (e=edge_get_first(vu2); e; e=enext) {
+ enext = edge_get_next(e, ml->v);
+ edge_set_vuser(membase, e, ml->v, vu);
+ }
+ }
}
}
-#ifdef EDGESPLIT_DEBUG_3
- if(face->edges[3])
- printf(" -> {%2d %2d %2d %2d}\n",
- face->edges[0]->newIndex, face->edges[1]->newIndex,
- face->edges[2]->newIndex, face->edges[3]->newIndex);
- else
- printf(" -> {%2d %2d %2d}\n",
- face->edges[0]->newIndex, face->edges[1]->newIndex,
- face->edges[2]->newIndex);
-#endif
-}
+ mp = mpoly;
+ for (i=0; i<cddm->numPolyData; i++, mp++) {
+ ml = mloop + mp->loopstart;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ if (!etags[ml->e].tag)
+ continue;
-static int edge_is_loose(SmoothEdge *edge)
-{
- return !(edge->faces && edge->faces->next);
-}
+ prevl = mloop + mp->loopstart + ((j-1)+mp->totloop) % mp->totloop;
-static int edge_is_sharp(SmoothEdge *edge)
-{
-#ifdef EDGESPLIT_DEBUG_1
- printf("edge %d: ", edge->newIndex);
-#endif
- if(edge->flag & ME_SHARP) {
- /* edge can only be sharp if it has at least 2 faces */
- if(!edge_is_loose(edge)) {
-#ifdef EDGESPLIT_DEBUG_1
- printf("sharp\n");
-#endif
- return 1;
- } else {
- /* edge is loose, so it can't be sharp */
- edge->flag &= ~ME_SHARP;
+ if (!etags[prevl->e].tag) {
+ vu = edge_get_vuser(membase, etags+prevl->e, ml->v);
+ if (!vu) {
+ vu = new_vuser(membase);
+ vu->ov = vu->v = ml->v;
+ edge_set_vuser(membase, etags+prevl->e, ml->v, vu);
+ }
+
+ edge_set_vuser(membase, etags+ml->e, ml->v, vu);
+ } else {
+ vu = new_vuser(membase);
+ vu->ov = vu->v = ml->v;
+ edge_set_vuser(membase, etags+ml->e, ml->v, vu);
+ }
}
}
-#ifdef EDGESPLIT_DEBUG_1
- printf("not sharp\n");
-#endif
- return 0;
-}
-
-/* finds another sharp edge which uses vert, by traversing faces around the
- * vert until it does one of the following:
- * - hits a loose edge (the edge is returned)
- * - hits a sharp edge (the edge is returned)
- * - returns to the start edge (NULL is returned)
- */
-static SmoothEdge *find_other_sharp_edge(SmoothVert *vert, SmoothEdge *edge, LinkNode **visited_faces)
-{
- SmoothFace *face = NULL;
- SmoothEdge *edge2 = NULL;
- /* holds the edges we've seen so we can avoid looping indefinitely */
- LinkNode *visited_edges = NULL;
-#ifdef EDGESPLIT_DEBUG_1
- printf("=== START === find_other_sharp_edge(edge = %4d, vert = %4d)\n",
- edge->newIndex, vert->newIndex);
-#endif
+ curv = cddm->numVertData;
+ cure = cddm->numEdgeData;
+ mp = mpoly;
+ for (i=0; i<cddm->numPolyData; i++, mp++) {
+ ml = mloop + mp->loopstart;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ e = etags + ml->e;
+ if (e->v1user && !e->v1user->done) {
+ e->v1user->done = 1;
+ BLI_array_growone(mvert);
+
+ mvert[curv] = mvert[e->v1user->ov];
+ e->v1user->v = curv;
+
+ curv++;
+ }
- /* get a face on which to start */
- if(edge->faces) face = edge->faces->link;
- else return NULL;
+ if (e->v2user && !e->v2user->done) {
+ e->v2user->done = 1;
+ BLI_array_growone(mvert);
- /* record this edge as visited */
- BLI_linklist_prepend(&visited_edges, edge);
+ mvert[curv] = mvert[e->v2user->ov];
+ e->v2user->v = curv;
- /* get the next edge */
- edge2 = other_edge(face, vert, edge);
+ curv++;
+ }
- /* record this face as visited */
- if(visited_faces)
- BLI_linklist_prepend(visited_faces, face);
+ vu = edge_get_vuser(membase, e, ml->v);
+ if (!vu)
+ continue;
+ ml->v = vu->v;
+
+#if 0 //BMESH_TODO should really handle edges here, but for now use cddm_calc_edges
+ /*ok, now we have to deal with edges. . .*/
+ if (etags[ml->e].tag) {
+ if (etags[ml->e].used) {
+ BLI_array_growone(medge);
+ BLI_array_growone(etags);
+ medge[cure] = medge[ml->e];
+
+ ml->e = cure;
+ etags[cure].used = 1;
+ cure++;
+ }
+
+ vu = etags[ml->e].v1user;
+ vu2 = etags[ml->e].v2user;
+
+ if (vu)
+ medge[ml->e].v1 = vu->v;
+ if (vu2)
+ medge[ml->e].v2 = vu2->v;
+ } else {
+ etags[ml->e].used = 1;
- /* search until we hit a loose edge or a sharp edge or an edge we've
- * seen before
- */
- while(face && !edge_is_sharp(edge2)
- && !linklist_contains(visited_edges, edge2)) {
-#ifdef EDGESPLIT_DEBUG_3
- printf("current face %4d; current edge %4d\n", face->newIndex,
- edge2->newIndex);
-#endif
- /* get the next face */
- face = other_face(edge2, face);
-
- /* if face == NULL, edge2 is a loose edge */
- if(face) {
- /* record this face as visited */
- if(visited_faces)
- BLI_linklist_prepend(visited_faces, face);
-
- /* record this edge as visited */
- BLI_linklist_prepend(&visited_edges, edge2);
-
- /* get the next edge */
- edge2 = other_edge(face, vert, edge2);
-#ifdef EDGESPLIT_DEBUG_3
- printf("next face %4d; next edge %4d\n",
- face->newIndex, edge2->newIndex);
- } else {
- printf("loose edge: %4d\n", edge2->newIndex);
+ if (vu->ov == etags[ml->e].v1)
+ medge[ml->e].v1 = vu->v;
+ else if (vu->ov == etags[ml->e].v2)
+ medge[ml->e].v2 = vu->v;
+ }
#endif
}
- }
-
- /* either we came back to the start edge or we found a sharp/loose edge */
- if(linklist_contains(visited_edges, edge2))
- /* we came back to the start edge */
- edge2 = NULL;
-
- BLI_linklist_free(visited_edges, NULL);
-
-#ifdef EDGESPLIT_DEBUG_1
- printf("=== END === find_other_sharp_edge(edge = %4d, vert = %4d), "
- "returning edge %d\n",
- edge->newIndex, vert->newIndex, edge2 ? edge2->newIndex : -1);
-#endif
- return edge2;
-}
-
-static void split_single_vert(SmoothVert *vert, SmoothFace *face,
- SmoothMesh *mesh)
-{
- SmoothVert *copy_vert;
- ReplaceData repdata;
-
- copy_vert = smoothvert_copy(vert, mesh);
-
- repdata.find = vert;
- repdata.replace = copy_vert;
- face_replace_vert(face, &repdata);
-}
-
-typedef struct PropagateEdge {
- struct PropagateEdge *next, *prev;
- SmoothEdge *edge;
- SmoothVert *vert;
-} PropagateEdge;
-
-static void push_propagate_stack(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh)
-{
- PropagateEdge *pedge = mesh->reusestack.first;
-
- if(pedge) {
- BLI_remlink(&mesh->reusestack, pedge);
}
- else {
- if(!mesh->arena) {
- mesh->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "edgesplit arena");
- BLI_memarena_use_calloc(mesh->arena);
- }
- pedge = BLI_memarena_alloc(mesh->arena, sizeof(PropagateEdge));
- }
- pedge->edge = edge;
- pedge->vert = vert;
- BLI_addhead(&mesh->propagatestack, pedge);
-}
+ /*resize customdata arrays and add new medge/mvert arrays*/
+ vdata = cddm->vertData;
+ edata = cddm->edgeData;
-static void pop_propagate_stack(SmoothEdge **edge, SmoothVert **vert, SmoothMesh *mesh)
-{
- PropagateEdge *pedge = mesh->propagatestack.first;
+ /*make sure we don't copy over mvert/medge layers*/
+ CustomData_set_layer(&vdata, CD_MVERT, NULL);
+ CustomData_set_layer(&edata, CD_MEDGE, NULL);
+ CustomData_free_layer_active(&vdata, CD_MVERT, cddm->numVertData);
+ CustomData_free_layer_active(&edata, CD_MEDGE, cddm->numEdgeData);
- if(pedge) {
- *edge = pedge->edge;
- *vert = pedge->vert;
- BLI_remlink(&mesh->propagatestack, pedge);
- BLI_addhead(&mesh->reusestack, pedge);
- }
- else {
- *edge = NULL;
- *vert = NULL;
- }
-}
+ memset(&cddm->vertData, 0, sizeof(CustomData));
+ memset(&cddm->edgeData, 0, sizeof(CustomData));
-static void split_edge(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh);
+ CustomData_copy(&vdata, &cddm->vertData, CD_MASK_DERIVEDMESH, CD_CALLOC, curv);
+ CustomData_copy_data(&vdata, &cddm->vertData, 0, 0, cddm->numVertData);
+ CustomData_free(&vdata, cddm->numVertData);
+ cddm->numVertData = curv;
-static void propagate_split(SmoothEdge *edge, SmoothVert *vert,
- SmoothMesh *mesh)
-{
- SmoothEdge *edge2;
- LinkNode *visited_faces = NULL;
-#ifdef EDGESPLIT_DEBUG_1
- printf("=== START === propagate_split(edge = %4d, vert = %4d)\n",
- edge->newIndex, vert->newIndex);
-#endif
+ CustomData_copy(&edata, &cddm->edgeData, CD_MASK_DERIVEDMESH, CD_CALLOC, cure);
+ CustomData_copy_data(&edata, &cddm->edgeData, 0, 0, cddm->numEdgeData);
+ CustomData_free(&edata, cddm->numEdgeData);
+ cddm->numEdgeData = cure;
- edge2 = find_other_sharp_edge(vert, edge, &visited_faces);
-
- if(!edge2) {
- /* didn't find a sharp or loose edge, so we've hit a dead end */
- } else if(!edge_is_loose(edge2)) {
- /* edge2 is not loose, so it must be sharp */
- if(edge_is_loose(edge)) {
- /* edge is loose, so we can split edge2 at this vert */
- split_edge(edge2, vert, mesh);
- } else if(edge_is_sharp(edge)) {
- /* both edges are sharp, so we can split the pair at vert */
- split_edge(edge, vert, mesh);
- } else {
- /* edge is not sharp, so try to split edge2 at its other vert */
- split_edge(edge2, other_vert(edge2, vert), mesh);
- }
- } else { /* edge2 is loose */
- if(edge_is_loose(edge)) {
- SmoothVert *vert2;
- ReplaceData repdata;
-
- /* can't split edge, what should we do with vert? */
- if(linklist_subset(vert->faces, visited_faces)) {
- /* vert has only one fan of faces attached; don't split it */
- } else {
- /* vert has more than one fan of faces attached; split it */
- vert2 = smoothvert_copy(vert, mesh);
+ CDDM_set_mvert(cddm, mvert);
+ CDDM_set_medge(cddm, medge);
- /* replace vert with its copy in visited_faces */
- repdata.find = vert;
- repdata.replace = vert2;
- BLI_linklist_apply(visited_faces, face_replace_vert, &repdata);
- }
- } else {
- /* edge is not loose, so it must be sharp; split it */
- split_edge(edge, vert, mesh);
- }
- }
+ free_membase(membase);
+ MEM_freeN(etags);
- BLI_linklist_free(visited_faces, NULL);
-#ifdef EDGESPLIT_DEBUG_1
- printf("=== END === propagate_split(edge = %4d, vert = %4d)\n",
- edge->newIndex, vert->newIndex);
-#endif
-}
+ /*edge calculation isn't working correctly, so just brute force it*/
+ cddm->numEdgeData = 0;
+ CDDM_calc_edges_poly(cddm);
-static void split_edge(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh)
-{
- SmoothEdge *edge2;
- SmoothVert *vert2;
- ReplaceData repdata;
- /* the list of faces traversed while looking for a sharp edge */
- LinkNode *visited_faces = NULL;
-#ifdef EDGESPLIT_DEBUG_1
- printf("=== START === split_edge(edge = %4d, vert = %4d)\n",
- edge->newIndex, vert->newIndex);
-#endif
+ cddm->numFaceData = mesh_recalcTesselation(&cddm->faceData,
+ &cddm->loopData, &cddm->polyData,
+ mvert, cddm->numFaceData,
+ cddm->numLoopData, cddm->numPolyData, 1, 0);
- edge2 = find_other_sharp_edge(vert, edge, &visited_faces);
-
- if(!edge2) {
- /* didn't find a sharp or loose edge, so try the other vert */
- vert2 = other_vert(edge, vert);
- push_propagate_stack(edge, vert2, mesh);
- } else if(!edge_is_loose(edge2)) {
- /* edge2 is not loose, so it must be sharp */
- SmoothEdge *copy_edge = smoothedge_copy(edge, mesh);
- SmoothEdge *copy_edge2 = smoothedge_copy(edge2, mesh);
- SmoothVert *vert2;
-
- /* replace edge with its copy in visited_faces */
- repdata.find = edge;
- repdata.replace = copy_edge;
- BLI_linklist_apply(visited_faces, face_replace_edge, &repdata);
-
- /* replace edge2 with its copy in visited_faces */
- repdata.find = edge2;
- repdata.replace = copy_edge2;
- BLI_linklist_apply(visited_faces, face_replace_edge, &repdata);
-
- vert2 = smoothvert_copy(vert, mesh);
-
- /* replace vert with its copy in visited_faces (must be done after
- * edge replacement so edges have correct vertices)
- */
- repdata.find = vert;
- repdata.replace = vert2;
- BLI_linklist_apply(visited_faces, face_replace_vert, &repdata);
-
- /* all copying and replacing is done; the mesh should be consistent.
- * now propagate the split to the vertices at either end
- */
- push_propagate_stack(copy_edge, other_vert(copy_edge, vert2), mesh);
- push_propagate_stack(copy_edge2, other_vert(copy_edge2, vert2), mesh);
-
- if(smoothedge_has_vert(edge, vert))
- push_propagate_stack(edge, vert, mesh);
- } else {
- /* edge2 is loose */
- SmoothEdge *copy_edge = smoothedge_copy(edge, mesh);
- SmoothVert *vert2;
-
- /* replace edge with its copy in visited_faces */
- repdata.find = edge;
- repdata.replace = copy_edge;
- BLI_linklist_apply(visited_faces, face_replace_edge, &repdata);
-
- vert2 = smoothvert_copy(vert, mesh);
-
- /* replace vert with its copy in visited_faces (must be done after
- * edge replacement so edges have correct vertices)
- */
- repdata.find = vert;
- repdata.replace = vert2;
- BLI_linklist_apply(visited_faces, face_replace_vert, &repdata);
-
- /* copying and replacing is done; the mesh should be consistent.
- * now propagate the split to the vertex at the other end
- */
- push_propagate_stack(copy_edge, other_vert(copy_edge, vert2), mesh);
-
- if(smoothedge_has_vert(edge, vert))
- push_propagate_stack(edge, vert, mesh);
- }
+ CDDM_set_mface(cddm, DM_get_tessface_data_layer(cddm, CD_MFACE));
+ CDDM_calc_normals(cddm);
- BLI_linklist_free(visited_faces, NULL);
-#ifdef EDGESPLIT_DEBUG_1
- printf("=== END === split_edge(edge = %4d, vert = %4d)\n",
- edge->newIndex, vert->newIndex);
-#endif
+ return cddm;
}
-static void tag_and_count_extra_edges(SmoothMesh *mesh, float split_angle,
- int flags, int *extra_edges)
-{
- /* if normal1 dot normal2 < threshold, angle is greater, so split */
- /* FIXME not sure if this always works */
- /* 0.00001 added for floating-point rounding */
- float threshold = cos((split_angle + 0.00001) * M_PI / 180.0);
- int i;
-
- *extra_edges = 0;
-
- /* loop through edges, counting potential new ones */
- for(i = 0; i < mesh->num_edges; i++) {
- SmoothEdge *edge = &mesh->edges[i];
- int sharp = 0;
-
- /* treat all non-manifold edges (3 or more faces) as sharp */
- if(edge->faces && edge->faces->next && edge->faces->next->next) {
- LinkNode *node;
-
- /* this edge is sharp */
- sharp = 1;
-
- /* add an extra edge for every face beyond the first */
- *extra_edges += 2;
- for(node = edge->faces->next->next->next; node; node = node->next)
- (*extra_edges)++;
- } else if((flags & (MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG))
- && !edge_is_loose(edge)) {
- /* (the edge can only be sharp if we're checking angle or flag,
- * and it has at least 2 faces) */
-
- /* if we're checking the sharp flag and it's set, good */
- if((flags & MOD_EDGESPLIT_FROMFLAG) && (edge->flag & ME_SHARP)) {
- /* this edge is sharp */
- sharp = 1;
-
- (*extra_edges)++;
- } else if(flags & MOD_EDGESPLIT_FROMANGLE) {
- /* we know the edge has 2 faces, so check the angle */
- SmoothFace *face1 = edge->faces->link;
- SmoothFace *face2 = edge->faces->next->link;
- float edge_angle_cos = dot_v3v3(face1->normal,
- face2->normal);
-
- if(edge_angle_cos < threshold) {
- /* this edge is sharp */
- sharp = 1;
-
- (*extra_edges)++;
- }
- }
- }
-
- /* set/clear sharp flag appropriately */
- if(sharp) edge->flag |= ME_SHARP;
- else edge->flag &= ~ME_SHARP;
- }
-}
-static void split_sharp_edges(SmoothMesh *mesh, float split_angle, int flags)
-{
- SmoothVert *vert;
- int i;
- /* if normal1 dot normal2 < threshold, angle is greater, so split */
- /* FIXME not sure if this always works */
- /* 0.00001 added for floating-point rounding */
- mesh->threshold = cos((split_angle + 0.00001) * M_PI / 180.0);
- mesh->flags = flags;
-
- /* loop through edges, splitting sharp ones */
- /* can't use an iterator here, because we'll be adding edges */
- for(i = 0; i < mesh->num_edges; i++) {
- SmoothEdge *edge = &mesh->edges[i];
-
- if(edge_is_sharp(edge)) {
- split_edge(edge, edge->verts[0], mesh);
-
- do {
- pop_propagate_stack(&edge, &vert, mesh);
- if(edge && smoothedge_has_vert(edge, vert))
- propagate_split(edge, vert, mesh);
- } while(edge);
- }
- }
-}
-
-static int count_bridge_verts(SmoothMesh *mesh)
+static void initData(ModifierData *md)
{
- int i, j, count = 0;
-
- for(i = 0; i < mesh->num_faces; i++) {
- SmoothFace *face = &mesh->faces[i];
-
- for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
- SmoothEdge *edge = face->edges[j];
- SmoothEdge *next_edge;
- SmoothVert *vert = edge->verts[1 - face->flip[j]];
- int next = (j + 1) % SMOOTHFACE_MAX_EDGES;
-
- /* wrap next around if at last edge */
- if(!face->edges[next]) next = 0;
-
- next_edge = face->edges[next];
-
- /* if there are other faces sharing this vertex but not
- * these edges, the vertex will be split, so count it
- */
- /* vert has to have at least one face (this one), so faces != 0 */
- if(!edge->faces->next && !next_edge->faces->next
- && vert->faces->next) {
- count++;
- }
- }
- }
+ EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
- /* each bridge vert will be counted once per face that uses it,
- * so count is too high, but it's ok for now
+ /* default to 30-degree split angle, sharpness from both angle & flag
*/
- return count;
+ emd->split_angle = 30;
+ emd->flags = MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG;
}
-static void split_bridge_verts(SmoothMesh *mesh)
+static void copyData(ModifierData *md, ModifierData *target)
{
- int i,j;
-
- for(i = 0; i < mesh->num_faces; i++) {
- SmoothFace *face = &mesh->faces[i];
-
- for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
- SmoothEdge *edge = face->edges[j];
- SmoothEdge *next_edge;
- SmoothVert *vert = edge->verts[1 - face->flip[j]];
- int next = (j + 1) % SMOOTHFACE_MAX_EDGES;
-
- /* wrap next around if at last edge */
- if(!face->edges[next]) next = 0;
-
- next_edge = face->edges[next];
-
- /* if there are other faces sharing this vertex but not
- * these edges, split the vertex
- */
- /* vert has to have at least one face (this one), so faces != 0 */
- if(!edge->faces->next && !next_edge->faces->next
- && vert->faces->next)
- /* FIXME this needs to find all faces that share edges with
- * this one and split off together
- */
- split_single_vert(vert, face, mesh);
- }
- }
+ EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
+ EdgeSplitModifierData *temd = (EdgeSplitModifierData*) target;
+
+ temd->split_angle = emd->split_angle;
+ temd->flags = emd->flags;
}
-static DerivedMesh *edgesplitModifier_do(EdgeSplitModifierData *emd, DerivedMesh *dm)
+static DerivedMesh *edgesplitModifier_do(EdgeSplitModifierData *emd,
+ Object *ob, DerivedMesh *dm)
{
- SmoothMesh *mesh;
- DerivedMesh *result;
- int max_verts, max_edges;
-
if(!(emd->flags & (MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG)))
return dm;
- /* 1. make smoothmesh with initial number of elements */
- mesh = smoothmesh_from_derivedmesh(dm);
-
- /* 2. count max number of elements to add */
- tag_and_count_extra_edges(mesh, emd->split_angle, emd->flags, &max_edges);
- max_verts = max_edges * 2 + mesh->max_verts;
- max_verts += count_bridge_verts(mesh);
- max_edges += mesh->max_edges;
-
- /* 3. reallocate smoothmesh arrays & copy elements across */
- /* 4. remap copied elements' pointers to point into the new arrays */
- smoothmesh_resize_verts(mesh, max_verts);
- smoothmesh_resize_edges(mesh, max_edges);
-
-#ifdef EDGESPLIT_DEBUG_1
- printf("********** Pre-split **********\n");
- smoothmesh_print(mesh);
-#endif
-
- split_sharp_edges(mesh, emd->split_angle, emd->flags);
-#ifdef EDGESPLIT_DEBUG_1
- printf("********** Post-edge-split **********\n");
- smoothmesh_print(mesh);
-#endif
-
- split_bridge_verts(mesh);
-
-#ifdef EDGESPLIT_DEBUG_1
- printf("********** Post-vert-split **********\n");
- smoothmesh_print(mesh);
-#endif
-
-#ifdef EDGESPLIT_DEBUG_0
- printf("Edgesplit: Estimated %d verts & %d edges, "
- "found %d verts & %d edges\n", max_verts, max_edges,
- mesh->num_verts, mesh->num_edges);
-#endif
-
- result = CDDM_from_smoothmesh(mesh);
- smoothmesh_free(mesh);
-
- return result;
+ return doEdgeSplit(dm, emd);
}
-static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
- DerivedMesh *derivedData,
- int UNUSED(useRenderParams),
- int UNUSED(isFinalCalc))
+static DerivedMesh *applyModifier(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ int useRenderParams, int isFinalCalc)
{
DerivedMesh *result;
EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
- result = edgesplitModifier_do(emd, derivedData);
+ result = edgesplitModifier_do(emd, ob, derivedData);
if(result != derivedData)
CDDM_calc_normals(result);
@@ -1264,8 +429,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
- struct EditMesh *UNUSED(editData),
- DerivedMesh *derivedData)
+ BMEditMesh *editData, DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
}
@@ -1284,7 +448,7 @@ ModifierTypeInfo modifierType_EdgeSplit = {
/* copyData */ copyData,
/* deformVerts */ 0,
- /* deformMatrices */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
@@ -1295,7 +459,6 @@ ModifierTypeInfo modifierType_EdgeSplit = {
/* isDisabled */ 0,
/* updateDepgraph */ 0,
/* dependsOnTime */ 0,
- /* dependsOnNormals */ 0,
/* foreachObjectLink */ 0,
/* foreachIDLink */ 0,
};
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index aea6997c5d5..04687958efd 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -110,8 +110,8 @@ static void createFacepa(ExplodeModifierData *emd,
int i,p,v1,v2,v3,v4=0;
mvert = dm->getVertArray(dm);
- mface = dm->getFaceArray(dm);
- totface= dm->getNumFaces(dm);
+ mface = dm->getTessFaceArray(dm);
+ totface= dm->getNumTessFaces(dm);
totvert= dm->getNumVerts(dm);
totpart= psmd->psys->totpart;
@@ -200,7 +200,7 @@ const short add_faces[24] = {
MFace *get_dface(DerivedMesh *dm, DerivedMesh *split, int cur, int i, MFace *mf)
{
- MFace *df = CDDM_get_face(split, cur);
+ MFace *df = CDDM_get_tessface(split, cur);
DM_copy_face_data(dm, split, i, cur, 1);
*df = *mf;
return df;
@@ -547,12 +547,12 @@ static void remap_uvs_23(DerivedMesh *dm, DerivedMesh *split, int numlayer, int
static DerivedMesh * cutEdges(ExplodeModifierData *emd, DerivedMesh *dm){
DerivedMesh *splitdm;
MFace *mf=NULL,*df1=NULL;
- MFace *mface=dm->getFaceArray(dm);
+ MFace *mface=dm->getTessFaceArray(dm);
MVert *dupve, *mv;
EdgeHash *edgehash;
EdgeHashIterator *ehi;
int totvert=dm->getNumVerts(dm);
- int totface=dm->getNumFaces(dm);
+ int totface=dm->getNumTessFaces(dm);
int *facesplit = MEM_callocN(sizeof(int)*totface,"explode_facesplit");
int *vertpa = MEM_callocN(sizeof(int)*totvert,"explode_vertpa2");
@@ -628,7 +628,7 @@ static DerivedMesh * cutEdges(ExplodeModifierData *emd, DerivedMesh *dm){
for(i=0,fs=facesplit; i<totface; i++,fs++)
totfsplit += add_faces[*fs];
- splitdm= CDDM_from_template(dm, totesplit, 0, totface+totfsplit);
+ splitdm= CDDM_from_template(dm, totesplit, 0, totface+totfsplit, 0, 0);
numlayer = CustomData_number_of_layers(&splitdm->faceData, CD_MTFACE);
/* copy new faces & verts (is it really this painful with custom data??) */
@@ -670,7 +670,7 @@ static DerivedMesh * cutEdges(ExplodeModifierData *emd, DerivedMesh *dm){
curdupface=0;//=totface;
//curdupin=totesplit;
for(i=0,fs=facesplit; i<totface; i++,fs++){
- mf = dm->getFaceData(dm, i, CD_MFACE);
+ mf = dm->getTessFaceData(dm, i, CD_MFACE);
switch(*fs) {
case 3:
@@ -760,7 +760,7 @@ static DerivedMesh * cutEdges(ExplodeModifierData *emd, DerivedMesh *dm){
}
for(i=0; i<curdupface; i++) {
- mf = CDDM_get_face(splitdm, i);
+ mf = CDDM_get_tessface(splitdm, i);
test_index_face(mf, &splitdm->faceData, i, (mf->flag & ME_FACE_SEL ? 4 : 3));
}
@@ -768,8 +768,11 @@ static DerivedMesh * cutEdges(ExplodeModifierData *emd, DerivedMesh *dm){
MEM_freeN(facesplit);
MEM_freeN(vertpa);
- return splitdm;
+ dm = CDDM_copy(splitdm, 1); /*builds ngon faces from tess (mface) faces*/
+ splitdm->needsFree = 1;
+ splitdm->release(splitdm);
+ return dm;
}
static DerivedMesh * explodeMesh(ExplodeModifierData *emd,
ParticleSystemModifierData *psmd, Scene *scene, Object *ob,
@@ -792,9 +795,9 @@ static DerivedMesh * explodeMesh(ExplodeModifierData *emd,
int i, j, v, mindex=0;
MTFace *mtface = NULL, *mtf;
- totface= dm->getNumFaces(dm);
+ totface= dm->getNumTessFaces(dm);
totvert= dm->getNumVerts(dm);
- mface= dm->getFaceArray(dm);
+ mface= dm->getTessFaceArray(dm);
totpart= psmd->psys->totpart;
sim.scene= scene;
@@ -839,7 +842,7 @@ static DerivedMesh * explodeMesh(ExplodeModifierData *emd,
BLI_edgehashIterator_free(ehi);
/* the final duplicated vertices */
- explode= CDDM_from_template(dm, totdup, 0,totface);
+ explode= CDDM_from_template(dm, totdup, 0,totface, 0, 0);
mtface = CustomData_get_layer_named(&explode->faceData, CD_MTFACE, emd->uvname);
/*dupvert= CDDM_get_verts(explode);*/
@@ -907,8 +910,8 @@ static DerivedMesh * explodeMesh(ExplodeModifierData *emd,
if(pa->alive==PARS_DEAD && (emd->flag&eExplodeFlag_Dead)==0) continue;
}
- dm->getFace(dm,i,&source);
- mf=CDDM_get_face(explode,i);
+ dm->getTessFace(dm,i,&source);
+ mf=CDDM_get_tessface(explode,i);
orig_v4 = source.v4;
@@ -954,6 +957,10 @@ static DerivedMesh * explodeMesh(ExplodeModifierData *emd,
psmd->psys->lattice= NULL;
}
+ dm = CDDM_copy(explode, 1); /*builds ngon faces from tess (mface) faces*/
+ explode->needsFree = 1;
+ explode->release(explode);
+
return explode;
}
@@ -988,7 +995,7 @@ static DerivedMesh * applyModifier(ModifierData *md, Object *ob,
if(emd->facepa==0
|| psmd->flag&eParticleSystemFlag_Pars
|| emd->flag&eExplodeFlag_CalcFaces
- || MEM_allocN_len(emd->facepa)/sizeof(int) != dm->getNumFaces(dm))
+ || MEM_allocN_len(emd->facepa)/sizeof(int) != dm->getNumTessFaces(dm))
{
if(psmd->flag & eParticleSystemFlag_Pars)
psmd->flag &= ~eParticleSystemFlag_Pars;
diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c
index 02912e38204..7db1f003146 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c
@@ -227,7 +227,7 @@ static DerivedMesh *fluidsim_read_obj(const char *filename)
return NULL;
}
- dm = CDDM_new(numverts, 0, numfaces);
+ dm = CDDM_new(numverts, 0, numfaces, 0, 0);
if(!dm)
{
@@ -283,7 +283,7 @@ static DerivedMesh *fluidsim_read_obj(const char *filename)
}
// read triangles from file
- mf = CDDM_get_faces(dm);
+ mf = CDDM_get_tessfaces(dm);
for(i=numfaces; i>0; i--, mf++)
{
int face[3];
@@ -510,12 +510,12 @@ static DerivedMesh *fluidsim_read_cache(DerivedMesh *orgdm, FluidsimModifierData
}
// assign material + flags to new dm
- mface = orgdm->getFaceArray(orgdm);
+ mface = orgdm->getTessFaceArray(orgdm);
mat_nr = mface[0].mat_nr;
flag = mface[0].flag;
- mface = dm->getFaceArray(dm);
- numfaces = dm->getNumFaces(dm);
+ mface = dm->getTessFaceArray(dm);
+ numfaces = dm->getNumTessFaces(dm);
for(i=0; i<numfaces; i++)
{
mface[i].mat_nr = mat_nr;
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index 9519e5b9131..7b969f9322e 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -116,7 +116,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
/* get original number of verts, edges, and faces */
maxVerts= dm->getNumVerts(dm);
maxEdges= dm->getNumEdges(dm);
- maxFaces= dm->getNumFaces(dm);
+ maxFaces= dm->getNumTessFaces(dm);
/* check if we can just return the original mesh
* - must have verts and therefore verts assigned to vgroups to do anything useful
@@ -294,7 +294,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
for (i = 0; i < maxFaces; i++)
{
MFace mf;
- dm->getFace(dm, i, &mf);
+ dm->getTessFace(dm, i, &mf);
/* all verts must be available */
if ( BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1)) &&
@@ -311,7 +311,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
/* now we know the number of verts, edges and faces,
* we can create the new (reduced) mesh
*/
- result = CDDM_from_template(dm, numVerts, numEdges, numFaces);
+ result = CDDM_from_template(dm, numVerts, numEdges, numFaces, 0, 0);
/* using ghash-iterators, map data into new mesh */
@@ -365,8 +365,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
int orig_v4;
- dm->getFace(dm, oldIndex, &source);
- dest = CDDM_get_face(result, newIndex);
+ dm->getTessFace(dm, oldIndex, &source);
+ dest = CDDM_get_tessface(result, newIndex);
orig_v4 = source.v4;
@@ -392,7 +392,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
BLI_ghash_free(faceHash, NULL, NULL);
/* return the new mesh */
- return result;
+ dm = CDDM_copy(result, 1); /*builds ngon faces from tess (mface) faces*/
+ result->needsFree = 1;
+ result->release(result);
+
+ return dm;
}
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index a6b4a5dabcd..a34eff6120c 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -34,7 +34,7 @@
* \ingroup modifiers
*/
-
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -47,6 +47,7 @@
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
+#include "BKE_tessmesh.h"
#include "depsgraph_private.h"
@@ -185,7 +186,7 @@ static void meshdeformModifier_do(
{
MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
struct Mesh *me= (mmd->object)? mmd->object->data: NULL;
- struct EditMesh *em = (me)? BKE_mesh_get_editmesh(me): NULL;
+ BMEditMesh *em = me ? me->edit_btmesh : NULL;
DerivedMesh *tmpdm, *cagedm;
MDeformVert *dvert = NULL;
MDeformWeight *dw;
@@ -201,10 +202,9 @@ static void meshdeformModifier_do(
/* get cage derivedmesh */
if(em) {
- tmpdm= editmesh_get_derived_cage_and_final(md->scene, ob, em, &cagedm, 0);
+ tmpdm= editbmesh_get_derived_cage_and_final(md->scene, ob, em, &cagedm, 0);
if(tmpdm)
tmpdm->release(tmpdm);
- BKE_mesh_end_editmesh(me, em);
}
else
cagedm= mmd->object->derivedFinal;
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index cf31e86a2f5..2540a1e3b3b 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -30,28 +30,21 @@
*
*/
-/** \file blender/modifiers/intern/MOD_mirror.c
- * \ingroup modifiers
- */
-
-
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "BLI_math.h"
-#include "BLI_utildefines.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
-
+#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
#include "MEM_guardedalloc.h"
#include "depsgraph_private.h"
-#include "MOD_util.h"
-
static void initData(ModifierData *md)
{
MirrorModifierData *mmd = (MirrorModifierData*) md;
@@ -69,7 +62,7 @@ static void copyData(ModifierData *md, ModifierData *target)
tmmd->axis = mmd->axis;
tmmd->flag = mmd->flag;
tmmd->tolerance = mmd->tolerance;
- tmmd->mirror_ob = mmd->mirror_ob;
+ tmmd->mirror_ob = mmd->mirror_ob;;
}
static void foreachObjectLink(
@@ -78,14 +71,13 @@ static void foreachObjectLink(
void *userData)
{
MirrorModifierData *mmd = (MirrorModifierData*) md;
-
- walk(userData, ob, &mmd->mirror_ob);
+
+ if (mmd->mirror_ob)
+ walk(userData, ob, &mmd->mirror_ob);
}
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
+static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *scene,
+ Object *ob, DagNode *obNode)
{
MirrorModifierData *mmd = (MirrorModifierData*) md;
@@ -97,194 +89,108 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
-static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
+
+/* Mirror */
+#define VERT_NEW 1
+
+void vertgroup_flip_name (char *name, int strip_number);
+DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
Object *ob,
DerivedMesh *dm,
int initFlags,
int axis)
{
- int i;
float tolerance = mmd->tolerance;
- DerivedMesh *result;
- int numVerts, numEdges, numFaces;
- int maxVerts = dm->getNumVerts(dm);
- int maxEdges = dm->getNumEdges(dm);
- int maxFaces = dm->getNumFaces(dm);
- int *flip_map= NULL;
- int do_vgroup_mirr= (mmd->flag & MOD_MIR_VGROUP);
- int (*indexMap)[2];
+ DerivedMesh *result, *cddm;
+ BMEditMesh *em;
+ BMesh *bm;
+ BMOIter siter1;
+ BMOperator op;
+ BMVert *v1;
+ BMIter iter;
+ bDeformGroup *def, *defb;
+ bDeformGroup **vector_def = NULL;
float mtx[4][4], imtx[4][4];
-
- numVerts = numEdges = numFaces = 0;
-
- indexMap = MEM_mallocN(sizeof(*indexMap) * maxVerts, "indexmap");
-
- result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2);
-
-
- if (do_vgroup_mirr) {
- flip_map= defgroup_flip_map(ob, 0);
- if(flip_map == NULL)
- do_vgroup_mirr= 0;
+ int j;
+ int vector_size=0, a, b;
+
+ cddm = dm; //copying shouldn't be necassary here, as all modifiers return CDDM's
+ em = CDDM_To_BMesh(dm, NULL);
+
+ /*convienence variable*/
+ bm = em->bm;
+
+ if (mmd->flag & MOD_MIR_VGROUP) {
+ /* calculate the number of deformedGroups */
+ for(vector_size = 0, def = ob->defbase.first; def;
+ def = def->next, vector_size++);
+
+ /* load the deformedGroups for fast access */
+ vector_def =
+ (bDeformGroup **)MEM_mallocN(sizeof(bDeformGroup*) * vector_size,
+ "group_index");
+ for(a = 0, def = ob->defbase.first; def; def = def->next, a++) {
+ vector_def[a] = def;
+ }
}
if (mmd->mirror_ob) {
- float obinv[4][4];
-
- invert_m4_m4(obinv, mmd->mirror_ob->obmat);
- mul_m4_m4m4(mtx, ob->obmat, obinv);
- invert_m4_m4(imtx, mtx);
- }
+ float mtx2[4][4];
- for(i = 0; i < maxVerts; i++) {
- MVert inMV;
- MVert *mv = CDDM_get_vert(result, numVerts);
- int isShared;
- float co[3];
-
- dm->getVert(dm, i, &inMV);
-
- copy_v3_v3(co, inMV.co);
-
- if (mmd->mirror_ob) {
- mul_m4_v3(mtx, co);
- }
-
- if(mmd->flag & MOD_MIR_NO_MERGE)
- isShared = 0;
- else
- isShared = ABS(co[axis])<=tolerance;
-
- /* Because the topology result (# of vertices) must be the same if
- * the mesh data is overridden by vertex cos, have to calc sharedness
- * based on original coordinates. This is why we test before copy.
- */
- DM_copy_vert_data(dm, result, i, numVerts, 1);
- *mv = inMV;
- numVerts++;
-
- indexMap[i][0] = numVerts - 1;
- indexMap[i][1] = !isShared;
- //
- if(isShared ) {
- co[axis] = 0;
- if (mmd->mirror_ob) {
- mul_m4_v3(imtx, co);
- }
- copy_v3_v3(mv->co, co);
-
- mv->flag |= ME_VERT_MERGED;
- } else {
- MVert *mv2 = CDDM_get_vert(result, numVerts);
-
- DM_copy_vert_data(dm, result, i, numVerts, 1);
- *mv2 = *mv;
-
- co[axis] = -co[axis];
- if (mmd->mirror_ob) {
- mul_m4_v3(imtx, co);
- }
- copy_v3_v3(mv2->co, co);
-
- if (do_vgroup_mirr) {
- MDeformVert *dvert= DM_get_vert_data(result, numVerts, CD_MDEFORMVERT);
- if(dvert) {
- defvert_flip(dvert, flip_map);
- }
- }
-
- numVerts++;
- }
+ invert_m4_m4(mtx2, mmd->mirror_ob->obmat);
+ mul_m4_m4m4(mtx, ob->obmat, mtx2);
+ } else {
+ unit_m4(mtx);
}
- for(i = 0; i < maxEdges; i++) {
- MEdge inMED;
- MEdge *med = CDDM_get_edge(result, numEdges);
-
- dm->getEdge(dm, i, &inMED);
-
- DM_copy_edge_data(dm, result, i, numEdges, 1);
- *med = inMED;
- numEdges++;
-
- med->v1 = indexMap[inMED.v1][0];
- med->v2 = indexMap[inMED.v2][0];
- if(initFlags)
- med->flag |= ME_EDGEDRAW | ME_EDGERENDER;
-
- if(indexMap[inMED.v1][1] || indexMap[inMED.v2][1]) {
- MEdge *med2 = CDDM_get_edge(result, numEdges);
-
- DM_copy_edge_data(dm, result, i, numEdges, 1);
- *med2 = *med;
- numEdges++;
-
- med2->v1 += indexMap[inMED.v1][1];
- med2->v2 += indexMap[inMED.v2][1];
- }
- }
+ BMO_InitOpf(bm, &op, "mirror geom=%avef mat=%m4 mergedist=%f axis=%d",
+ mtx, mmd->tolerance, axis);
+
+ BMO_Exec_Op(bm, &op);
- for(i = 0; i < maxFaces; i++) {
- MFace inMF;
- MFace *mf = CDDM_get_face(result, numFaces);
-
- dm->getFace(dm, i, &inMF);
-
- DM_copy_face_data(dm, result, i, numFaces, 1);
- *mf = inMF;
- numFaces++;
-
- mf->v1 = indexMap[inMF.v1][0];
- mf->v2 = indexMap[inMF.v2][0];
- mf->v3 = indexMap[inMF.v3][0];
- mf->v4 = indexMap[inMF.v4][0];
-
- if(indexMap[inMF.v1][1]
- || indexMap[inMF.v2][1]
- || indexMap[inMF.v3][1]
- || (mf->v4 && indexMap[inMF.v4][1])) {
- MFace *mf2 = CDDM_get_face(result, numFaces);
- static int corner_indices[4] = {2, 1, 0, 3};
-
- DM_copy_face_data(dm, result, i, numFaces, 1);
- *mf2 = *mf;
-
- mf2->v1 += indexMap[inMF.v1][1];
- mf2->v2 += indexMap[inMF.v2][1];
- mf2->v3 += indexMap[inMF.v3][1];
- if(inMF.v4) mf2->v4 += indexMap[inMF.v4][1];
-
- /* mirror UVs if enabled */
- if(mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) {
- MTFace *tf = result->getFaceData(result, numFaces, CD_MTFACE);
- if(tf) {
- int j;
- for(j = 0; j < 4; ++j) {
- if(mmd->flag & MOD_MIR_MIRROR_U)
- tf->uv[j][0] = 1.0f - tf->uv[j][0];
- if(mmd->flag & MOD_MIR_MIRROR_V)
- tf->uv[j][1] = 1.0f - tf->uv[j][1];
+ BMO_CallOpf(bm, "reversefaces faces=%s", &op, "newout");
+
+ /*handle vgroup stuff*/
+ if (mmd->flag & MOD_MIR_VGROUP) {
+ BMO_ITER(v1, &siter1, bm, &op, "newout", BM_VERT) {
+ MDeformVert *dvert = CustomData_bmesh_get(&bm->vdata, v1->head.data, CD_MDEFORMVERT);
+
+ if (dvert) {
+ for(j = 0; j < dvert[0].totweight; ++j) {
+ char tmpname[32];
+
+ if(dvert->dw[j].def_nr < 0 ||
+ dvert->dw[j].def_nr >= vector_size)
+ continue;
+
+ def = vector_def[dvert->dw[j].def_nr];
+ strcpy(tmpname, def->name);
+ vertgroup_flip_name(tmpname,0);
+
+ for(b = 0, defb = ob->defbase.first; defb;
+ defb = defb->next, b++)
+ {
+ if(!strcmp(defb->name, tmpname))
+ {
+ dvert->dw[j].def_nr = b;
+ break;
+ }
}
}
}
-
- /* Flip face normal */
- SWAP(int, mf2->v1, mf2->v3);
- DM_swap_face_data(result, numFaces, corner_indices);
-
- test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3);
- numFaces++;
}
}
- if (flip_map) MEM_freeN(flip_map);
-
- MEM_freeN(indexMap);
+ BMO_Finish_Op(bm, &op);
- CDDM_lower_num_verts(result, numVerts);
- CDDM_lower_num_edges(result, numEdges);
- CDDM_lower_num_faces(result, numFaces);
+ if (vector_def) MEM_freeN(vector_def);
+
+ BMEdit_RecalcTesselation(em);
+ result = CDDM_from_BMEditMesh(em, NULL);
+ BMEdit_Free(em);
+ MEM_freeN(em);
+
return result;
}
@@ -312,10 +218,9 @@ static DerivedMesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
return result;
}
-static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
- int UNUSED(useRenderParams),
- int UNUSED(isFinalCalc))
+static DerivedMesh *applyModifier(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ int useRenderParams, int isFinalCalc)
{
DerivedMesh *result;
MirrorModifierData *mmd = (MirrorModifierData*) md;
@@ -328,9 +233,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
return result;
}
-static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
- struct EditMesh *UNUSED(editData),
- DerivedMesh *derivedData)
+static DerivedMesh *applyModifierEM(
+ ModifierData *md, Object *ob, struct BMEditMesh *editData,
+ DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
}
@@ -349,8 +254,8 @@ ModifierTypeInfo modifierType_Mirror = {
/* copyData */ copyData,
/* deformVerts */ 0,
- /* deformMatrices */ 0,
/* deformVertsEM */ 0,
+ /* deformMatrices */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
/* applyModifierEM */ applyModifierEM,
@@ -360,7 +265,6 @@ ModifierTypeInfo modifierType_Mirror = {
/* isDisabled */ 0,
/* updateDepgraph */ updateDepgraph,
/* dependsOnTime */ 0,
- /* dependsOnNormals */ 0,
/* foreachObjectLink */ foreachObjectLink,
/* foreachIDLink */ 0,
};
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index 7653511da10..b61302d118b 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -80,7 +80,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm,
Mesh *me= (Mesh*)ob->data;
if(mmd->totlvl) {
- if(!CustomData_get_layer(&me->fdata, CD_MDISPS)) {
+ if(!CustomData_get_layer(&me->ldata, CD_MDISPS)) {
/* multires always needs a displacement layer */
CustomData_add_layer(&me->fdata, CD_MDISPS, CD_CALLOC, NULL, me->totface);
}
@@ -92,7 +92,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm,
return dm;
if(useRenderParams || !isFinalCalc) {
- DerivedMesh *cddm= CDDM_copy(result);
+ DerivedMesh *cddm= CDDM_copy(result, 0);
result->release(result);
result= cddm;
}
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 1fa0ff7beed..92c8b089360 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -176,7 +176,7 @@ static DerivedMesh * applyModifier(ModifierData *md, Object *ob,
pars=psys->particles;
totvert=dm->getNumVerts(dm);
- totface=dm->getNumFaces(dm);
+ totface=dm->getNumTessFaces(dm);
maxvert=totvert*totpart;
maxface=totface*totpart;
@@ -192,7 +192,7 @@ static DerivedMesh * applyModifier(ModifierData *md, Object *ob,
max_co=max_r[track];
}
- result = CDDM_from_template(dm, maxvert,dm->getNumEdges(dm)*totpart,maxface);
+ result = CDDM_from_template(dm, maxvert,dm->getNumEdges(dm)*totpart,maxface, 0, 0);
mvert=result->getVertArray(result);
orig_mvert=dm->getVertArray(dm);
@@ -262,8 +262,8 @@ static DerivedMesh * applyModifier(ModifierData *md, Object *ob,
VECADD(mv->co,mv->co,state.co);
}
- mface=result->getFaceArray(result);
- orig_mface=dm->getFaceArray(dm);
+ mface=result->getTessFaceArray(result);
+ orig_mface=dm->getTessFaceArray(dm);
for(i=0; i<maxface; i++){
MFace *inMF;
@@ -314,7 +314,11 @@ static DerivedMesh * applyModifier(ModifierData *md, Object *ob,
if(size)
MEM_freeN(size);
- return result;
+ dm = CDDM_copy(result, 1); /*builds ngon faces from tess (mface) faces*/
+ result->needsFree = 1;
+ result->release(result);
+
+ return dm;
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
struct EditMesh *UNUSED(editData),
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index a23a53335ef..80c96fd8553 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -166,7 +166,7 @@ static void deformVerts(ModifierData *md, Object *ob,
}
/* make new dm */
- psmd->dm=CDDM_copy(dm);
+ psmd->dm=CDDM_copy(dm, 0);
CDDM_apply_vert_coords(psmd->dm, vertexCos);
CDDM_calc_normals(psmd->dm);
@@ -181,13 +181,13 @@ static void deformVerts(ModifierData *md, Object *ob,
/* report change in mesh structure */
if(psmd->dm->getNumVerts(psmd->dm)!=psmd->totdmvert ||
psmd->dm->getNumEdges(psmd->dm)!=psmd->totdmedge ||
- psmd->dm->getNumFaces(psmd->dm)!=psmd->totdmface){
+ psmd->dm->getNumTessFaces(psmd->dm)!=psmd->totdmface){
psys->recalc |= PSYS_RECALC_RESET;
psmd->totdmvert= psmd->dm->getNumVerts(psmd->dm);
psmd->totdmedge= psmd->dm->getNumEdges(psmd->dm);
- psmd->totdmface= psmd->dm->getNumFaces(psmd->dm);
+ psmd->totdmface= psmd->dm->getNumTessFaces(psmd->dm);
}
if(psys) {
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index ac48a9682a1..68ad5437585 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -176,7 +176,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
/* dont do anything? */
if (!totvert)
- return CDDM_from_template(dm, 0, 0, 0);
+ return CDDM_from_template(dm, 0, 0, 0, 0, 0);
switch(ltmd->axis) {
case 0:
@@ -294,17 +294,17 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
maxFaces = totedge * (step_tot-1);
}
- result= CDDM_from_template(dm, maxVerts, maxEdges, maxFaces);
+ result= CDDM_from_template(dm, maxVerts, maxEdges, maxFaces, 0, 0);
/* copy verts from mesh */
mvert_orig = dm->getVertArray(dm);
medge_orig = dm->getEdgeArray(dm);
mvert_new = result->getVertArray(result);
- mface_new = result->getFaceArray(result);
+ mface_new = result->getTessFaceArray(result);
medge_new = result->getEdgeArray(result);
- origindex= result->getFaceDataArray(result, CD_ORIGINDEX);
+ origindex= result->getTessFaceDataArray(result, CD_ORIGINDEX);
DM_copy_vert_data(dm, result, 0, 0, totvert); /* copy first otherwise this overwrites our own vertex normals */
@@ -830,7 +830,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
CDDM_calc_normals(result);
}
- return result;
+ dm = CDDM_copy(result, 1); /*builds ngon faces from tess (mface) faces*/
+ result->needsFree = 1;
+ result->release(result);
+
+ return dm;
}
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 14a07b62a91..50317e363ad 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -69,7 +69,7 @@ static void dm_calc_normal(DerivedMesh *dm, float (*temp_nors)[3])
numVerts = dm->getNumVerts(dm);
numEdges = dm->getNumEdges(dm);
numFaces = dm->getNumFaces(dm);
- mface = dm->getFaceArray(dm);
+ mface = dm->getTessFaceArray(dm);
mvert = dm->getVertArray(dm);
/* we don't want to overwrite any referenced layers */
@@ -203,7 +203,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
int UNUSED(isFinalCalc))
{
int i;
- DerivedMesh *result;
+ DerivedMesh *result, *copy;
const SolidifyModifierData *smd = (SolidifyModifierData*) md;
MFace *mf, *mface, *orig_mface;
@@ -237,7 +237,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (defgrp_index >= 0)
dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
- orig_mface = dm->getFaceArray(dm);
+ orig_mface = dm->getTessFaceArray(dm);
orig_medge = dm->getEdgeArray(dm);
orig_mvert = dm->getVertArray(dm);
@@ -327,9 +327,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
dm_calc_normal(dm, vert_nors);
}
- result = CDDM_from_template(dm, numVerts * 2, (numEdges * 2) + newEdges, (numFaces * 2) + newFaces);
+ result = CDDM_from_template(dm, numVerts * 2, (numEdges * 2) + newEdges, (numFaces * 2) + newFaces, 0, 0);
- mface = result->getFaceArray(result);
+ mface = result->getTessFaceArray(result);
medge = result->getEdgeArray(result);
mvert = result->getVertArray(result);
@@ -357,7 +357,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
{
is_quad = mf->v4;
SWAP(int, mf->v1, mf->v3);
- DM_swap_face_data(result, i+numFaces, corner_indices);
+ DM_swap_tessface_data(result, i+numFaces, corner_indices);
test_index_face(mf, &result->faceData, numFaces, is_quad ? 4:3);
}
}
@@ -565,7 +565,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DM_copy_face_data(dm, result, fidx, (numFaces * 2) + i, 1);
if(flip) {
- DM_swap_face_data(result, (numFaces * 2) + i, edge_indices[edge_order[eidx]]);
+ DM_swap_tessface_data(result, (numFaces * 2) + i, edge_indices[edge_order[eidx]]);
mf->v1= ed->v1;
mf->v2= ed->v2;
@@ -573,7 +573,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
mf->v4= ed->v1 + numVerts;
}
else {
- DM_swap_face_data(result, (numFaces * 2) + i, edge_indices[edge_order[eidx]]);
+ DM_swap_tessface_data(result, (numFaces * 2) + i, edge_indices[edge_order[eidx]]);
mf->v1= ed->v2;
mf->v2= ed->v1;
@@ -628,7 +628,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
MEM_freeN(edge_order);
}
- return result;
+ copy = CDDM_copy(result, 1); /*builds ngon faces from tess (mface) faces*/
+ result->needsFree = 1;
+ result->release(result);
+
+ return copy;
}
#undef SOLIDIFY_SIDE_NORMALS
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 823cc03cff2..6d5477e5ec8 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -103,7 +103,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
useRenderParams, NULL, isFinalCalc, 0);
if(useRenderParams || !isFinalCalc) {
- DerivedMesh *cddm= CDDM_copy(result);
+ DerivedMesh *cddm= CDDM_copy(result, 0);
result->release(result);
result= cddm;
}
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index e0bdb063331..d229f75189f 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -101,7 +101,7 @@ static void deformVerts(ModifierData *md, Object *ob,
surmd->dm->release(surmd->dm);
/* if possible use/create DerivedMesh */
- if(derivedData) surmd->dm = CDDM_copy(derivedData);
+ if(derivedData) surmd->dm = CDDM_copy(derivedData, 0);
else surmd->dm = get_dm(ob, NULL, NULL, NULL, 0);
if(!ob->pd)
@@ -160,7 +160,7 @@ static void deformVerts(ModifierData *md, Object *ob,
else
surmd->bvhtree = MEM_callocN(sizeof(BVHTreeFromMesh), "BVHTreeFromMesh");
- if(surmd->dm->getNumFaces(surmd->dm))
+ if(surmd->dm->getNumTessFaces(surmd->dm))
bvhtree_from_mesh_faces(surmd->bvhtree, surmd->dm, 0.0, 2, 6);
else
bvhtree_from_mesh_edges(surmd->bvhtree, surmd->dm, 0.0, 2, 6);
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index 8c94e6f65bc..d5235736368 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -115,7 +115,7 @@ DerivedMesh *get_cddm(Object *ob, struct EditMesh *em, DerivedMesh *dm, float (*
dm= get_dm(ob, em, dm, vertexCos, 0);
}
else {
- dm= CDDM_copy(dm);
+ dm= CDDM_copy(dm, 0);
CDDM_apply_vert_coords(dm, vertexCos);
}
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index 1a572984fe3..29bdde4d2f6 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -273,8 +273,8 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
for(i = 0, co = coords; i < numVerts; ++i, ++co)
mul_project_m4_v4(projectors[0].projmat, *co);
- mface = dm->getFaceArray(dm);
- numFaces = dm->getNumFaces(dm);
+ mface = dm->getTessFaceArray(dm);
+ numFaces = dm->getNumTessFaces(dm);
/* apply coords as UVs, and apply image if tfaces are new */
for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tface) {
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 575c454c980..42b1369e8ca 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -183,11 +183,11 @@ static void wavemod_get_texture_coords(WaveModifierData *wmd, Object *ob,
/* UVs need special handling, since they come from faces */
if(texmapping == MOD_WAV_MAP_UV) {
if(CustomData_has_layer(&dm->faceData, CD_MTFACE)) {
- MFace *mface = dm->getFaceArray(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
MFace *mf;
char *done = MEM_callocN(sizeof(*done) * numVerts,
"get_texture_coords done");
- int numFaces = dm->getNumFaces(dm);
+ int numFaces = dm->getNumTessFaces(dm);
char uvname[32];
MTFace *tf;
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_output.c b/source/blender/nodes/intern/SHD_nodes/SHD_output.c
index 548bc067076..12a6953363f 100644
--- a/source/blender/nodes/intern/SHD_nodes/SHD_output.c
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_output.c
@@ -38,7 +38,7 @@ static bNodeSocketType sh_node_output_in[]= {
static void node_shader_exec_output(void *data, bNode *node, bNodeStack **in, bNodeStack **UNUSED(out))
{
- if(data) {
+ if(data && in[0] && in[1]) {
ShadeInput *shi= ((ShaderCallData *)data)->shi;
float col[4];
diff --git a/source/blender/python/BPY_menus.c b/source/blender/python/BPY_menus.c
new file mode 100644
index 00000000000..b67f1e717da
--- /dev/null
+++ b/source/blender/python/BPY_menus.c
@@ -0,0 +1,1118 @@
+/*
+ * $Id: BPY_menus.c 12932 2007-12-17 20:21:06Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Michael Reimpell
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+/*
+ *This is the main file responsible for having bpython scripts accessible
+ * from Blender menus. To know more, please start with its header file.
+ */
+
+#include "BPY_menus.h"
+
+#include <Python.h>
+#ifndef WIN32
+ #include <dirent.h>
+#else
+ #include "BLI_winstuff.h"
+#endif
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+#include "BLI_blenlib.h"
+#include "MEM_guardedalloc.h"
+#include "DNA_userdef_types.h" /* for U.pythondir */
+#include "api2_2x/EXPP_interface.h" /* for bpy_gethome() */
+
+#define BPYMENU_DATAFILE "Bpymenus"
+#define MAX_DIR_DEPTH 4 /* max depth for traversing scripts dirs */
+#define MAX_DIR_NUMBER 30 /* max number of dirs in scripts dirs trees */
+
+static int DEBUG;
+static int Dir_Depth;
+static int Dirs_Number;
+
+/* BPyMenuTable holds all registered pymenus, as linked lists for each menu
+ * where they can appear (see PYMENUHOOKS enum in BPY_menus.h).
+*/
+BPyMenu *BPyMenuTable[PYMENU_TOTAL];
+
+static int bpymenu_group_atoi( char *str )
+{
+ if( !strcmp( str, "Export" ) )
+ return PYMENU_EXPORT;
+ else if( !strcmp( str, "Import" ) )
+ return PYMENU_IMPORT;
+ else if( !strcmp( str, "Help" ) )
+ return PYMENU_HELP;
+ else if( !strcmp( str, "HelpWebsites" ) )
+ return PYMENU_HELPWEBSITES;
+ else if( !strcmp( str, "HelpSystem" ) )
+ return PYMENU_HELPSYSTEM;
+ else if( !strcmp( str, "Render" ) )
+ return PYMENU_RENDER;
+ else if( !strcmp( str, "System" ) )
+ return PYMENU_SYSTEM;
+ else if( !strcmp( str, "Object" ) )
+ return PYMENU_OBJECT;
+ else if( !strcmp( str, "Mesh" ) )
+ return PYMENU_MESH;
+ else if( !strncmp( str, "Theme", 5 ) )
+ return PYMENU_THEMES;
+ else if( !strcmp( str, "Add" ) )
+ return PYMENU_ADD;
+ else if( !strcmp( str, "Wizards" ) )
+ return PYMENU_WIZARDS;
+ else if( !strcmp( str, "Animation" ) )
+ return PYMENU_ANIMATION;
+ else if( !strcmp( str, "Materials" ) )
+ return PYMENU_MATERIALS;
+ else if( !strcmp( str, "UV" ) )
+ return PYMENU_UV;
+ else if( !strcmp( str, "Image" ) )
+ return PYMENU_IMAGE;
+ else if( !strcmp( str, "FaceSelect" ) )
+ return PYMENU_FACESELECT;
+ else if( !strcmp( str, "WeightPaint" ) )
+ return PYMENU_WEIGHTPAINT;
+ else if( !strcmp( str, "VertexPaint" ) )
+ return PYMENU_VERTEXPAINT;
+ else if( !strcmp( str, "UVCalculation" ) )
+ return PYMENU_UVCALCULATION;
+ else if( !strcmp( str, "Armature" ) )
+ return PYMENU_ARMATURE;
+ else if( !strcmp( str, "ScriptTemplate" ) )
+ return PYMENU_SCRIPTTEMPLATE;
+ else if( !strcmp( str, "MeshFaceKey" ) )
+ return PYMENU_MESHFACEKEY;
+ else if( !strcmp( str, "AddMesh" ) )
+ return PYMENU_ADDMESH;
+ /* "Misc" or an inexistent group name: use misc */
+ else
+ return PYMENU_MISC;
+}
+
+char *BPyMenu_group_itoa( short menugroup )
+{
+ switch ( menugroup ) {
+ case PYMENU_EXPORT:
+ return "Export";
+ break;
+ case PYMENU_IMPORT:
+ return "Import";
+ break;
+ case PYMENU_ADD:
+ return "Add";
+ break;
+ case PYMENU_HELP:
+ return "Help";
+ break;
+ case PYMENU_HELPWEBSITES:
+ return "HelpWebsites";
+ break;
+ case PYMENU_HELPSYSTEM:
+ return "HelpSystem";
+ break;
+ case PYMENU_RENDER:
+ return "Render";
+ break;
+ case PYMENU_SYSTEM:
+ return "System";
+ break;
+ case PYMENU_OBJECT:
+ return "Object";
+ break;
+ case PYMENU_MESH:
+ return "Mesh";
+ break;
+ case PYMENU_THEMES:
+ return "Themes";
+ break;
+ case PYMENU_WIZARDS:
+ return "Wizards";
+ break;
+ case PYMENU_ANIMATION:
+ return "Animation";
+ break;
+ case PYMENU_MATERIALS:
+ return "Materials";
+ break;
+ case PYMENU_UV:
+ return "UV";
+ break;
+ case PYMENU_IMAGE:
+ return "Image";
+ break;
+ case PYMENU_FACESELECT:
+ return "FaceSelect";
+ break;
+ case PYMENU_WEIGHTPAINT:
+ return "WeightPaint";
+ break;
+ case PYMENU_VERTEXPAINT:
+ return "VertexPaint";
+ break;
+ case PYMENU_UVCALCULATION:
+ return "UVCalculation";
+ break;
+ case PYMENU_ARMATURE:
+ return "Armature";
+ break;
+ case PYMENU_SCRIPTTEMPLATE:
+ return "ScriptTemplate";
+ break;
+ case PYMENU_MESHFACEKEY:
+ return "MeshFaceKey";
+ break;
+ case PYMENU_ADDMESH:
+ return "AddMesh";
+ break;
+ case PYMENU_MISC:
+ return "Misc";
+ break;
+ }
+ return NULL;
+}
+
+/* BPyMenu_CreatePupmenuStr:
+ * build and return a meaninful string to be used by pupmenu(). The
+ * string is made of a bpymenu name as title and its submenus as possible
+ * choices for the user.
+*/
+char *BPyMenu_CreatePupmenuStr( BPyMenu * pym, short menugroup )
+{
+ BPySubMenu *pysm = pym->submenus;
+ char str[1024], str2[100];
+ int i = 0, rlen;
+
+ if( !pym || !pysm )
+ return NULL;
+
+ str[0] = '\0';
+
+ PyOS_snprintf( str2, sizeof( str2 ), "%s: %s%%t",
+ BPyMenu_group_itoa( menugroup ), pym->name );
+ strcat( str, str2 );
+
+ while( pysm ) {
+ PyOS_snprintf( str2, sizeof( str2 ), "|%s%%x%d", pysm->name,
+ i );
+ rlen = sizeof( str ) - strlen( str );
+ strncat( str, str2, rlen );
+ i++;
+ pysm = pysm->next;
+ }
+
+ return BLI_strdup( str );
+}
+
+static void bpymenu_RemoveAllSubEntries( BPySubMenu * smenu )
+{
+ BPySubMenu *tmp;
+
+ while( smenu ) {
+ tmp = smenu->next;
+ if( smenu->name )
+ MEM_freeN( smenu->name );
+ if( smenu->arg )
+ MEM_freeN( smenu->arg );
+ MEM_freeN( smenu );
+ smenu = tmp;
+ }
+ return;
+}
+
+void BPyMenu_RemoveAllEntries( void )
+{
+ BPyMenu *tmp, *pymenu;
+ int i;
+
+ for( i = 0; i < PYMENU_TOTAL; i++ ) {
+ pymenu = BPyMenuTable[i];
+ while( pymenu ) {
+ tmp = pymenu->next;
+ if( pymenu->name )
+ MEM_freeN( pymenu->name );
+ if( pymenu->filename )
+ MEM_freeN( pymenu->filename );
+ if( pymenu->tooltip )
+ MEM_freeN( pymenu->tooltip );
+ if( pymenu->submenus )
+ bpymenu_RemoveAllSubEntries( pymenu->
+ submenus );
+ MEM_freeN( pymenu );
+ pymenu = tmp;
+ }
+ BPyMenuTable[i] = NULL;
+ }
+
+ Dirs_Number = 0;
+ Dir_Depth = 0;
+
+ return;
+}
+
+static BPyMenu *bpymenu_FindEntry( short group, char *name )
+{
+ BPyMenu *pymenu;
+
+ if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) )
+ return NULL;
+
+ pymenu = BPyMenuTable[group];
+
+ while( pymenu ) {
+ if( !strcmp( pymenu->name, name ) )
+ return pymenu;
+ pymenu = pymenu->next;
+ }
+
+ return NULL;
+}
+
+/* BPyMenu_GetEntry:
+ * given a group and a position, return the entry in that position from
+ * that group.
+*/
+BPyMenu *BPyMenu_GetEntry( short group, short pos )
+{
+ BPyMenu *pym = NULL;
+
+ if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) )
+ return NULL;
+
+ pym = BPyMenuTable[group];
+
+ while( pos-- ) {
+ if( pym )
+ pym = pym->next;
+ else
+ break;
+ }
+
+ return pym; /* found entry or NULL */
+}
+
+static void bpymenu_set_tooltip( BPyMenu * pymenu, char *tip )
+{
+ if( !pymenu )
+ return;
+
+ if( pymenu->tooltip )
+ MEM_freeN( pymenu->tooltip );
+ pymenu->tooltip = BLI_strdup( tip );
+
+ return;
+}
+
+/* bpymenu_AddEntry:
+ * try to find an existing pymenu entry with the given type and name;
+ * if found, update it with new info, otherwise create a new one and fill it.
+ */
+static BPyMenu *bpymenu_AddEntry( short group, short version, char *name,
+ char *fname, int is_userdir, char *tooltip )
+{
+ BPyMenu *menu, *next = NULL, **iter;
+ int nameclash = 0;
+
+ if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) )
+ return NULL;
+ if( !name || !fname )
+ return NULL;
+
+ menu = bpymenu_FindEntry( group, name ); /* already exists? */
+
+ /* if a menu with this name already exists in the same group:
+ * - if one script is in the default dir and the other in U.pythondir,
+ * accept and let the new one override the other.
+ * - otherwise, report the error and return NULL. */
+ if( menu ) {
+ if( menu->dir < is_userdir ) { /* new one is in U.pythondir */
+ nameclash = 1;
+ if( menu->name )
+ MEM_freeN( menu->name );
+ if( menu->filename )
+ MEM_freeN( menu->filename );
+ if( menu->tooltip )
+ MEM_freeN( menu->tooltip );
+ if( menu->submenus )
+ bpymenu_RemoveAllSubEntries( menu->submenus );
+ next = menu->next;
+ } else { /* they are in the same dir */
+ if (DEBUG) {
+ fprintf(stderr, "\n\
+Warning: script %s's menu name is already in use.\n\
+Edit the script and change its \n\
+Name: '%s'\n\
+field, please.\n\
+Note: if you really want to have two scripts for the same menu with\n\
+the same name, keep one in the default dir and the other in\n\
+the user defined dir (only the later will be registered).\n", fname, name);
+ }
+ return NULL;
+ }
+ } else
+ menu = MEM_mallocN( sizeof( BPyMenu ), "pymenu" );
+
+ if( !menu )
+ return NULL;
+
+ menu->name = BLI_strdup( name );
+ menu->version = version;
+ menu->filename = BLI_strdup( fname );
+ menu->tooltip = NULL;
+ if( tooltip )
+ menu->tooltip = BLI_strdup( tooltip );
+ menu->dir = is_userdir;
+ menu->submenus = NULL;
+ menu->next = next; /* non-NULL if menu already existed */
+
+ if( nameclash )
+ return menu; /* no need to place it, it's already at the list */
+ else { /* insert the new entry in its correct position at the table */
+ BPyMenu *prev = NULL;
+ char *s = NULL;
+
+ iter = &BPyMenuTable[group];
+ while( *iter ) {
+ s = ( *iter )->name;
+ if( s )
+ if( strcmp( menu->name, s ) < 0 )
+ break; /* sort by names */
+ prev = *iter;
+ iter = &( ( *iter )->next );
+ }
+
+ if( *iter ) { /* prepend */
+ menu->next = *iter;
+ if( prev )
+ prev->next = menu;
+ else
+ BPyMenuTable[group] = menu; /* is first entry */
+ } else
+ *iter = menu; /* append */
+ }
+
+ return menu;
+}
+
+/* bpymenu_AddSubEntry:
+ * add a submenu to an existing python menu.
+ */
+static int bpymenu_AddSubEntry( BPyMenu * mentry, char *name, char *arg )
+{
+ BPySubMenu *smenu, **iter;
+
+ smenu = MEM_mallocN( sizeof( BPySubMenu ), "pysubmenu" );
+ if( !smenu )
+ return -1;
+
+ smenu->name = BLI_strdup( name );
+ smenu->arg = BLI_strdup( arg );
+ smenu->next = NULL;
+
+ if( !smenu->name || !smenu->arg )
+ return -1;
+
+ iter = &( mentry->submenus );
+ while( *iter )
+ iter = &( ( *iter )->next );
+
+ *iter = smenu;
+
+ return 0;
+}
+
+/* bpymenu_CreateFromFile:
+ * parse the bpymenus data file where Python menu data is stored;
+ * based on this data, create and fill the pymenu structs.
+ */
+static int bpymenu_CreateFromFile( void )
+{
+ FILE *fp;
+ char line[255], w1[255], w2[255], tooltip[255], *tip;
+ char *homedir = NULL;
+ int parsing, version, is_userdir;
+ short group;
+ BPyMenu *pymenu = NULL;
+
+ /* init global bpymenu table (it is a list of pointers to struct BPyMenus
+ * for each available cathegory: import, export, etc.) */
+ for( group = 0; group < PYMENU_TOTAL; group++ )
+ BPyMenuTable[group] = NULL;
+
+ /* let's try to open the file with bpymenu data */
+ homedir = bpy_gethome(0);
+ if (!homedir) {
+ if( DEBUG )
+ fprintf(stderr,
+ "BPyMenus error: couldn't open config file Bpymenus: no home dir.\n");
+ return -1;
+ }
+
+ BLI_make_file_string( "/", line, homedir, BPYMENU_DATAFILE );
+
+ fp = fopen( line, "rb" );
+
+ if( !fp ) {
+ if( DEBUG )
+ fprintf(stderr, "BPyMenus error: couldn't open config file %s.\n", line );
+ return -1;
+ }
+
+ fgets( line, 255, fp ); /* header */
+
+ /* check if the U.pythondir we saved at the file is different from the
+ * current one. If so, return to force updating from dirs */
+ w1[0] = '\0';
+ fscanf( fp, "# User defined scripts dir: %[^\n]\n", w1 );
+ if( w1 ) {
+ char upythondir[FILE_MAXDIR];
+
+ BLI_strncpy(upythondir, U.pythondir, FILE_MAXDIR);
+ BLI_convertstringcode(upythondir, G.sce, 0);
+ if( strcmp( w1, upythondir ) != 0 )
+ return -1;
+ w1[0] = '\0';
+ }
+
+ while( fgets( line, 255, fp ) ) { /* parsing file lines */
+
+ switch ( line[0] ) { /* check first char */
+ case '#': /* comment */
+ continue;
+ break;
+ case '\n':
+ continue;
+ break;
+ default:
+ parsing = sscanf( line, "%s {\n", w1 ); /* menu group */
+ break;
+ }
+
+ if( parsing == 1 ) { /* got menu group string */
+ group = (short)bpymenu_group_atoi( w1 );
+ if( group < 0 && DEBUG ) { /* invalid type */
+ fprintf(stderr,
+ "BPyMenus error parsing config file: wrong group: %s,\n\
+will use 'Misc'.\n", w1 );
+ }
+ } else
+ continue;
+
+ for(;;) {
+ tip = NULL; /* optional tooltip */
+ fgets( line, 255, fp );
+ if( line[0] == '}' )
+ break;
+ else if( line[0] == '\n' )
+ continue;
+ else if( line[0] == '\'' ) { /* menu entry */
+ parsing =
+ sscanf( line,
+ "'%[^']' %d %s %d '%[^']'\n",
+ w1, &version, w2, &is_userdir,
+ tooltip );
+
+ if( parsing <= 0 ) { /* invalid line, get rid of it */
+ fgets( line, 255, fp );
+ } else if( parsing == 5 )
+ tip = tooltip; /* has tooltip */
+
+ pymenu = bpymenu_AddEntry( group,
+ ( short ) version,
+ w1, w2, is_userdir,
+ tip );
+ if( !pymenu ) {
+ puts( "BPyMenus error: couldn't create bpymenu entry.\n" );
+ fclose( fp );
+ return -1;
+ }
+ } else if( line[0] == '|' && line[1] == '_' ) { /* menu sub-entry */
+ if( !pymenu )
+ continue; /* no menu yet, skip this line */
+ sscanf( line, "|_%[^:]: %s\n", w1, w2 );
+ bpymenu_AddSubEntry( pymenu, w1, w2 );
+ }
+ }
+ }
+
+ fclose( fp );
+ return 0;
+}
+
+/* bpymenu_WriteDataFile:
+ * writes the registered scripts info to the user's home dir, for faster
+ * access when the scripts dir hasn't changed.
+*/
+static void bpymenu_WriteDataFile( void )
+{
+ BPyMenu *pymenu;
+ BPySubMenu *smenu;
+ FILE *fp;
+ char fname[FILE_MAXDIR], *homedir;
+ int i;
+
+ homedir = bpy_gethome(0);
+
+ if (!homedir) {
+ if( DEBUG )
+ fprintf(stderr,
+ "BPyMenus error: couldn't write Bpymenus file: no home dir.\n\n");
+ return;
+ }
+
+ BLI_make_file_string( "/", fname, homedir, BPYMENU_DATAFILE );
+
+ fp = fopen( fname, "w" );
+ if( !fp ) {
+ if( DEBUG )
+ fprintf(stderr, "BPyMenus error: couldn't write %s file.\n\n",
+ fname );
+ return;
+ }
+
+ fprintf( fp,
+ "# Blender: registered menu entries for bpython scripts\n" );
+
+ if (U.pythondir[0] != '\0' &&
+ strcmp(U.pythondir, "/") != 0 && strcmp(U.pythondir, "//") != 0)
+ {
+ char upythondir[FILE_MAXDIR];
+
+ BLI_strncpy(upythondir, U.pythondir, FILE_MAXDIR);
+ BLI_convertstringcode(upythondir, G.sce, 0);
+ fprintf( fp, "# User defined scripts dir: %s\n", upythondir );
+ }
+
+ for( i = 0; i < PYMENU_TOTAL; i++ ) {
+ pymenu = BPyMenuTable[i];
+ if( !pymenu )
+ continue;
+ fprintf( fp, "\n%s {\n", BPyMenu_group_itoa( (short)i ) );
+ while( pymenu ) {
+ fprintf( fp, "'%s' %d %s %d", pymenu->name,
+ pymenu->version, pymenu->filename,
+ pymenu->dir );
+ if( pymenu->tooltip )
+ fprintf( fp, " '%s'\n", pymenu->tooltip );
+ else
+ fprintf( fp, "\n" );
+ smenu = pymenu->submenus;
+ while( smenu ) {
+ fprintf( fp, "|_%s: %s\n", smenu->name,
+ smenu->arg );
+ smenu = smenu->next;
+ }
+ pymenu = pymenu->next;
+ }
+ fprintf( fp, "}\n" );
+ }
+
+ fclose( fp );
+ return;
+}
+
+/* BPyMenu_PrintAllEntries:
+ * useful for debugging.
+ */
+void BPyMenu_PrintAllEntries( void )
+{
+ BPyMenu *pymenu;
+ BPySubMenu *smenu;
+ int i;
+
+ printf( "# Blender: registered menu entries for bpython scripts\n" );
+
+ for( i = 0; i < PYMENU_TOTAL; i++ ) {
+ pymenu = BPyMenuTable[i];
+ printf( "\n%s {\n", BPyMenu_group_itoa( (short)i ) );
+ while( pymenu ) {
+ printf( "'%s' %d %s %d", pymenu->name, pymenu->version,
+ pymenu->filename, pymenu->dir );
+ if( pymenu->tooltip )
+ printf( " '%s'\n", pymenu->tooltip );
+ else
+ printf( "\n" );
+ smenu = pymenu->submenus;
+ while( smenu ) {
+ printf( "|_%s: %s\n", smenu->name,
+ smenu->arg );
+ smenu = smenu->next;
+ }
+ pymenu = pymenu->next;
+ }
+ printf( "}\n" );
+ }
+}
+
+/* bpymenu_ParseFile:
+ * recursively scans folders looking for scripts to register.
+ *
+ * This function scans the scripts directory looking for .py files with the
+ * right header and menu info, using that to fill the bpymenu structs.
+ * is_userdir defines if the script is in the default scripts dir or the
+ * user defined one (U.pythondir: is_userdir == 1).
+ * Speed is important.
+ *
+ * The first line of the script must be '#!BPY'.
+ * The header registration lines must appear between the first pair of
+ * '\"\"\"' and follow this order (the single-quotes are part of
+ * the format):
+ *
+ * # \"\"\"<br>
+ * # Name: 'script name for the menu'
+ * # Blender: <code>short int</code> (minimal Blender version)
+ * # Group: 'group name' (defines menu)
+ * # Submenu: 'submenu name' related_1word_arg
+ * # Tooltip: 'tooltip for the menu'
+ * # \"\"\"
+ *
+ * Notes:
+ *
+ * - Commenting out header lines with "#" is optional, but recommended.
+ * - There may be more than one submenu line, or none:
+ * submenus and the tooltip are optional;
+ * - The Blender version is the same number reported by
+ * Blender.Get('version') in BPython or G.version in C;
+ * - Line length must be less than 99.
+ */
+static int bpymenu_ParseFile(FILE *file, char *fname, int is_userdir)
+{
+ char line[100];
+ char head[100];
+ char middle[100];
+ char tail[100];
+ int matches;
+ int parser_state;
+
+ char script_name[100];
+ int script_version = 1;
+ int script_group;
+
+ BPyMenu *scriptMenu = NULL;
+
+ if (file != NULL) {
+ parser_state = 1; /* state of parser, 0 to terminate */
+
+ while ((parser_state != 0) && (fgets(line, 100, file) != NULL)) {
+
+ switch (parser_state) {
+
+ case 1: /* !BPY */
+ if (strncmp(line, "#!BPY", 5) == 0) {
+ parser_state++;
+ } else {
+ parser_state = 0;
+ }
+ break;
+
+ case 2: /* \"\"\" */
+ if ((strstr(line, "\"\"\""))) {
+ parser_state++;
+ }
+ break;
+
+ case 3: /* Name: 'script name for the menu' */
+ matches = sscanf(line, "%[^']'%[^']'%c", head, script_name, tail);
+ if ((matches == 3) && (strstr(head, "Name:") != NULL)) {
+ parser_state++;
+ } else {
+ if (DEBUG)
+ fprintf(stderr, "BPyMenus error: Wrong 'Name' line: %s\n", fname);
+ parser_state = 0;
+ }
+ break;
+
+ case 4: /* Blender: <short int> */
+ matches = sscanf(line, "%[^1234567890]%i%c", head, &script_version,
+ tail);
+ if (matches == 3) {
+ parser_state++;
+ } else {
+ if (DEBUG)
+ fprintf(stderr,"BPyMenus error: Wrong 'Blender' line: %s\n",fname);
+ parser_state = 0;
+ }
+ break;
+
+ case 5: /* Group: 'group name' */
+ matches = sscanf(line, "%[^']'%[^']'%c", head, middle, tail);
+ if ((matches == 3) && (strstr(head, "Group:") != NULL)) {
+ script_group = bpymenu_group_atoi(middle);
+ if (script_group < 0) {
+ if (DEBUG)
+ fprintf(stderr, "BPyMenus error: Unknown group \"%s\": %s\n",
+ middle, fname);
+ parser_state = 0;
+ }
+
+ else { /* register script */
+ scriptMenu = bpymenu_AddEntry((short)script_group,
+ (short int)script_version, script_name, fname, is_userdir,NULL);
+ if (scriptMenu == NULL) {
+ if (DEBUG)
+ fprintf(stderr,
+ "BPyMenus error: Couldn't create entry for: %s\n", fname);
+ parser_state = 0;
+ } else {
+ parser_state++;
+ }
+ }
+
+ } else {
+ if (DEBUG)
+ fprintf(stderr, "BPyMenus error: Wrong 'Group' line: %s\n",fname);
+ parser_state = 0;
+ }
+ break;
+
+ case 6: /* optional elements */
+ /* Submenu: 'submenu name' related_1word_arg */
+ matches = sscanf(line, "%[^']'%[^']'%s\n", head, middle, tail);
+ if ((matches == 3) && (strstr(head, "Submenu:") != NULL)) {
+ bpymenu_AddSubEntry(scriptMenu, middle, tail);
+ } else {
+ /* Tooltip: 'tooltip for the menu */
+ matches = sscanf(line, "%[^']'%[^']'%c", head, middle, tail);
+ if ((matches == 3) && ((strstr(head, "Tooltip:") != NULL) ||
+ (strstr(head, "Tip:") != NULL))) {
+ bpymenu_set_tooltip(scriptMenu, middle);
+ }
+ parser_state = 0;
+ }
+ break;
+
+ default:
+ parser_state = 0;
+ break;
+ }
+ }
+ }
+
+ else { /* shouldn't happen, it's checked in bpymenus_ParseDir */
+ if (DEBUG)
+ fprintf(stderr, "BPyMenus error: Couldn't open %s.\n", fname);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* bpymenu_ParseDir:
+ * recursively scans folders looking for scripts to register.
+ *
+ * This function scans the scripts directory looking for .py files with the
+ * right header and menu info.
+ * - is_userdir defines if the script is in the default scripts dir or the
+ * user defined one (U.pythondir: is_userdir == 1);
+ * - parentdir is the parent dir name to store as part of the script filename,
+ * if we're down a subdir.
+ * Speed is important.
+ */
+static int bpymenu_ParseDir(char *dirname, char *parentdir, int is_userdir )
+{
+ DIR *dir;
+ FILE *file = NULL;
+ struct dirent *de;
+ struct stat status;
+ char *file_extension;
+ char path[FILE_MAX];
+ char subdir[FILE_MAX];
+ char *s = NULL;
+
+ dir = opendir(dirname);
+
+ if (dir != NULL) {
+ while ((de = readdir(dir)) != NULL) {
+
+ /* skip files and dirs starting with '.' or 'bpy' */
+ if ((de->d_name[0] == '.') || !strncmp(de->d_name, "bpy", 3)) {
+ continue;
+ }
+
+ BLI_make_file_string("/", path, dirname, de->d_name);
+
+ if (stat(path, &status) != 0) {
+ if (DEBUG)
+ fprintf(stderr, "stat %s failed: %s\n", path, strerror(errno));
+ }
+
+ if (S_ISREG(status.st_mode)) { /* is file */
+
+ file_extension = strstr(de->d_name, ".py");
+
+ if (file_extension && *(file_extension + 3) == '\0') {
+ file = fopen(path, "rb");
+
+ if (file) {
+ s = de->d_name;
+ if (parentdir) {
+ /* Join parentdir and de->d_name */
+ BLI_join_dirfile(subdir, parentdir, de->d_name);
+
+ s = subdir;
+ }
+ bpymenu_ParseFile(file, s, is_userdir);
+ fclose(file);
+ }
+
+ else {
+ if (DEBUG)
+ fprintf(stderr, "BPyMenus error: Couldn't open %s.\n", path);
+ }
+ }
+ }
+
+ else if (S_ISDIR(status.st_mode)) { /* is subdir */
+ Dirs_Number++;
+ Dir_Depth++;
+ if (Dirs_Number > MAX_DIR_NUMBER) {
+ if (DEBUG) {
+ fprintf(stderr, "BPyMenus error: too many subdirs.\n");
+ }
+ closedir(dir);
+ return -1;
+ }
+ else if (Dir_Depth > MAX_DIR_DEPTH) {
+ if (DEBUG)
+ fprintf(stderr,
+ "BPyMenus error: max depth reached traversing dir tree.\n");
+ closedir(dir);
+ return -1;
+ }
+ s = de->d_name;
+ if (parentdir) {
+ /* Join parentdir and de->d_name */
+ BLI_join_dirfile(subdir, parentdir, de->d_name);
+ s = subdir;
+ }
+ if (bpymenu_ParseDir(path, s, is_userdir) == -1) {
+ closedir(dir);
+ return -1;
+ }
+ Dir_Depth--;
+ }
+
+ }
+ closedir(dir);
+ }
+
+ else { /* open directory stream failed */
+ if (DEBUG)
+ fprintf(stderr, "opendir %s failed: %s\n", dirname, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int bpymenu_GetStatMTime( char *name, int is_file, time_t * mtime )
+{
+ struct stat st;
+ int result;
+
+ result = stat( name, &st );
+
+ if( result == -1 )
+ return -1;
+
+ if( is_file ) {
+ if( !S_ISREG( st.st_mode ) )
+ return -2;
+ } else if( !S_ISDIR( st.st_mode ) )
+ return -2;
+
+ *mtime = st.st_mtime;
+
+ return 0;
+}
+
+/* BPyMenu_Init:
+ * import the bpython menus data to Blender, either from:
+ * - the BPYMENU_DATAFILE file (?/.blender/Bpymenus) or
+ * - the scripts dir(s), case newer than the datafile (then update the file).
+ * then fill the bpymenu table with this data.
+ * if param usedir != 0, then the data is recreated from the dir(s) anyway.
+*/
+int BPyMenu_Init( int usedir )
+{
+ char fname[FILE_MAXDIR];
+ char dirname[FILE_MAXDIR];
+ char upythondir[FILE_MAXDIR];
+ char *upydir = U.pythondir, *sdir = NULL;
+ time_t time_dir1 = 0, time_dir2 = 0, time_file = 0;
+ int stat_dir1 = 0, stat_dir2 = 0, stat_file = 0;
+ int i;
+
+ DEBUG = G.f & G_DEBUG; /* is Blender in debug mode (started with -d) ? */
+
+ /* init global bpymenu table (it is a list of pointers to struct BPyMenus
+ * for each available group: import, export, etc.) */
+ for( i = 0; i < PYMENU_TOTAL; i++ )
+ BPyMenuTable[i] = NULL;
+
+ if( DEBUG )
+ fprintf(stdout, "\nRegistering scripts in Blender menus ...\n\n" );
+
+ if( U.pythondir[0] == '\0') {
+ upydir = NULL;
+ }
+ else if (strcmp(U.pythondir, "/") == 0 || strcmp(U.pythondir, "//") == 0) {
+ /* these are not accepted to prevent possible slight slowdowns on startup;
+ * they should not be used as user defined scripts dir, anyway, also from
+ * speed considerations, since they'd not be dedicated scripts dirs */
+ if (DEBUG) fprintf(stderr,
+ "BPyMenus: invalid user defined Python scripts dir: \"/\" or \"//\".\n");
+ upydir = NULL;
+ }
+ else {
+ BLI_strncpy(upythondir, upydir, FILE_MAXDIR);
+ BLI_convertstringcode(upythondir, G.sce, 0);
+ }
+
+ sdir = bpy_gethome(1);
+
+ if (sdir) {
+ BLI_strncpy(dirname, sdir, FILE_MAXDIR);
+ stat_dir1 = bpymenu_GetStatMTime( dirname, 0, &time_dir1 );
+
+ if( stat_dir1 < 0 ) {
+ time_dir1 = 0;
+ if( DEBUG ) {
+ fprintf(stderr,
+ "\nDefault scripts dir: %s:\n%s\n", dirname, strerror(errno));
+ if( upydir )
+ fprintf(stdout,
+ "Getting scripts menu data from user defined dir: %s.\n",
+ upythondir );
+ }
+ }
+ }
+ else stat_dir1 = -1;
+
+ if( upydir ) {
+ stat_dir2 = bpymenu_GetStatMTime( upythondir, 0, &time_dir2 );
+
+ if( stat_dir2 < 0 ) {
+ time_dir2 = 0;
+ upydir = NULL;
+ if( DEBUG )
+ fprintf(stderr, "\nUser defined scripts dir: %s:\n%s.\n",
+ upythondir, strerror( errno ) );
+ if( stat_dir1 < 0 ) {
+ if( DEBUG )
+ fprintf(stderr, "\
+To have scripts in menus, please add them to the default scripts dir:\n\
+%s\n\
+and / or go to 'Info window -> File Paths tab' and set a valid path for\n\
+the user defined Python scripts dir.\n", dirname );
+ return -1;
+ }
+ }
+ }
+ else stat_dir2 = -1;
+
+ if( ( stat_dir1 < 0 ) && ( stat_dir2 < 0 ) ) {
+ if( DEBUG ) {
+ fprintf(stderr, "\nCannot register scripts in menus, no scripts dir"
+ " available.\nExpected default dir at: %s \n", dirname );
+ }
+ return -1;
+ }
+
+ if (usedir) stat_file = -1;
+ else { /* if we're not forced to use the dir */
+ char *homedir = bpy_gethome(0);
+
+ if (homedir) {
+ BLI_make_file_string( "/", fname, homedir, BPYMENU_DATAFILE );
+ stat_file = bpymenu_GetStatMTime( fname, 1, &time_file );
+ if( stat_file < 0 )
+ time_file = 0;
+
+ /* comparing dates */
+
+ if((stat_file == 0)
+ && (time_file > time_dir1) && (time_file > time_dir2))
+ { /* file is newer */
+ stat_file = bpymenu_CreateFromFile( ); /* -1 if an error occurred */
+ if( !stat_file && DEBUG )
+ fprintf(stdout,
+ "Getting menu data for scripts from file:\n%s\n\n", fname );
+ }
+ else stat_file = -1;
+ }
+ else stat_file = -1; /* -1 to use dirs: didn't use file or it was corrupted */
+ }
+
+ if( stat_file == -1 ) { /* use dirs */
+ if( DEBUG ) {
+ fprintf(stdout,
+ "Getting menu data for scripts from dir(s):\ndefault: %s\n", dirname );
+ if( upydir )
+ fprintf(stdout, "user defined: %s\n", upythondir );
+ fprintf(stdout, "\n");
+ }
+ if( stat_dir1 == 0 ) {
+ i = bpymenu_ParseDir( dirname, NULL, 0 );
+ if (i == -1 && DEBUG)
+ fprintf(stderr, "Default scripts dir does not seem valid.\n\n");
+ }
+ if( stat_dir2 == 0 ) {
+ BLI_strncpy(dirname, U.pythondir, FILE_MAXDIR);
+ BLI_convertstringcode(dirname, G.sce, 0);
+ i = bpymenu_ParseDir( dirname, NULL, 1 );
+ if (i == -1 && DEBUG)
+ fprintf(stderr, "User defined scripts dir does not seem valid.\n\n");
+ }
+
+ /* check if we got any data */
+ for( i = 0; i < PYMENU_TOTAL; i++ )
+ if( BPyMenuTable[i] )
+ break;
+
+ /* if we got, recreate the file */
+ if( i < PYMENU_TOTAL )
+ bpymenu_WriteDataFile( );
+ else if( DEBUG ) {
+ fprintf(stderr, "\n\
+Warning: Registering scripts in menus -- no info found.\n\
+Either your scripts dirs have no .py scripts or the scripts\n\
+don't have a header with registration data.\n\
+Default scripts dir is:\n\
+%s\n", dirname );
+ if( upydir )
+ fprintf(stderr, "User defined scripts dir is: %s\n",
+ upythondir );
+ }
+ }
+
+ return 0;
+}
diff --git a/source/blender/python/BPY_menus.h b/source/blender/python/BPY_menus.h
new file mode 100644
index 00000000000..6cdea608b10
--- /dev/null
+++ b/source/blender/python/BPY_menus.h
@@ -0,0 +1,128 @@
+/*
+ * $Id: BPY_menus.h 12931 2007-12-17 18:20:48Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Matt Ebb
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef BPY_MENUS_H
+#define BPY_MENUS_H
+
+/* This header exposes BPyMenu related public declarations. The implementation
+ * adds 'dynamic' menus to Blender, letting scripts register themselves in any
+ * of a few pre-defined (trivial to upgrade) places in menus. These places or
+ * slots are called groups here (Import, Export, etc). This is how it works:
+ * - scripts at dirs user pref U.pythondir and .blender/scripts/ are scanned
+ * for registration info.
+ * - this data is also saved to a Bpymenus file at the user's .blender/ dir and
+ * only re-created when the scripts folder gets modified.
+ * - on start-up Blender uses this info to fill a table, which is used to
+ * create the menu entries when they are needed (see header_info.c or
+ * header_script.c, under source/blender/src/, for examples).
+*/
+
+/* These two structs hold py menu/submenu info.
+ * BPyMenu holds a script's name (as should appear in the menu) and filename,
+ * plus an optional list of submenus. Each submenu is related to a string
+ * (arg) that the script can get from the __script__ pydict, to know which
+ * submenu was chosen. */
+
+typedef struct BPySubMenu {
+ char *name;
+ char *arg;
+ struct BPySubMenu *next;
+} BPySubMenu;
+
+typedef struct BPyMenu {
+ char *name;
+ char *filename;
+ char *tooltip;
+ short version; /* Blender version */
+ int dir; /* 0: default, 1: U.pythondir */
+ struct BPySubMenu *submenus;
+ struct BPyMenu *next;
+} BPyMenu;
+
+/* Scripts can be added to only a few pre-defined places in menus, like
+ * File->Import, File->Export, etc. (for speed and better control).
+ * To make a new menu 'slot' available for scripts:
+ * - add an entry to the enum below, before PYMENU_TOTAL, of course;
+ * - update the bpymenu_group_atoi() and BPyMenu_group_itoa() functions in
+ * BPY_menus.c;
+ * - add the necessary code to the header_***.c file in
+ * source/blender/src/, like done in header_info.c for import/export;
+*/
+typedef enum {
+ PYMENU_ADD,/* creates new objects */
+ PYMENU_ANIMATION,
+ PYMENU_EXPORT,
+ PYMENU_IMPORT,
+ PYMENU_MATERIALS,
+ PYMENU_MESH,
+ PYMENU_MISC,
+ PYMENU_OBJECT,
+ PYMENU_RENDER,/* exporters to external renderers */
+ PYMENU_SYSTEM,
+ PYMENU_THEMES,
+ PYMENU_UV,/* UV editing tools, to go in UV/Image editor space, 'UV' menu */
+ PYMENU_IMAGE,/* Image editing tools, to go in UV/Image editor space, 'Image' menu */
+ PYMENU_WIZARDS,/* complex 'app' scripts */
+
+ /* entries put after Wizards don't appear at the Scripts win->Scripts menu;
+ * see define right below */
+
+ PYMENU_FACESELECT,
+ PYMENU_WEIGHTPAINT,
+ PYMENU_VERTEXPAINT,
+ PYMENU_UVCALCULATION,
+ PYMENU_ARMATURE,
+ PYMENU_SCRIPTTEMPLATE,
+ PYMENU_HELP,/*Main Help menu items - prob best to leave for 'official' ones*/
+ PYMENU_HELPSYSTEM,/* Resources, troubleshooting, system tools */
+ PYMENU_HELPWEBSITES,/* Help -> Websites submenu */
+ PYMENU_MESHFACEKEY, /* face key in mesh editmode */
+ PYMENU_ADDMESH, /* adds mesh */
+ PYMENU_TOTAL
+} PYMENUHOOKS;
+
+#define PYMENU_SCRIPTS_MENU_TOTAL (PYMENU_WIZARDS + 1)
+
+/* BPyMenuTable holds all registered pymenus, as linked lists for each menu
+ * where they can appear (see PYMENUHOOKS enum above).
+*/
+extern BPyMenu *BPyMenuTable[]; /* defined in BPY_menus.c */
+
+/* public functions: */
+int BPyMenu_Init( int usedir );
+void BPyMenu_RemoveAllEntries( void );
+void BPyMenu_PrintAllEntries( void );
+char *BPyMenu_CreatePupmenuStr( BPyMenu * pym, short group );
+char *BPyMenu_group_itoa( short group );
+struct BPyMenu *BPyMenu_GetEntry( short group, short pos );
+
+#endif /* BPY_MENUS_H */
diff --git a/source/blender/python/Makefile b/source/blender/python/Makefile
new file mode 100644
index 00000000000..43b6f91369b
--- /dev/null
+++ b/source/blender/python/Makefile
@@ -0,0 +1,34 @@
+#
+# $Id$
+#
+# ***** 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) Blender Foundation.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/python
+DIRS = intern generic
+
+include nan_subdirs.mk
diff --git a/source/blender/python/epy_doc_gen.py b/source/blender/python/epy_doc_gen.py
new file mode 100644
index 00000000000..f16c7504cb2
--- /dev/null
+++ b/source/blender/python/epy_doc_gen.py
@@ -0,0 +1,753 @@
+ # ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ #
+ # Contributor(s): Campbell Barton
+ #
+ # #**** END GPL LICENSE BLOCK #****
+
+script_help_msg = '''
+Usage,
+run this script from blenders root path once you have compiled blender
+ ./blender.bin -P source/blender/python/epy_doc_gen.py
+
+This will generate python files in "./source/blender/python/doc/bpy"
+Generate html docs by running...
+
+ epydoc source/blender/python/doc/bpy/ -v \\
+ -o source/blender/python/doc/html \\
+ --inheritance=included \\
+ --no-sourcecode \\
+ --graph=classtree \\
+ --graph-font-size=8
+
+'''
+
+# if you dont have graphvis installed ommit the --graph arg.
+
+# GLOBALS['BASEDIR'] = './source/blender/python/doc'
+
+import os
+
+SUBMODULES = {}
+INIT_SUBMODULES = {} # store initialized files
+
+INIT_SUBMODULES_IMPORTS = {} # dont import the same module twice
+
+def append_package(package_path, mod_name):
+
+ init_path = os.path.join(os.path.dirname(package_path), "__init__.py")
+
+ # avoid double ups
+ if mod_name:
+ imports = INIT_SUBMODULES_IMPORTS.setdefault(init_path, [])
+ if mod_name in imports:
+ return
+ imports.append(mod_name)
+
+ try:
+ os.makedirs(os.path.dirname(init_path)) # make the dirs if they are not there
+ except:
+ pass
+
+ # Open the new file for the first time, otherwise keep it open.
+ f = INIT_SUBMODULES.get(init_path)
+ if f == None:
+ f = INIT_SUBMODULES[init_path] = open(init_path, 'w')
+
+ if mod_name:
+ f.write("import %s\n" % mod_name)
+
+ return f
+
+def append_package_recursive(package_path, BASEPATH):
+ '''
+ assume the last item of package_path will be a file (not a dir thats created)
+ '''
+
+ package_path = os.path.splitext(package_path)[0] # incase of .py
+
+ try:
+ os.makedirs(os.path.join(BASEPATH, os.path.dirname(package_path))) # make the dirs if they are not there
+ except:
+ pass
+
+ new_path = BASEPATH
+
+ for mod_name in package_path.split(os.sep):
+ init_path = os.path.join(new_path, "__init__.py")
+ new_path = os.path.join(new_path, mod_name)
+ append_package(init_path, mod_name)
+
+
+def open_submodule(subpath, BASEPATH):
+ '''
+ This is a utility function that lets us quickly add submodules
+ '''
+
+ # create all the package paths leading up to this module
+ append_package_recursive(subpath, BASEPATH)
+
+ module_name = os.path.basename( os.path.splitext(subpath)[0] )
+ mod_path = os.path.join(BASEPATH, subpath)
+
+ # Open the new file for the first time, otherwise keep it open.
+ f = SUBMODULES.get(mod_path)
+ if f == None:
+ f = SUBMODULES[mod_path] = open(mod_path, 'w')
+
+ f = open(mod_path, 'w')
+ return f
+
+def close_all():
+ for files in (INIT_SUBMODULES.values(), SUBMODULES.values()):
+ for f in files:
+ if f.name.endswith('.py'):
+ f_name = f.name
+ f.close()
+
+ f = open(f_name, 'a')
+ f.write("\ndel __package__\n") # annoying, no need do show this
+
+
+ f.close()
+
+
+def range_str(val):
+ if val < -10000000: return '-inf'
+ if val > 10000000: return 'inf'
+ if type(val)==float:
+ return '%g' % val
+ else:
+ return str(val)
+
+def get_array_str(length):
+ if length > 0: return ' array of %d items' % length
+ else: return ''
+
+def full_rna_struct_path(rna_struct):
+ '''
+ Needed when referencing one struct from another
+ '''
+ nested = rna_struct.nested
+ if nested:
+ return "%s.%s" % (full_rna_struct_path(nested), rna_struct.identifier)
+ else:
+ return rna_struct.identifier
+
+def rna_id_ignore(rna_id):
+ if rna_id == "rna_type":
+ return True
+
+ if "_OT_" in rna_id:
+ return True
+ if "_MT_" in rna_id:
+ return True
+ if "_PT_" in rna_id:
+ return True
+
+ return False
+
+def write_func(rna, ident, out, func_type):
+ # Keyword attributes
+ kw_args = [] # "foo = 1", "bar=0.5", "spam='ENUM'"
+ kw_arg_attrs = [] # "@type mode: int"
+
+ rna_struct= rna.rna_type
+
+ # Operators and functions work differently
+ if func_type=='OPERATOR':
+ rna_func_name = rna_struct.identifier.split("_OT_")[-1]
+ rna_func_desc = rna_struct.description.strip()
+ items = rna_struct.properties.items()
+ else:
+ rna_func_name = rna.identifier
+ rna_func_desc = rna.description.strip()
+ items = rna.parameters.items()
+
+
+ for rna_prop_identifier, rna_prop in items:
+ if rna_id_ignore(rna_prop_identifier):
+ continue
+
+ # clear vars
+ val = val_error = val_str = rna_prop_type = None
+
+ # ['rna_type', 'name', 'array_length', 'description', 'hard_max', 'hard_min', 'identifier', 'precision', 'readonly', 'soft_max', 'soft_min', 'step', 'subtype', 'type']
+ #rna_prop= op_rna.rna_type.properties[attr]
+ rna_prop_type = rna_prop.type.lower() # enum, float, int, boolean
+
+
+ # only for rna functions, operators should not get pointers as args
+ if rna_prop_type=='pointer':
+ rna_prop_type_refine = "L{%s}" % rna_prop.fixed_type.identifier
+ else:
+ # Collections/Arrays can have a srna type
+ rna_prop_srna_type = rna_prop.srna
+ if rna_prop_srna_type:
+ print(rna_prop_srna_type.identifier)
+ rna_prop_type_refine = "L{%s}" % rna_prop_srna_type.identifier
+ else:
+ rna_prop_type_refine = rna_prop_type
+
+ del rna_prop_srna_type
+
+
+ try: length = rna_prop.array_length
+ except: length = 0
+
+ array_str = get_array_str(length)
+
+ if rna_prop.use_return:
+ kw_type_str= "@rtype: %s%s" % (rna_prop_type_refine, array_str)
+ kw_param_str= "@return: %s" % (rna_prop.description.strip())
+ else:
+ kw_type_str= "@type %s: %s%s" % (rna_prop_identifier, rna_prop_type_refine, array_str)
+ kw_param_str= "@param %s: %s" % (rna_prop_identifier, rna_prop.description.strip())
+
+ kw_param_set = False
+
+ if func_type=='OPERATOR':
+ try:
+ val = getattr(rna, rna_prop_identifier)
+ val_error = False
+ except:
+ val = "'<UNDEFINED>'"
+ val_error = True
+
+
+ if val_error:
+ val_str = val
+ elif rna_prop_type=='float':
+ if length==0:
+ val_str= '%g' % val
+ if '.' not in val_str and '-' not in val_str: # value could be 1e-05
+ val_str += '.0'
+ else:
+ # array
+ val_str = str(tuple(val))
+
+ kw_param_str += (' in (%s, %s)' % (range_str(rna_prop.hard_min), range_str(rna_prop.hard_max)))
+ kw_param_set= True
+
+ elif rna_prop_type=='int':
+ if length==0:
+ val_str='%d' % val
+ else:
+ val_str = str(tuple(val))
+
+ # print(dir(rna_prop))
+ kw_param_str += (' in (%s, %s)' % (range_str(rna_prop.hard_min), range_str(rna_prop.hard_max)))
+ # These strings dont have a max length???
+ #kw_param_str += ' (maximum length of %s)' % (rna_prop.max_length)
+ kw_param_set= True
+
+ elif rna_prop_type=='boolean':
+ if length==0:
+ if val: val_str='True'
+ else: val_str='False'
+ else:
+ val_str = str(tuple(val))
+
+ elif rna_prop_type=='enum':
+ # no array here?
+ val_str="'%s'" % val
+ # Too cramped
+ kw_param_str += (' in (%s)' % ', '.join(rna_prop.items.keys()))
+
+ kw_param_set= True
+
+ elif rna_prop_type=='string':
+ # no array here?
+ val_str='"%s"' % val
+
+ # todo - collection - array
+ # print (rna_prop.type)
+
+ kw_args.append('%s = %s' % (rna_prop_identifier, val_str))
+
+ # stora
+ else:
+ # currently functions dont have a default value
+ if not rna_prop.use_return:
+ kw_args.append('%s' % (rna_prop_identifier))
+ else:
+ kw_param_set = True
+
+
+ # Same for operators and functions
+ kw_arg_attrs.append(kw_type_str)
+ if kw_param_set:
+ kw_arg_attrs.append(kw_param_str)
+
+
+
+ out.write(ident+'def %s(%s):\n' % (rna_func_name, ', '.join(kw_args)))
+ out.write(ident+'\t"""\n')
+
+ # Descriptions could be multiline
+ for rna_func_desc_line in rna_func_desc.split('\n'):
+ out.write(ident+'\t%s\n' % rna_func_desc_line.strip())
+
+ for desc in kw_arg_attrs:
+ out.write(ident+'\t%s\n' % desc)
+
+ # out.write(ident+'\t@rtype: None\n') # implicit
+ out.write(ident+'\t"""\n')
+
+
+
+def rna2epy(BASEPATH):
+
+ # Use for faster lookups
+ # use rna_struct.identifier as the key for each dict
+ rna_struct_dict = {} # store identifier:rna lookups
+ rna_full_path_dict = {} # store the result of full_rna_struct_path(rna_struct)
+ rna_children_dict = {} # store all rna_structs nested from here
+ rna_references_dict = {} # store a list of rna path strings that reference this type
+ rna_functions_dict = {} # store all functions directly in this type (not inherited)
+ rna_words = set()
+
+ # def write_func(rna_func, ident):
+
+
+ def write_struct(rna_struct, ident):
+ identifier = rna_struct.identifier
+
+ rna_base = rna_struct.base
+
+ if rna_base:
+ out.write(ident+ 'class %s(%s):\n' % (identifier, rna_base.identifier))
+ rna_base_prop_keys = rna_base.properties.keys() # could be cached
+ rna_base_func_keys = [f.identifier for f in rna_base.functions]
+ else:
+ out.write(ident+ 'class %s:\n' % identifier)
+ rna_base_prop_keys = []
+ rna_base_func_keys = []
+
+ out.write(ident+ '\t"""\n')
+
+ title = 'The %s Object' % rna_struct.name
+ description = rna_struct.description.strip()
+ out.write(ident+ '\t%s\n' % title)
+ out.write(ident+ '\t%s\n' % ('=' * len(title)))
+ out.write(ident+ '\t\t%s\n' % description)
+ rna_words.update(description.split())
+
+
+ # For convenience, give a list of all places were used.
+ rna_refs= rna_references_dict[identifier]
+
+ if rna_refs:
+ out.write(ident+ '\t\t\n')
+ out.write(ident+ '\t\tReferences\n')
+ out.write(ident+ '\t\t==========\n')
+
+ for rna_ref_string in rna_refs:
+ out.write(ident+ '\t\t\t- L{%s}\n' % rna_ref_string)
+
+ out.write(ident+ '\t\t\n')
+
+ else:
+ out.write(ident+ '\t\t\n')
+ out.write(ident+ '\t\t(no references to this struct found)\n')
+ out.write(ident+ '\t\t\n')
+
+ for rna_prop_identifier, rna_prop in rna_struct.properties.items():
+
+ if rna_prop_identifier=='RNA': continue
+ if rna_id_ignore(rna_prop_identifier): continue
+ if rna_prop_identifier in rna_base_prop_keys: continue # does this prop exist in our parent class, if so skip
+
+ rna_desc = rna_prop.description.strip()
+
+ if rna_desc: rna_words.update(rna_desc.split())
+ if not rna_desc: rna_desc = rna_prop.name
+ if not rna_desc: rna_desc = 'Note - No documentation for this property!'
+
+ rna_prop_type = rna_prop.type.lower()
+
+ if rna_prop_type=='collection': collection_str = 'Collection of '
+ else: collection_str = ''
+
+ # some collections have a srna for their own properties
+ # TODO - arrays, however this isnt used yet
+ rna_prop_srna_type = rna_prop.srna
+ if rna_prop_srna_type:
+ collection_str = "L{%s} %s" % (rna_prop_srna_type.identifier, collection_str)
+ del rna_prop_srna_type
+
+ try: rna_prop_ptr = rna_prop.fixed_type
+ except: rna_prop_ptr = None
+
+ try: length = rna_prop.array_length
+ except: length = 0
+
+ array_str = get_array_str(length)
+
+ if rna_prop.editable: readonly_str = ''
+ else: readonly_str = ' (readonly)'
+
+ if rna_prop_ptr: # Use the pointer type
+ out.write(ident+ '\t@ivar %s: %s\n' % (rna_prop_identifier, rna_desc))
+ out.write(ident+ '\t@type %s: %sL{%s}%s%s\n' % (rna_prop_identifier, collection_str, rna_prop_ptr.identifier, array_str, readonly_str))
+ else:
+ if rna_prop_type == 'enum':
+ if 0:
+ out.write(ident+ '\t@ivar %s: %s in (%s)\n' % (rna_prop_identifier, rna_desc, ', '.join(rna_prop.items.keys())))
+ else:
+ out.write(ident+ '\t@ivar %s: %s in...\n' % (rna_prop_identifier, rna_desc))
+ for e, e_rna_prop in rna_prop.items.items():
+ #out.write(ident+ '\t\t- %s: %s\n' % (e, e_rna_prop.description)) # XXX - segfaults, FIXME
+ out.write(ident+ '\t\t- %s\n' % e)
+
+ out.write(ident+ '\t@type %s: %s%s%s\n' % (rna_prop_identifier, rna_prop_type, array_str, readonly_str))
+ elif rna_prop_type == 'int' or rna_prop_type == 'float':
+ out.write(ident+ '\t@ivar %s: %s\n' % (rna_prop_identifier, rna_desc))
+ out.write(ident+ '\t@type %s: %s%s%s in [%s, %s]\n' % (rna_prop_identifier, rna_prop_type, array_str, readonly_str, range_str(rna_prop.hard_min), range_str(rna_prop.hard_max) ))
+ elif rna_prop_type == 'string':
+ out.write(ident+ '\t@ivar %s: %s (maximum length of %s)\n' % (rna_prop_identifier, rna_desc, rna_prop.max_length))
+ out.write(ident+ '\t@type %s: %s%s%s\n' % (rna_prop_identifier, rna_prop_type, array_str, readonly_str))
+ else:
+ out.write(ident+ '\t@ivar %s: %s\n' % (rna_prop_identifier, rna_desc))
+ out.write(ident+ '\t@type %s: %s%s%s\n' % (rna_prop_identifier, rna_prop_type, array_str, readonly_str))
+
+
+ out.write(ident+ '\t"""\n\n')
+
+
+ # Write functions
+ # for rna_func in rna_struct.functions: # Better ignore inherited (line below)
+ for rna_func in rna_functions_dict[identifier]:
+ if rna_func not in rna_base_func_keys:
+ write_func(rna_func, ident+'\t', out, 'FUNCTION')
+
+ out.write('\n')
+
+ # Now write children recursively
+ for child in rna_children_dict[identifier]:
+ write_struct(child, ident + '\t')
+
+
+
+ # out = open(target_path, 'w')
+ out = open_submodule("types.py", BASEPATH) # bpy.types
+
+ def base_id(rna_struct):
+ try: return rna_struct.base.identifier
+ except: return '' # invalid id
+
+ #structs = [(base_id(rna_struct), rna_struct.identifier, rna_struct) for rna_struct in bpy.doc.structs.values()]
+ '''
+ structs = []
+ for rna_struct in bpy.doc.structs.values():
+ structs.append( (base_id(rna_struct), rna_struct.identifier, rna_struct) )
+ '''
+ structs = []
+ for rna_type_name in dir(bpy.types):
+ rna_type = getattr(bpy.types, rna_type_name)
+
+ try: rna_struct = rna_type.bl_rna
+ except: rna_struct = None
+
+ if rna_struct:
+ #if not rna_type_name.startswith('__'):
+
+ identifier = rna_struct.identifier
+
+ if not rna_id_ignore(identifier):
+ structs.append( (base_id(rna_struct), identifier, rna_struct) )
+
+ # Simple lookup
+ rna_struct_dict[identifier] = rna_struct
+
+ # Store full rna path 'GameObjectSettings' -> 'Object.GameObjectSettings'
+ rna_full_path_dict[identifier] = full_rna_struct_path(rna_struct)
+
+ # Store a list of functions, remove inherited later
+ rna_functions_dict[identifier]= list(rna_struct.functions)
+
+
+ # fill in these later
+ rna_children_dict[identifier]= []
+ rna_references_dict[identifier]= []
+
+
+ else:
+ print("Ignoring", rna_type_name)
+
+
+ # Sucks but we need to copy this so we can check original parent functions
+ rna_functions_dict__copy = {}
+ for key, val in rna_functions_dict.items():
+ rna_functions_dict__copy[key] = val[:]
+
+
+ structs.sort() # not needed but speeds up sort below, setting items without an inheritance first
+
+ # Arrange so classes are always defined in the correct order
+ deps_ok = False
+ while deps_ok == False:
+ deps_ok = True
+ rna_done = set()
+
+ for i, (rna_base, identifier, rna_struct) in enumerate(structs):
+
+ rna_done.add(identifier)
+
+ if rna_base and rna_base not in rna_done:
+ deps_ok = False
+ data = structs.pop(i)
+ ok = False
+ while i < len(structs):
+ if structs[i][1]==rna_base:
+ structs.insert(i+1, data) # insert after the item we depend on.
+ ok = True
+ break
+ i+=1
+
+ if not ok:
+ print('Dependancy "%s" could not be found for "%s"' % (identifier, rna_base))
+
+ break
+
+ # Done ordering structs
+
+
+ # precalc vars to avoid a lot of looping
+ for (rna_base, identifier, rna_struct) in structs:
+
+ if rna_base:
+ rna_base_prop_keys = rna_struct_dict[rna_base].properties.keys() # could cache
+ rna_base_func_keys = [f.identifier for f in rna_struct_dict[rna_base].functions]
+ else:
+ rna_base_prop_keys = []
+ rna_base_func_keys= []
+
+ # rna_struct_path = full_rna_struct_path(rna_struct)
+ rna_struct_path = rna_full_path_dict[identifier]
+
+ for rna_prop_identifier, rna_prop in rna_struct.properties.items():
+
+ if rna_prop_identifier=='RNA': continue
+ if rna_id_ignore(rna_prop_identifier): continue
+ if rna_prop_identifier in rna_base_prop_keys: continue
+
+
+ for rna_prop_ptr in (getattr(rna_prop, "fixed_type", None), getattr(rna_prop, "srna", None)):
+ # Does this property point to me?
+ if rna_prop_ptr:
+ rna_references_dict[rna_prop_ptr.identifier].append( "%s.%s" % (rna_struct_path, rna_prop_identifier) )
+
+ for rna_func in rna_struct.functions:
+ for rna_prop_identifier, rna_prop in rna_func.parameters.items():
+
+ if rna_prop_identifier=='RNA': continue
+ if rna_id_ignore(rna_prop_identifier): continue
+ if rna_prop_identifier in rna_base_func_keys: continue
+
+
+ try: rna_prop_ptr = rna_prop.fixed_type
+ except: rna_prop_ptr = None
+
+ # Does this property point to me?
+ if rna_prop_ptr:
+ rna_references_dict[rna_prop_ptr.identifier].append( "%s.%s" % (rna_struct_path, rna_func.identifier) )
+
+
+ # Store nested children
+ nested = rna_struct.nested
+ if nested:
+ rna_children_dict[nested.identifier].append(rna_struct)
+
+
+ if rna_base:
+ rna_funcs = rna_functions_dict[identifier]
+ if rna_funcs:
+ # Remove inherited functions if we have any
+ rna_base_funcs = rna_functions_dict__copy[rna_base]
+ rna_funcs[:] = [f for f in rna_funcs if f not in rna_base_funcs]
+
+ rna_functions_dict__copy.clear()
+ del rna_functions_dict__copy
+
+ # Sort the refs, just reads nicer
+ for rna_refs in rna_references_dict.values():
+ rna_refs.sort()
+
+ for (rna_base, identifier, rna_struct) in structs:
+ if rna_struct.nested:
+ continue
+
+ write_struct(rna_struct, '')
+
+
+ out.write('\n')
+ out.close()
+
+ # # We could also just run....
+ # os.system('epydoc source/blender/python/doc/rna.py -o ./source/blender/python/doc/html -v')
+
+ target_path = os.path.join(BASEPATH, "dump.py") # XXX - used for other funcs
+
+ # Write graphviz
+ out= open(target_path.replace('.py', '.dot'), 'w')
+ out.write('digraph "rna data api" {\n')
+ out.write('\tnode [style=filled, shape = "box"];\n')
+ out.write('\toverlap=false;\n')
+ out.write('\trankdir = LR;\n')
+ out.write('\tsplines=true;\n')
+ out.write('\tratio=auto;\n')
+
+
+
+ out.write('\tsize="10,10"\n')
+ #out.write('\tpage="8.5,11"\n')
+ #out.write('\tcenter=""\n')
+
+ def isop(rna_struct):
+ return '_OT_' in rna_struct.identifier
+
+
+ for (rna_base, identifier, rna_struct) in structs:
+ if isop(rna_struct):
+ continue
+
+ base = rna_struct.base
+
+
+ out.write('\t"%s";\n' % identifier)
+
+ for (rna_base, identifier, rna_struct) in structs:
+
+ if isop(rna_struct):
+ continue
+
+ base = rna_struct.base
+
+ if base and not isop(base):
+ out.write('\t"%s" -> "%s" [label="(base)" weight=1.0];\n' % (base.identifier, identifier))
+
+ nested = rna_struct.nested
+ if nested and not isop(nested):
+ out.write('\t"%s" -> "%s" [label="(nested)" weight=1.0];\n' % (nested.identifier, identifier))
+
+
+
+ rna_refs= rna_references_dict[identifier]
+
+ for rna_ref_string in rna_refs:
+
+ if '_OT_' in rna_ref_string:
+ continue
+
+ ref = rna_ref_string.split('.')[-2]
+ out.write('\t"%s" -> "%s" [label="%s" weight=0.01];\n' % (ref, identifier, rna_ref_string))
+
+
+ out.write('}\n')
+ out.close()
+
+ # # We could also just run....
+ # os.system('dot source/blender/python/doc/rna.dot -Tsvg -o ./source/blender/python/doc/rna.svg')
+
+
+ out= open(target_path.replace('.py', '.words'), 'w')
+ rna_words = list(rna_words)
+ rna_words.sort()
+ for w in rna_words:
+ out.write('%s\n' % w)
+
+
+def op2epy(BASEPATH):
+ # out = open(target_path, 'w')
+
+ op_mods = dir(bpy.ops)
+ op_mods.remove('add')
+ op_mods.remove('remove')
+
+ for op_mod_name in sorted(op_mods):
+ if op_mod_name.startswith('__'):
+ continue
+
+ # open the submodule
+ mod_path = os.path.join("ops", op_mod_name + ".py")
+ out = open_submodule(mod_path, BASEPATH)
+
+
+ op_mod = getattr(bpy.ops, op_mod_name)
+ operators = dir(op_mod)
+ for op in sorted(operators):
+ # rna = getattr(bpy.types, op).bl_rna
+ rna = getattr(op_mod, op).get_rna()
+ write_func(rna, '', out, 'OPERATOR')
+
+ out.write('\n')
+ out.close()
+
+def misc2epy(BASEPATH):
+ '''
+ Hard coded modules, try to avoid adding stuff here
+ '''
+
+ f = append_package(os.path.join(BASEPATH, ""), ""); # add a slash on the end of the base path
+ f.write('''
+"""
+@type data: L{bpy.types.Main}
+@var data: blender data is accessed from here
+"""
+''')
+
+ f = open_submodule("props.py", BASEPATH)
+ f.write('''
+MAX_INT= 2**31
+MAX_FLOAT= 1e+37
+def BoolProperty(attr, name="", description="", default=False):
+ """
+ return a new bool property
+ """
+def IntProperty(attr, name="", description="", min=-MAX_INT, max=MAX_INT, soft_min=-MAX_INT, soft_max=MAX_INT, default=0):
+ """
+ return a new int property
+ """
+def FloatProperty(attr, name="", description="", min=-MAX_FLOAT, max=MAX_FLOAT, soft_min=-MAX_FLOAT, soft_max=MAX_FLOAT, default=0.0):
+ """
+ return a new float property
+ """
+def StringProperty(attr, name="", description="", maxlen=0, default=""):
+ """
+ return a new string property
+ """
+def EnumProperty(attr, items, name="", description="", default=""):
+ """
+ return a new enum property
+ """
+''')
+
+
+if __name__ == '__main__':
+ if 'bpy' not in dir():
+ print("\nError, this script must run from inside blender2.5")
+ print(script_help_msg)
+ else:
+ misc2epy('source/blender/python/doc/bpy') # first to write in info in some of the modules.
+ rna2epy('source/blender/python/doc/bpy')
+ op2epy('source/blender/python/doc/bpy')
+
+
+ close_all()
+
+ import sys
+ sys.exit()
diff --git a/source/blender/python/generic/bpy_internal_import.h b/source/blender/python/generic/bpy_internal_import.h
index dd7a3ab9f64..529c2c44df1 100644
--- a/source/blender/python/generic/bpy_internal_import.h
+++ b/source/blender/python/generic/bpy_internal_import.h
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: bpy_internal_import.h 21094 2009-06-23 00:09:26Z gsrb3d $
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
diff --git a/source/blender/python/intern/Makefile b/source/blender/python/intern/Makefile
new file mode 100644
index 00000000000..6c0b7b4d14e
--- /dev/null
+++ b/source/blender/python/intern/Makefile
@@ -0,0 +1,67 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = python
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+# OpenGL and Python
+CPPFLAGS += $(OGL_CPPFLAGS)
+CPPFLAGS += -I$(NAN_GLEW)/include
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
+# PreProcessor stuff
+
+CPPFLAGS += -I$(NAN_GHOST)/include
+CPPFLAGS += $(NAN_SDLCFLAGS)
+
+# modules
+CPPFLAGS += -I../../editors/include
+CPPFLAGS += -I../../python
+CPPFLAGS += -I../../makesdna
+CPPFLAGS += -I../../makesrna
+CPPFLAGS += -I../../blenlib
+CPPFLAGS += -I../../blenkernel
+CPPFLAGS += -I../../nodes
+CPPFLAGS += -I../../imbuf
+CPPFLAGS += -I../../blenloader
+CPPFLAGS += -I../../windowmanager
+CPPFLAGS += -I../../render/extern/include
+CPPFLAGS += -I$(NAN_AUDASPACE)/include
+
+# path to the guarded memory allocator
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I$(NAN_MEMUTIL)/include
+
+# path to our own headerfiles
+CPPFLAGS += -I..
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 3cb9e500852..44daef06cb4 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -51,7 +51,7 @@
#include "../generic/blf_py_api.h"
#include "../generic/IDProp.h"
-#include "AUD_PyInit.h"
+//#include "AUD_PyInit.h"
PyObject *bpy_package_py= NULL;
diff --git a/source/blender/python/intern/bpy_array.c b/source/blender/python/intern/bpy_array.c
new file mode 100644
index 00000000000..1afd54b3607
--- /dev/null
+++ b/source/blender/python/intern/bpy_array.c
@@ -0,0 +1,606 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Arystanbek Dyussenov
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "bpy_rna.h"
+#include "BKE_global.h"
+#include "MEM_guardedalloc.h"
+
+#define MAX_ARRAY_DIMENSION 10
+
+typedef void (*ItemConvertFunc)(PyObject *, char *);
+typedef int (*ItemTypeCheckFunc)(PyObject *);
+typedef void (*RNA_SetArrayFunc)(PointerRNA *, PropertyRNA *, const char *);
+typedef void (*RNA_SetIndexFunc)(PointerRNA *, PropertyRNA *, int index, void *);
+
+/*
+ arr[3][4][5]
+ 0 1 2 <- dimension index
+*/
+
+/*
+ arr[2] = x
+
+ py_to_array_index(arraydim=0, arrayoffset=0, index=2)
+ validate_array(lvalue_dim=0)
+ ... make real index ...
+*/
+
+/* arr[3]=x, self->arraydim is 0, lvalue_dim is 1 */
+/* Ensures that a python sequence has expected number of items/sub-items and items are of desired type. */
+static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[],
+ ItemTypeCheckFunc check_item_type, const char *item_type_str, const char *error_prefix)
+{
+ int i;
+
+ /* not the last dimension */
+ if (dim + 1 < totdim) {
+ /* check that a sequence contains dimsize[dim] items */
+
+ for (i= 0; i < PySequence_Length(seq); i++) {
+ PyObject *item;
+ int ok= 1;
+ item= PySequence_GetItem(seq, i);
+
+ if (!PySequence_Check(item)) {
+ /* BLI_snprintf(error_str, error_str_size, "expected a sequence of %s", item_type_str); */
+ PyErr_Format(PyExc_TypeError, "%s expected a sequence of %s", error_prefix, item_type_str);
+ ok= 0;
+ }
+ /* arr[3][4][5]
+ dimsize[1]=4
+ dimsize[2]=5
+
+ dim=0 */
+ else if (PySequence_Length(item) != dimsize[dim + 1]) {
+ /* BLI_snprintf(error_str, error_str_size, "sequences of dimension %d should contain %d items", (int)dim + 1, (int)dimsize[dim + 1]); */
+ PyErr_Format(PyExc_ValueError, "%s sequences of dimension %d should contain %d items", error_prefix, (int)dim + 1, (int)dimsize[dim + 1]);
+ ok= 0;
+ }
+ else if (!validate_array_type(item, dim + 1, totdim, dimsize, check_item_type, item_type_str, error_prefix)) {
+ ok= 0;
+ }
+
+ Py_DECREF(item);
+
+ if (!ok)
+ return 0;
+ }
+ }
+ else {
+ /* check that items are of correct type */
+ for (i= 0; i < PySequence_Length(seq); i++) {
+ PyObject *item= PySequence_GetItem(seq, i);
+
+ if (!check_item_type(item)) {
+ Py_DECREF(item);
+
+ /* BLI_snprintf(error_str, error_str_size, "sequence items should be of type %s", item_type_str); */
+ PyErr_Format(PyExc_TypeError, "sequence items should be of type %s", item_type_str);
+ return 0;
+ }
+
+ Py_DECREF(item);
+ }
+ }
+
+ return 1;
+}
+
+/* Returns the number of items in a single- or multi-dimensional sequence. */
+static int count_items(PyObject *seq)
+{
+ int totitem= 0;
+
+ if (PySequence_Check(seq)) {
+ int i;
+ for (i= 0; i < PySequence_Length(seq); i++) {
+ PyObject *item= PySequence_GetItem(seq, i);
+ totitem += count_items(item);
+ Py_DECREF(item);
+ }
+ }
+ else
+ totitem= 1;
+
+ return totitem;
+}
+
+/* Modifies property array length if needed and PROP_DYNAMIC flag is set. */
+static int validate_array_length(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, int *totitem, const char *error_prefix)
+{
+ int dimsize[MAX_ARRAY_DIMENSION];
+ int tot, totdim, len;
+
+ tot= count_items(rvalue);
+ totdim= RNA_property_array_dimension(ptr, prop, dimsize);
+
+ if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) {
+ if (RNA_property_array_length(ptr, prop) != tot) {
+#if 0
+ /* length is flexible */
+ if (!RNA_property_dynamic_array_set_length(ptr, prop, tot)) {
+ /* BLI_snprintf(error_str, error_str_size, "%s.%s: array length cannot be changed to %d", RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot); */
+ PyErr_Format(PyExc_ValueError, "%s %s.%s: array length cannot be changed to %d", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot);
+ return 0;
+ }
+#else
+ *totitem= tot;
+ return 1;
+
+#endif
+ }
+
+ len= tot;
+ }
+ else {
+ /* length is a constraint */
+ if (!lvalue_dim) {
+ len= RNA_property_array_length(ptr, prop);
+ }
+ /* array item assignment */
+ else {
+ int i;
+
+ len= 1;
+
+ /* arr[3][4][5]
+
+ arr[2] = x
+ dimsize={4, 5}
+ dimsize[1] = 4
+ dimsize[2] = 5
+ lvalue_dim=0, totdim=3
+
+ arr[2][3] = x
+ lvalue_dim=1
+
+ arr[2][3][4] = x
+ lvalue_dim=2 */
+ for (i= lvalue_dim; i < totdim; i++)
+ len *= dimsize[i];
+ }
+
+ if (tot != len) {
+ /* BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len); */
+ PyErr_Format(PyExc_ValueError, "%s sequence must have %d items total", error_prefix, len);
+ return 0;
+ }
+ }
+
+ *totitem= len;
+
+ return 1;
+}
+
+static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, ItemTypeCheckFunc check_item_type, const char *item_type_str, int *totitem, const char *error_prefix)
+{
+ int dimsize[MAX_ARRAY_DIMENSION];
+ int totdim= RNA_property_array_dimension(ptr, prop, dimsize);
+
+ /* validate type first because length validation may modify property array length */
+
+ if (!validate_array_type(rvalue, lvalue_dim, totdim, dimsize, check_item_type, item_type_str, error_prefix))
+ return 0;
+
+ return validate_array_length(rvalue, ptr, prop, lvalue_dim, totitem, error_prefix);
+}
+
+static char *copy_values(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop, int dim, char *data, unsigned int item_size, int *index, ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index)
+{
+ unsigned int i;
+ int totdim= RNA_property_array_dimension(ptr, prop, NULL);
+
+ for (i= 0; i < PySequence_Length(seq); i++) {
+ PyObject *item= PySequence_GetItem(seq, i);
+
+ if (dim + 1 < totdim) {
+ data= copy_values(item, ptr, prop, dim + 1, data, item_size, index, convert_item, rna_set_index);
+ }
+ else {
+ if (!data) {
+ char value[sizeof(int)];
+
+ convert_item(item, value);
+ rna_set_index(ptr, prop, *index, value);
+ *index = *index + 1;
+ }
+ else {
+ convert_item(item, data);
+ data += item_size;
+ }
+ }
+
+ Py_DECREF(item);
+ }
+
+ return data;
+}
+
+static int py_to_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, ParameterList *parms, char *param_data, ItemTypeCheckFunc check_item_type, const char *item_type_str, int item_size, ItemConvertFunc convert_item, RNA_SetArrayFunc rna_set_array, const char *error_prefix)
+{
+ int totdim, dim_size[MAX_ARRAY_DIMENSION];
+ int totitem;
+ char *data= NULL;
+
+ totdim= RNA_property_array_dimension(ptr, prop, dim_size);
+
+ if (!validate_array(py, ptr, prop, 0, check_item_type, item_type_str, &totitem, error_prefix)) {
+ return 0;
+ }
+
+ if (totitem) {
+ /* note: this code is confusing */
+ if(param_data && RNA_property_flag(prop) & PROP_DYNAMIC) {
+ /* not freeing allocated mem, RNA_parameter_list_free() will do this */
+ ParameterDynAlloc *param_alloc= (ParameterDynAlloc *)param_data;
+ param_alloc->array_tot= (int)totitem;
+ param_alloc->array= MEM_callocN(item_size * totitem, "py_to_array dyn"); /* freeing param list will free */
+
+ data= param_alloc->array;
+ }
+ else if (param_data) {
+ data= param_data;
+ }
+ else {
+ data= PyMem_MALLOC(item_size * totitem);
+ }
+
+ copy_values(py, ptr, prop, 0, data, item_size, NULL, convert_item, NULL);
+
+ if (param_data==NULL) {
+ /* NULL can only pass through in case RNA property arraylength is 0 (impossible?) */
+ rna_set_array(ptr, prop, data);
+ PyMem_FREE(data);
+ }
+ }
+
+ return 1;
+}
+
+static int py_to_array_index(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, int arrayoffset, int index, ItemTypeCheckFunc check_item_type, const char *item_type_str, ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index, const char *error_prefix)
+{
+ int totdim, dimsize[MAX_ARRAY_DIMENSION];
+ int totitem, i;
+
+ totdim= RNA_property_array_dimension(ptr, prop, dimsize);
+
+ /* convert index */
+
+ /* arr[3][4][5]
+
+ arr[2] = x
+ lvalue_dim=0, index = 0 + 2 * 4 * 5
+
+ arr[2][3] = x
+ lvalue_dim=1, index = 40 + 3 * 5 */
+
+ lvalue_dim++;
+
+ for (i= lvalue_dim; i < totdim; i++)
+ index *= dimsize[i];
+
+ index += arrayoffset;
+
+ if (!validate_array(py, ptr, prop, lvalue_dim, check_item_type, item_type_str, &totitem, error_prefix))
+ return 0;
+
+ if (totitem)
+ copy_values(py, ptr, prop, lvalue_dim, NULL, 0, &index, convert_item, rna_set_index);
+
+ return 1;
+}
+
+static void py_to_float(PyObject *py, char *data)
+{
+ *(float*)data= (float)PyFloat_AsDouble(py);
+}
+
+static void py_to_int(PyObject *py, char *data)
+{
+ *(int*)data= (int)PyLong_AsSsize_t(py);
+}
+
+static void py_to_bool(PyObject *py, char *data)
+{
+ *(int*)data= (int)PyObject_IsTrue(py);
+}
+
+static int py_float_check(PyObject *py)
+{
+ /* accept both floats and integers */
+ return PyFloat_Check(py) || PyLong_Check(py);
+}
+
+static int py_int_check(PyObject *py)
+{
+ /* accept only integers */
+ return PyLong_Check(py);
+}
+
+static int py_bool_check(PyObject *py)
+{
+ return PyBool_Check(py);
+}
+
+static void float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
+{
+ RNA_property_float_set_index(ptr, prop, index, *(float*)value);
+}
+
+static void int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
+{
+ RNA_property_int_set_index(ptr, prop, index, *(int*)value);
+}
+
+static void bool_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
+{
+ RNA_property_boolean_set_index(ptr, prop, index, *(int*)value);
+}
+
+int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, ParameterList *parms, char *param_data, PyObject *py, const char *error_prefix)
+{
+ int ret;
+ switch (RNA_property_type(prop)) {
+ case PROP_FLOAT:
+ ret= py_to_array(py, ptr, prop, parms, param_data, py_float_check, "float", sizeof(float), py_to_float, (RNA_SetArrayFunc)RNA_property_float_set_array, error_prefix);
+ break;
+ case PROP_INT:
+ ret= py_to_array(py, ptr, prop, parms, param_data, py_int_check, "int", sizeof(int), py_to_int, (RNA_SetArrayFunc)RNA_property_int_set_array, error_prefix);
+ break;
+ case PROP_BOOLEAN:
+ ret= py_to_array(py, ptr, prop, parms, param_data, py_bool_check, "boolean", sizeof(int), py_to_bool, (RNA_SetArrayFunc)RNA_property_boolean_set_array, error_prefix);
+ break;
+ default:
+ PyErr_SetString(PyExc_TypeError, "not an array type");
+ ret= 0;
+ }
+
+ return ret;
+}
+
+int pyrna_py_to_array_index(PointerRNA *ptr, PropertyRNA *prop, int arraydim, int arrayoffset, int index, PyObject *py, const char *error_prefix)
+{
+ int ret;
+ switch (RNA_property_type(prop)) {
+ case PROP_FLOAT:
+ ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_float_check, "float", py_to_float, float_set_index, error_prefix);
+ break;
+ case PROP_INT:
+ ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_int_check, "int", py_to_int, int_set_index, error_prefix);
+ break;
+ case PROP_BOOLEAN:
+ ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_bool_check, "boolean", py_to_bool, bool_set_index, error_prefix);
+ break;
+ default:
+ PyErr_SetString(PyExc_TypeError, "not an array type");
+ ret= 0;
+ }
+
+ return ret;
+}
+
+static PyObject *pyrna_array_item(PointerRNA *ptr, PropertyRNA *prop, int index)
+{
+ PyObject *item;
+
+ switch (RNA_property_type(prop)) {
+ case PROP_FLOAT:
+ item= PyFloat_FromDouble(RNA_property_float_get_index(ptr, prop, index));
+ break;
+ case PROP_BOOLEAN:
+ item= PyBool_FromLong(RNA_property_boolean_get_index(ptr, prop, index));
+ break;
+ case PROP_INT:
+ item= PyLong_FromSsize_t(RNA_property_int_get_index(ptr, prop, index));
+ break;
+ default:
+ PyErr_SetString(PyExc_TypeError, "not an array type");
+ item= NULL;
+ }
+
+ return item;
+}
+
+#if 0
+/* XXX this is not used (and never will?) */
+/* Given an array property, creates an N-dimensional tuple of values. */
+static PyObject *pyrna_py_from_array_internal(PointerRNA *ptr, PropertyRNA *prop, int dim, int *index)
+{
+ PyObject *tuple;
+ int i, len;
+ int totdim= RNA_property_array_dimension(ptr, prop, NULL);
+
+ len= RNA_property_multi_array_length(ptr, prop, dim);
+
+ tuple= PyTuple_New(len);
+
+ for (i= 0; i < len; i++) {
+ PyObject *item;
+
+ if (dim + 1 < totdim)
+ item= pyrna_py_from_array_internal(ptr, prop, dim + 1, index);
+ else {
+ item= pyrna_array_item(ptr, prop, *index);
+ *index= *index + 1;
+ }
+
+ if (!item) {
+ Py_DECREF(tuple);
+ return NULL;
+ }
+
+ PyTuple_SetItem(tuple, i, item);
+ }
+
+ return tuple;
+}
+#endif
+
+PyObject *pyrna_py_from_array_index(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, int index)
+{
+ int totdim, arraydim, arrayoffset, dimsize[MAX_ARRAY_DIMENSION], i, len;
+ BPy_PropertyArrayRNA *ret= NULL;
+
+ arraydim= self ? self->arraydim : 0;
+ arrayoffset = self ? self->arrayoffset : 0;
+
+ /* just in case check */
+ len= RNA_property_multi_array_length(ptr, prop, arraydim);
+ if (index >= len || index < 0) {
+ /* this shouldn't happen because higher level funcs must check for invalid index */
+ if (G.f & G_DEBUG) printf("pyrna_py_from_array_index: invalid index %d for array with length=%d\n", index, len);
+
+ PyErr_SetString(PyExc_IndexError, "out of range");
+ return NULL;
+ }
+
+ totdim= RNA_property_array_dimension(ptr, prop, dimsize);
+
+ if (arraydim + 1 < totdim) {
+ ret= (BPy_PropertyArrayRNA*)pyrna_prop_CreatePyObject(ptr, prop);
+ ret->arraydim= arraydim + 1;
+
+ /* arr[3][4][5]
+
+ x = arr[2]
+ index = 0 + 2 * 4 * 5
+
+ x = arr[2][3]
+ index = offset + 3 * 5 */
+
+ for (i= arraydim + 1; i < totdim; i++)
+ index *= dimsize[i];
+
+ ret->arrayoffset= arrayoffset + index;
+ }
+ else {
+ index = arrayoffset + index;
+ ret= (BPy_PropertyArrayRNA *)pyrna_array_item(ptr, prop, index);
+ }
+
+ return (PyObject*)ret;
+}
+
+PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop)
+{
+ PyObject *ret;
+
+ ret= pyrna_math_object_from_array(ptr, prop);
+
+ /* is this a maths object? */
+ if (ret) return ret;
+
+ return pyrna_prop_CreatePyObject(ptr, prop);
+}
+
+/* TODO, multi-dimensional arrays */
+int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
+{
+ int len= RNA_property_array_length(ptr, prop);
+ int type;
+ int i;
+
+ if(len==0) /* possible with dynamic arrays */
+ return 0;
+
+ if (RNA_property_array_dimension(ptr, prop, NULL) > 1) {
+ PyErr_SetString(PyExc_TypeError, "PropertyRNA - multi dimensional arrays not supported yet");
+ return -1;
+ }
+
+ type= RNA_property_type(prop);
+
+ switch (type) {
+ case PROP_FLOAT:
+ {
+ float value_f= PyFloat_AsDouble(value);
+ if(value_f==-1 && PyErr_Occurred()) {
+ PyErr_Clear();
+ return 0;
+ }
+ else {
+ float tmp[32];
+ float *tmp_arr;
+
+ if(len * sizeof(float) > sizeof(tmp)) {
+ tmp_arr= PyMem_MALLOC(len * sizeof(float));
+ }
+ else {
+ tmp_arr= tmp;
+ }
+
+ RNA_property_float_get_array(ptr, prop, tmp_arr);
+
+ for(i=0; i<len; i++)
+ if(tmp_arr[i] == value_f)
+ break;
+
+ if(tmp_arr != tmp)
+ PyMem_FREE(tmp_arr);
+
+ return i<len ? 1 : 0;
+ }
+ break;
+ }
+ case PROP_BOOLEAN:
+ case PROP_INT:
+ {
+ int value_i= PyLong_AsSsize_t(value);
+ if(value_i==-1 && PyErr_Occurred()) {
+ PyErr_Clear();
+ return 0;
+ }
+ else {
+ int tmp[32];
+ int *tmp_arr;
+
+ if(len * sizeof(int) > sizeof(tmp)) {
+ tmp_arr= PyMem_MALLOC(len * sizeof(int));
+ }
+ else {
+ tmp_arr= tmp;
+ }
+
+ if(type==PROP_BOOLEAN)
+ RNA_property_boolean_get_array(ptr, prop, tmp_arr);
+ else
+ RNA_property_int_get_array(ptr, prop, tmp_arr);
+
+ for(i=0; i<len; i++)
+ if(tmp_arr[i] == value_i)
+ break;
+
+ if(tmp_arr != tmp)
+ PyMem_FREE(tmp_arr);
+
+ return i<len ? 1 : 0;
+ }
+ break;
+ }
+ }
+
+ /* should never reach this */
+ PyErr_SetString(PyExc_TypeError, "PropertyRNA - type not in float/bool/int");
+ return -1;
+}
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 4f59467a9d6..669c6541bc5 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -353,6 +353,10 @@ typedef struct {
} PyModuleObject;
#endif
+int PyC_MainModule_Backup(PyObject **main_mod);
+PyObject *PyC_DefaultNameSpace(const char *n);
+int PyC_MainModule_Restore(PyObject *main_mod);
+
static int python_script_exec(bContext *C, const char *fn, struct Text *text, struct ReportList *reports)
{
PyObject *main_mod= NULL;
diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c
index 51ab889e321..f890ab81948 100644
--- a/source/blender/python/intern/bpy_operator_wrap.c
+++ b/source/blender/python/intern/bpy_operator_wrap.c
@@ -1,4 +1,3 @@
-
/**
* $Id$
*
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index f18b1aee5ab..d3bda0e2a5f 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -1116,6 +1116,8 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
int subtype= RNA_property_subtype(prop);
if(ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) {
/* TODO, get size */
+ PyObject *PyC_UnicodeAsByte(PyObject *value, PyObject **value_coerce);
+
param= PyC_UnicodeAsByte(value, &value_coerce);
}
else {
diff --git a/source/blender/python/intern/bpy_ui.c b/source/blender/python/intern/bpy_ui.c
new file mode 100644
index 00000000000..ab50ebd8bd5
--- /dev/null
+++ b/source/blender/python/intern/bpy_ui.c
@@ -0,0 +1,69 @@
+/**
+ * $Id$
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "bpy_ui.h"
+#include "bpy_util.h"
+#include "bpy_rna.h" /* for rna buttons */
+#include "bpy_operator.h" /* for setting button operator properties */
+
+#include "WM_types.h" /* for WM_OP_INVOKE_DEFAULT & friends */
+
+#include "BLI_dynstr.h"
+
+#include "MEM_guardedalloc.h"
+#include "BKE_global.h" /* evil G.* */
+#include "BKE_context.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h" /* only for SpaceLink */
+#include "UI_interface.h"
+#include "WM_api.h"
+
+/* Dummy Module, may want to include non RNA UI functions here, else it can be removed */
+
+static struct PyMethodDef ui_methods[] = {
+ {NULL, NULL, 0, NULL}
+};
+
+static struct PyModuleDef ui_module = {
+ PyModuleDef_HEAD_INIT,
+ "_bpy.ui",
+ "",
+ -1,/* multiple "initialization" just copies the module dict. */
+ ui_methods,
+ NULL, NULL, NULL, NULL
+};
+
+PyObject *BPY_ui_module( void )
+{
+ PyObject *submodule;
+ submodule= PyModule_Create(&ui_module);
+
+ /* INCREF since its its assumed that all these functions return the
+ * module with a new ref like PyDict_New, since they are passed to
+ * PyModule_AddObject which steals a ref */
+ Py_INCREF(submodule);
+
+ return submodule;
+}
diff --git a/source/blender/python/intern/bpy_ui.h b/source/blender/python/intern/bpy_ui.h
new file mode 100644
index 00000000000..95afa1f08c8
--- /dev/null
+++ b/source/blender/python/intern/bpy_ui.h
@@ -0,0 +1,31 @@
+/**
+ * $Id: bpy_ui.h 21094 2009-06-23 00:09:26Z gsrb3d $
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef BPY_UI_H__
+#define BPY_UI_H__
+
+#include <Python.h>
+
+PyObject *BPY_ui_module( void );
+
+#endif
diff --git a/source/blender/python/simple_enum_gen.py b/source/blender/python/simple_enum_gen.py
index bc7a2df9fb6..a536f04ecde 100644
--- a/source/blender/python/simple_enum_gen.py
+++ b/source/blender/python/simple_enum_gen.py
@@ -19,24 +19,24 @@
# #**** END GPL LICENSE BLOCK #****
defs = """
- SPACE_EMPTY,
- SPACE_VIEW3D,
- SPACE_IPO,
- SPACE_OUTLINER,
- SPACE_BUTS,
- SPACE_FILE,
+ SPACE_EMPTY,
+ SPACE_VIEW3D,
+ SPACE_IPO,
+ SPACE_OUTLINER,
+ SPACE_BUTS,
+ SPACE_FILE,
SPACE_IMAGE,
- SPACE_INFO,
- SPACE_SEQ,
- SPACE_TEXT,
- SPACE_IMASEL,
- SPACE_SOUND,
- SPACE_ACTION,
- SPACE_NLA,
- SPACE_SCRIPT,
- SPACE_TIME,
- SPACE_NODE,
- SPACEICONMAX
+ SPACE_INFO,
+ SPACE_SEQ,
+ SPACE_TEXT,
+ SPACE_IMASEL,
+ SPACE_SOUND,
+ SPACE_ACTION,
+ SPACE_NLA,
+ SPACE_SCRIPT,
+ SPACE_TIME,
+ SPACE_NODE,
+ SPACEICONMAX
"""
print '\tmod = PyModule_New("dummy");'
@@ -44,21 +44,21 @@ print '\tPyModule_AddObject( submodule, "key", mod );'
for d in defs.split('\n'):
- d = d.replace(',', ' ')
- w = d.split()
+ d = d.replace(',', ' ')
+ w = d.split()
- if not w:
- continue
+ if not w:
+ continue
- try: w.remove("#define")
- except: pass
+ try: w.remove("#define")
+ except: pass
- # print w
+ # print w
- val = w[0]
- py_val = w[0]
+ val = w[0]
+ py_val = w[0]
- print '\tPyModule_AddObject( mod, "%s", PyLong_FromSize_t(%s) );' % (val, py_val)
+ print '\tPyModule_AddObject( mod, "%s", PyLong_FromSize_t(%s) );' % (val, py_val)
diff --git a/source/blender/readblenfile/intern/BLO_readblenfile.c b/source/blender/readblenfile/intern/BLO_readblenfile.c
index eddb82897d5..ac059b12c0a 100644
--- a/source/blender/readblenfile/intern/BLO_readblenfile.c
+++ b/source/blender/readblenfile/intern/BLO_readblenfile.c
@@ -169,4 +169,3 @@ cleanup:
return bfd;
}
-
diff --git a/source/blender/render/SConscript b/source/blender/render/SConscript
index a402139b927..d471025c7da 100644
--- a/source/blender/render/SConscript
+++ b/source/blender/render/SConscript
@@ -6,7 +6,11 @@ raysources = env.Glob('intern/raytrace/*.cpp')
incs = 'intern/include #/intern/guardedalloc ../blenlib ../makesdna ../makesrna'
incs += ' extern/include ../blenkernel ../radiosity/extern/include ../imbuf'
+<<<<<<< .working
+incs += ' ../include ../blenloader ../../../intern/smoke/extern ../bmesh'
+=======
incs += ' ../include ../blenloader ../../../intern/smoke/extern ../../../intern/mikktspace'
+>>>>>>> .merge-right.r35190
cflags_raytrace = env['CCFLAGS']
cxxflags_raytrace = env['CXXFLAGS']
diff --git a/source/blender/render/intern/include/raycounter.h b/source/blender/render/intern/include/raycounter.h
index 78d7d8fe4b4..6c5e2b2f064 100644
--- a/source/blender/render/intern/include/raycounter.h
+++ b/source/blender/render/intern/include/raycounter.h
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: raycounter.h 23649 2009-10-06 02:56:11Z jaguarandi $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/render/intern/include/rayobject.h b/source/blender/render/intern/include/rayobject.h
index 415876ca35f..f5c9dd32b85 100644
--- a/source/blender/render/intern/include/rayobject.h
+++ b/source/blender/render/intern/include/rayobject.h
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: rayobject.h 23651 2009-10-06 03:40:50Z aligorith $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/render/intern/raytrace/reorganize.h b/source/blender/render/intern/raytrace/reorganize.h
index 0524073abfc..2f89cd47faa 100644
--- a/source/blender/render/intern/raytrace/reorganize.h
+++ b/source/blender/render/intern/raytrace/reorganize.h
@@ -30,6 +30,7 @@
#include <float.h>
#include <math.h>
#include <stdio.h>
+#include <math.h>
#include <algorithm>
#include <queue>
@@ -171,7 +172,7 @@ void pushup(Node *parent)
{
float c_area = bb_area(child->bb, child->bb+3) ;
int nchilds = count_childs(child);
- float original_cost = ((p_area != 0.0f)? (c_area / p_area)*nchilds: 1.0f) + 1;
+ float original_cost = (c_area / p_area)*nchilds + 1;
float flatten_cost = nchilds;
if(flatten_cost < original_cost && nchilds >= 2)
{
@@ -302,6 +303,7 @@ float bvh_refit(Node *node)
* with the purpose to reduce the expected cost (eg.: number of BB tests).
*/
#include <vector>
+#include <cmath>
#define MAX_CUT_SIZE 4 /* svbvh assumes max 4 children! */
#define MAX_OPTIMIZE_CHILDS MAX_CUT_SIZE
@@ -409,7 +411,7 @@ struct VBVH_optimalPackSIMD
for(Node *child = node->child; child && RE_rayobject_isAligned(child); child = child->sibling)
{
this->child[nchilds] = child;
- this->child_hit_prob[nchilds] = (parent_area != 0.0f)? bb_area(child->bb, child->bb+3) / parent_area: 1.0f;
+ this->child_hit_prob[nchilds] = bb_area(child->bb, child->bb+3) / parent_area;
nchilds++;
}
@@ -479,7 +481,7 @@ struct VBVH_optimalPackSIMD
float parent_area = bb_area(node->bb, node->bb+3);
for(Node *child = node->child; child && RE_rayobject_isAligned(child); child = child->sibling)
{
- cost += ((parent_area != 0.0f)? ( bb_area(child->bb, child->bb+3) / parent_area ): 1.0f) * child->get_cost(1);
+ cost += ( bb_area(child->bb, child->bb+3) / parent_area ) * child->get_cost(1);
}
cost += testcost(nchilds);
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 0da61204aba..c2c33df1e99 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -1540,7 +1540,7 @@ static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int
if(sd->uvco && ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)) {
for(i=0; i<sd->totuv; i++) {
if(num != DMCACHE_NOTFOUND) {
- MFace *mface = dm->getFaceData(dm, num, CD_MFACE);
+ MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE);
MTFace *mtface = (MTFace*)CustomData_get_layer_n(&dm->faceData, CD_MTFACE, i);
mtface += num;
@@ -1557,7 +1557,7 @@ static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int
if(sd->mcol && ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)) {
for(i=0; i<sd->totcol; i++) {
if(num != DMCACHE_NOTFOUND) {
- MFace *mface = dm->getFaceData(dm, num, CD_MFACE);
+ MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE);
MCol *mc = (MCol*)CustomData_get_layer_n(&dm->faceData, CD_MCOL, i);
mc += num * 4;
@@ -1789,8 +1789,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
if(ma->amb != 0.0f)
dosurfacecache= 1;
- totface= psmd->dm->getNumFaces(psmd->dm);
- origindex= psmd->dm->getFaceDataArray(psmd->dm, CD_ORIGINDEX);
+ totface= psmd->dm->getNumTessFaces(psmd->dm);
+ origindex= psmd->dm->getTessFaceDataArray(psmd->dm, CD_ORIGINDEX);
for(a=0; a<totface; a++)
strandbuf->totbound= MAX2(strandbuf->totbound, (origindex)? origindex[a]: a);
@@ -1834,7 +1834,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
num= pa->num_dmcache;
if(num == DMCACHE_NOTFOUND)
- if(pa->num < psmd->dm->getNumFaces(psmd->dm))
+ if(pa->num < psmd->dm->getNumTessFaces(psmd->dm))
num= pa->num;
get_particle_uvco_mcol(part->from, psmd->dm, pa->fuv, num, &sd);
@@ -1895,7 +1895,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
num = parent->num_dmcache;
if(num == DMCACHE_NOTFOUND)
- if(parent->num < psmd->dm->getNumFaces(psmd->dm))
+ if(parent->num < psmd->dm->getNumTessFaces(psmd->dm))
num = parent->num;
get_particle_uvco_mcol(part->from, psmd->dm, parent->fuv, num, &sd);
@@ -2734,8 +2734,8 @@ static void init_render_dm(DerivedMesh *dm, Render *re, ObjectRen *obr,
for(a1=0; (a1<ob->totcol || (a1==0 && ob->totcol==0)); a1++) {
ma= give_render_material(re, ob, a1+1);
- end= dm->getNumFaces(dm);
- mface= dm->getFaceArray(dm);
+ end= dm->getNumTessFaces(dm);
+ mface= dm->getTessFaceArray(dm);
for(a=0; a<end; a++, mface++) {
int v1, v2, v3, v4, flag;
@@ -3099,10 +3099,10 @@ static struct edgesort *make_mesh_edge_lookup(DerivedMesh *dm, int *totedgesort)
unsigned int *mcol=NULL;
int a, totedge=0, totface;
- mface= dm->getFaceArray(dm);
- totface= dm->getNumFaces(dm);
- tface= dm->getFaceDataArray(dm, CD_MTFACE);
- mcol= dm->getFaceDataArray(dm, CD_MCOL);
+ mface= dm->getTessFaceArray(dm);
+ totface= dm->getNumTessFaces(dm);
+ tface= dm->getTessFaceDataArray(dm, CD_MTFACE);
+ mcol= dm->getTessFaceDataArray(dm, CD_MCOL);
if(mcol==NULL && tface==NULL) return NULL;
@@ -3320,7 +3320,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
totvert= dm->getNumVerts(dm);
/* attempt to autsmooth on original mesh, only without subsurf */
- if(do_autosmooth && me->totvert==totvert && me->totface==dm->getNumFaces(dm))
+ if(do_autosmooth && me->totvert==totvert && me->totface==dm->getNumTessFaces(dm))
use_original_normals= 1;
ms = (totvert==me->totvert)?me->msticky:NULL;
@@ -3381,8 +3381,8 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
}
if(ok) {
- end= dm->getNumFaces(dm);
- mface= dm->getFaceArray(dm);
+ end= dm->getNumTessFaces(dm);
+ mface= dm->getTessFaceArray(dm);
for(a=0; a<end; a++, mface++) {
int v1, v2, v3, v4, flag;
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 7c24169b3bd..abb7acd91fc 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -2514,7 +2514,7 @@ static void do_render_seq(Render * re)
if(ibuf->rect_float) {
if (!rr->rectf)
rr->rectf= MEM_mallocN(4*sizeof(float)*rr->rectx*rr->recty, "render_seq rectf");
-
+
/* color management: when off ensure rectf is non-lin, since thats what the internal
* render engine delivers */
if(re->r.color_mgt_flag & R_COLOR_MANAGEMENT) {
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index 1325fd89ec6..5cf65eccd9a 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -205,7 +205,7 @@ static void pointdensity_cache_object(Render *re, PointDensity *pd, Object *ob)
for(i=0; i < pd->totpoints; i++, mvert++) {
float co[3];
-
+
VECCOPY(co, mvert->co);
switch(pd->ob_cache_space) {
@@ -255,7 +255,7 @@ static void cache_pointdensity(Render *re, Tex *tex)
Object *ob = pd->object;
if (ob && ob->type == OB_MESH)
pointdensity_cache_object(re, pd, ob);
- }
+ }
}
static void free_pointdensity(Render *UNUSED(re), Tex *tex)
diff --git a/source/blender/render/intern/source/rayobject_blibvh.c b/source/blender/render/intern/source/rayobject_blibvh.c
new file mode 100644
index 00000000000..16c2dcb83d8
--- /dev/null
+++ b/source/blender/render/intern/source/rayobject_blibvh.c
@@ -0,0 +1,169 @@
+/**
+ * $Id: rayobject_blibvh.c 23649 2009-10-06 02:56:11Z jaguarandi $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include <assert.h>
+
+#include "MEM_guardedalloc.h"
+#include "BKE_utildefines.h"
+#include "BLI_kdopbvh.h"
+#include "BLI_math.h"
+#include "RE_raytrace.h"
+#include "render_types.h"
+#include "rayobject.h"
+
+static int RE_rayobject_blibvh_intersect(RayObject *o, Isect *isec);
+static void RE_rayobject_blibvh_add(RayObject *o, RayObject *ob);
+static void RE_rayobject_blibvh_done(RayObject *o);
+static void RE_rayobject_blibvh_free(RayObject *o);
+static void RE_rayobject_blibvh_bb(RayObject *o, float *min, float *max);
+
+static float RE_rayobject_blibvh_cost(RayObject *o)
+{
+ //TODO calculate the expected cost to raycast on this structure
+ return 1.0;
+}
+
+static void RE_rayobject_blibvh_hint_bb(RayObject *o, RayHint *hint, float *min, float *max)
+{
+ return;
+}
+
+static RayObjectAPI bvh_api =
+{
+ RE_rayobject_blibvh_intersect,
+ RE_rayobject_blibvh_add,
+ RE_rayobject_blibvh_done,
+ RE_rayobject_blibvh_free,
+ RE_rayobject_blibvh_bb,
+ RE_rayobject_blibvh_cost,
+ RE_rayobject_blibvh_hint_bb
+};
+
+typedef struct BVHObject
+{
+ RayObject rayobj;
+ RayObject **leafs, **next_leaf;
+ BVHTree *bvh;
+ float bb[2][3];
+
+} BVHObject;
+
+
+RayObject *RE_rayobject_blibvh_create(int size)
+{
+ BVHObject *obj= (BVHObject*)MEM_callocN(sizeof(BVHObject), "BVHObject");
+ assert( RE_rayobject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */
+
+ obj->rayobj.api = &bvh_api;
+ obj->bvh = BLI_bvhtree_new(size, 0.0, 4, 6);
+ obj->next_leaf = obj->leafs = (RayObject**)MEM_callocN(size*sizeof(RayObject*), "BVHObject leafs");
+
+ INIT_MINMAX(obj->bb[0], obj->bb[1]);
+ return RE_rayobject_unalignRayAPI((RayObject*) obj);
+}
+
+struct BVHCallbackUserData
+{
+ Isect *isec;
+ RayObject **leafs;
+};
+
+static void bvh_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+ struct BVHCallbackUserData *data = (struct BVHCallbackUserData*)userdata;
+ Isect *isec = data->isec;
+ RayObject *face = data->leafs[index];
+
+ if(RE_rayobject_intersect(face,isec))
+ {
+ hit->index = index;
+
+ if(isec->mode == RE_RAY_SHADOW)
+ hit->dist = 0;
+ else
+ hit->dist = isec->labda*isec->dist;
+ }
+}
+
+static int RE_rayobject_blibvh_intersect(RayObject *o, Isect *isec)
+{
+ BVHObject *obj = (BVHObject*)o;
+ BVHTreeRayHit hit;
+ float dir[3];
+ struct BVHCallbackUserData data;
+ data.isec = isec;
+ data.leafs = obj->leafs;
+
+ VECCOPY(dir, isec->vec);
+ normalize_v3(dir);
+
+ hit.index = 0;
+ hit.dist = isec->labda*isec->dist;
+
+ return BLI_bvhtree_ray_cast(obj->bvh, isec->start, dir, 0.0, &hit, bvh_callback, (void*)&data);
+}
+
+static void RE_rayobject_blibvh_add(RayObject *o, RayObject *ob)
+{
+ BVHObject *obj = (BVHObject*)o;
+ float min_max[6];
+ INIT_MINMAX(min_max, min_max+3);
+ RE_rayobject_merge_bb(ob, min_max, min_max+3);
+
+ DO_MIN(min_max , obj->bb[0]);
+ DO_MAX(min_max+3, obj->bb[1]);
+
+ BLI_bvhtree_insert(obj->bvh, obj->next_leaf - obj->leafs, min_max, 2 );
+ *(obj->next_leaf++) = ob;
+}
+
+static void RE_rayobject_blibvh_done(RayObject *o)
+{
+ BVHObject *obj = (BVHObject*)o;
+ BLI_bvhtree_balance(obj->bvh);
+}
+
+static void RE_rayobject_blibvh_free(RayObject *o)
+{
+ BVHObject *obj = (BVHObject*)o;
+
+ if(obj->bvh)
+ BLI_bvhtree_free(obj->bvh);
+
+ if(obj->leafs)
+ MEM_freeN(obj->leafs);
+
+ MEM_freeN(obj);
+}
+
+static void RE_rayobject_blibvh_bb(RayObject *o, float *min, float *max)
+{
+ BVHObject *obj = (BVHObject*)o;
+ DO_MIN( obj->bb[0], min );
+ DO_MAX( obj->bb[1], max );
+}
diff --git a/source/blender/render/intern/source/rayobject_instance.c b/source/blender/render/intern/source/rayobject_instance.c
new file mode 100644
index 00000000000..a3e062c01c6
--- /dev/null
+++ b/source/blender/render/intern/source/rayobject_instance.c
@@ -0,0 +1,207 @@
+/**
+ * $Id: rayobject_instance.c 23763 2009-10-10 18:42:20Z jaguarandi $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include <assert.h>
+
+#include "MEM_guardedalloc.h"
+#include "BKE_utildefines.h"
+#include "BLI_math.h"
+#include "RE_raytrace.h"
+#include "rayobject.h"
+
+#define RE_COST_INSTANCE (1.0f)
+
+static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec);
+static void RE_rayobject_instance_free(RayObject *o);
+static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max);
+static float RE_rayobject_instance_cost(RayObject *o);
+
+static void RE_rayobject_instance_hint_bb(RayObject *o, RayHint *hint, float *min, float *max)
+{}
+
+static RayObjectAPI instance_api =
+{
+ RE_rayobject_instance_intersect,
+ NULL, //static void RE_rayobject_instance_add(RayObject *o, RayObject *ob);
+ NULL, //static void RE_rayobject_instance_done(RayObject *o);
+ RE_rayobject_instance_free,
+ RE_rayobject_instance_bb,
+ RE_rayobject_instance_cost,
+ RE_rayobject_instance_hint_bb
+};
+
+typedef struct InstanceRayObject
+{
+ RayObject rayobj;
+ RayObject *target;
+
+ void *ob; //Object represented by this instance
+ void *target_ob; //Object represented by the inner RayObject, needed to handle self-intersection
+
+ float global2target[4][4];
+ float target2global[4][4];
+
+} InstanceRayObject;
+
+
+RayObject *RE_rayobject_instance_create(RayObject *target, float transform[][4], void *ob, void *target_ob)
+{
+ InstanceRayObject *obj= (InstanceRayObject*)MEM_callocN(sizeof(InstanceRayObject), "InstanceRayObject");
+ assert( RE_rayobject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */
+
+ obj->rayobj.api = &instance_api;
+ obj->target = target;
+ obj->ob = ob;
+ obj->target_ob = target_ob;
+
+ copy_m4_m4(obj->target2global, transform);
+ invert_m4_m4(obj->global2target, obj->target2global);
+
+ return RE_rayobject_unalignRayAPI((RayObject*) obj);
+}
+
+static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
+{
+ //TODO
+ // *there is probably a faster way to convert between coordinates
+
+ InstanceRayObject *obj = (InstanceRayObject*)o;
+ int res;
+ float start[3], vec[3], labda, dist;
+ int changed = 0, i;
+
+ //TODO - this is disabling self intersection on instances
+ if(isec->orig.ob == obj->ob && obj->ob)
+ {
+ changed = 1;
+ isec->orig.ob = obj->target_ob;
+ }
+
+
+ VECCOPY( start, isec->start );
+ VECCOPY( vec , isec->vec );
+ labda = isec->labda;
+ dist = isec->dist;
+
+ //Transform to target coordinates system
+ VECADD( isec->vec, isec->vec, isec->start );
+
+ mul_m4_v3(obj->global2target, isec->start);
+ mul_m4_v3(obj->global2target, isec->vec );
+
+ isec->dist = len_v3v3( isec->start, isec->vec );
+ VECSUB( isec->vec, isec->vec, isec->start );
+
+ isec->labda *= isec->dist / dist;
+
+ //Update idot_axis and bv_index
+ for(i=0; i<3; i++)
+ {
+ isec->idot_axis[i] = 1.0f / isec->vec[i];
+
+ isec->bv_index[2*i] = isec->idot_axis[i] < 0.0 ? 1 : 0;
+ isec->bv_index[2*i+1] = 1 - isec->bv_index[2*i];
+
+ isec->bv_index[2*i] = i+3*isec->bv_index[2*i];
+ isec->bv_index[2*i+1] = i+3*isec->bv_index[2*i+1];
+ }
+
+ //Raycast
+ res = RE_rayobject_intersect(obj->target, isec);
+
+ //Restore coordinate space coords
+ if(res == 0)
+ {
+ isec->labda = labda;
+ }
+ else
+ {
+ isec->labda *= dist / isec->dist;
+ isec->hit.ob = obj->ob;
+
+#ifdef RT_USE_LAST_HIT
+ // TODO support for last hit optimization in instances that can jump
+ // directly to the last hit face.
+ // For now it jumps directly to the last-hit instance root node.
+ isec->last_hit = RE_rayobject_unalignRayAPI((RayObject*) obj);
+#endif
+ }
+ isec->dist = dist;
+ VECCOPY( isec->start, start );
+ VECCOPY( isec->vec, vec );
+
+ if(changed)
+ isec->orig.ob = obj->ob;
+
+ //Update idot_axis and bv_index
+ for(i=0; i<3; i++)
+ {
+ isec->idot_axis[i] = 1.0f / isec->vec[i];
+
+ isec->bv_index[2*i] = isec->idot_axis[i] < 0.0 ? 1 : 0;
+ isec->bv_index[2*i+1] = 1 - isec->bv_index[2*i];
+
+ isec->bv_index[2*i] = i+3*isec->bv_index[2*i];
+ isec->bv_index[2*i+1] = i+3*isec->bv_index[2*i+1];
+ }
+
+ return res;
+}
+
+static void RE_rayobject_instance_free(RayObject *o)
+{
+ InstanceRayObject *obj = (InstanceRayObject*)o;
+ MEM_freeN(obj);
+}
+
+static float RE_rayobject_instance_cost(RayObject *o)
+{
+ InstanceRayObject *obj = (InstanceRayObject*)o;
+ return RE_rayobject_cost(obj->target) + RE_COST_INSTANCE;
+}
+
+static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max)
+{
+ //TODO:
+ // *better bb.. calculated without rotations of bb
+ // *maybe cache that better-fitted-BB at the InstanceRayObject
+ InstanceRayObject *obj = (InstanceRayObject*)o;
+
+ float m[3], M[3], t[3];
+ int i, j;
+ INIT_MINMAX(m, M);
+ RE_rayobject_merge_bb(obj->target, m, M);
+
+ //There must be a faster way than rotating all the 8 vertexs of the BB
+ for(i=0; i<8; i++)
+ {
+ for(j=0; j<3; j++) t[j] = i&(1<<j) ? M[j] : m[j];
+ mul_m4_v3(obj->target2global, t);
+ DO_MINMAX(t, min, max);
+ }
+}
diff --git a/source/blender/render/intern/source/rayobject_octree.c b/source/blender/render/intern/source/rayobject_octree.c
new file mode 100644
index 00000000000..98265d166d0
--- /dev/null
+++ b/source/blender/render/intern/source/rayobject_octree.c
@@ -0,0 +1,1080 @@
+/**
+ * $Id: rayobject_octree.c 23649 2009-10-06 02:56:11Z jaguarandi $
+ *
+ * ***** 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) 1990-1998 NeoGeo BV.
+ * All rights reserved.
+ *
+ * Contributors: 2004/2005 Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* IMPORTANT NOTE: this code must be independent of any other render code
+ to use it outside the renderer! */
+
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <float.h>
+#include <assert.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_material_types.h"
+
+#include "BKE_utildefines.h"
+
+#include "BLI_math.h"
+
+#include "rayobject.h"
+
+/* ********** structs *************** */
+#define BRANCH_ARRAY 1024
+#define NODE_ARRAY 4096
+
+typedef struct Branch
+{
+ struct Branch *b[8];
+} Branch;
+
+typedef struct OcVal
+{
+ short ocx, ocy, ocz;
+} OcVal;
+
+typedef struct Node
+{
+ struct RayFace *v[8];
+ struct OcVal ov[8];
+ struct Node *next;
+} Node;
+
+typedef struct Octree {
+ RayObject rayobj;
+
+ struct Branch **adrbranch;
+ struct Node **adrnode;
+ float ocsize; /* ocsize: mult factor, max size octree */
+ float ocfacx,ocfacy,ocfacz;
+ float min[3], max[3];
+ int ocres;
+ int branchcount, nodecount;
+
+ /* during building only */
+ char *ocface;
+
+ RayFace **ro_nodes;
+ int ro_nodes_size, ro_nodes_used;
+
+} Octree;
+
+static int RE_rayobject_octree_intersect(RayObject *o, Isect *isec);
+static void RE_rayobject_octree_add(RayObject *o, RayObject *ob);
+static void RE_rayobject_octree_done(RayObject *o);
+static void RE_rayobject_octree_free(RayObject *o);
+static void RE_rayobject_octree_bb(RayObject *o, float *min, float *max);
+
+/*
+ * This function is not expected to be called by current code state.
+ */
+static float RE_rayobject_octree_cost(RayObject *o)
+{
+ return 1.0;
+}
+
+static void RE_rayobject_octree_hint_bb(RayObject *o, RayHint *hint, float *min, float *max)
+{
+ return;
+}
+
+static RayObjectAPI octree_api =
+{
+ RE_rayobject_octree_intersect,
+ RE_rayobject_octree_add,
+ RE_rayobject_octree_done,
+ RE_rayobject_octree_free,
+ RE_rayobject_octree_bb,
+ RE_rayobject_octree_cost,
+ RE_rayobject_octree_hint_bb
+};
+
+/* **************** ocval method ******************* */
+/* within one octree node, a set of 3x15 bits defines a 'boundbox' to OR with */
+
+#define OCVALRES 15
+#define BROW16(min, max) (((max)>=OCVALRES? 0xFFFF: (1<<(max+1))-1) - ((min>0)? ((1<<(min))-1):0) )
+
+static void calc_ocval_face(float *v1, float *v2, float *v3, float *v4, short x, short y, short z, OcVal *ov)
+{
+ float min[3], max[3];
+ int ocmin, ocmax;
+
+ VECCOPY(min, v1);
+ VECCOPY(max, v1);
+ DO_MINMAX(v2, min, max);
+ DO_MINMAX(v3, min, max);
+ if(v4) {
+ DO_MINMAX(v4, min, max);
+ }
+
+ ocmin= OCVALRES*(min[0]-x);
+ ocmax= OCVALRES*(max[0]-x);
+ ov->ocx= BROW16(ocmin, ocmax);
+
+ ocmin= OCVALRES*(min[1]-y);
+ ocmax= OCVALRES*(max[1]-y);
+ ov->ocy= BROW16(ocmin, ocmax);
+
+ ocmin= OCVALRES*(min[2]-z);
+ ocmax= OCVALRES*(max[2]-z);
+ ov->ocz= BROW16(ocmin, ocmax);
+
+}
+
+static void calc_ocval_ray(OcVal *ov, float xo, float yo, float zo, float *vec1, float *vec2)
+{
+ int ocmin, ocmax;
+
+ if(vec1[0]<vec2[0]) {
+ ocmin= OCVALRES*(vec1[0] - xo);
+ ocmax= OCVALRES*(vec2[0] - xo);
+ } else {
+ ocmin= OCVALRES*(vec2[0] - xo);
+ ocmax= OCVALRES*(vec1[0] - xo);
+ }
+ ov->ocx= BROW16(ocmin, ocmax);
+
+ if(vec1[1]<vec2[1]) {
+ ocmin= OCVALRES*(vec1[1] - yo);
+ ocmax= OCVALRES*(vec2[1] - yo);
+ } else {
+ ocmin= OCVALRES*(vec2[1] - yo);
+ ocmax= OCVALRES*(vec1[1] - yo);
+ }
+ ov->ocy= BROW16(ocmin, ocmax);
+
+ if(vec1[2]<vec2[2]) {
+ ocmin= OCVALRES*(vec1[2] - zo);
+ ocmax= OCVALRES*(vec2[2] - zo);
+ } else {
+ ocmin= OCVALRES*(vec2[2] - zo);
+ ocmax= OCVALRES*(vec1[2] - zo);
+ }
+ ov->ocz= BROW16(ocmin, ocmax);
+}
+
+/* ************* octree ************** */
+
+static Branch *addbranch(Octree *oc, Branch *br, short ocb)
+{
+ int index;
+
+ if(br->b[ocb]) return br->b[ocb];
+
+ oc->branchcount++;
+ index= oc->branchcount>>12;
+
+ if(oc->adrbranch[index]==NULL)
+ oc->adrbranch[index]= MEM_callocN(4096*sizeof(Branch), "new oc branch");
+
+ if(oc->branchcount>= BRANCH_ARRAY*4096) {
+ printf("error; octree branches full\n");
+ oc->branchcount=0;
+ }
+
+ return br->b[ocb]= oc->adrbranch[index]+(oc->branchcount & 4095);
+}
+
+static Node *addnode(Octree *oc)
+{
+ int index;
+
+ oc->nodecount++;
+ index= oc->nodecount>>12;
+
+ if(oc->adrnode[index]==NULL)
+ oc->adrnode[index]= MEM_callocN(4096*sizeof(Node),"addnode");
+
+ if(oc->nodecount> NODE_ARRAY*NODE_ARRAY) {
+ printf("error; octree nodes full\n");
+ oc->nodecount=0;
+ }
+
+ return oc->adrnode[index]+(oc->nodecount & 4095);
+}
+
+static int face_in_node(RayFace *face, short x, short y, short z, float rtf[][3])
+{
+ static float nor[3], d;
+ float fx, fy, fz;
+
+ // init static vars
+ if(face) {
+ normal_tri_v3( nor,rtf[0], rtf[1], rtf[2]);
+ d= -nor[0]*rtf[0][0] - nor[1]*rtf[0][1] - nor[2]*rtf[0][2];
+ return 0;
+ }
+
+ fx= x;
+ fy= y;
+ fz= z;
+
+ if((fx)*nor[0] + (fy)*nor[1] + (fz)*nor[2] + d > 0.0f) {
+ if((fx+1)*nor[0] + (fy )*nor[1] + (fz )*nor[2] + d < 0.0f) return 1;
+ if((fx )*nor[0] + (fy+1)*nor[1] + (fz )*nor[2] + d < 0.0f) return 1;
+ if((fx+1)*nor[0] + (fy+1)*nor[1] + (fz )*nor[2] + d < 0.0f) return 1;
+
+ if((fx )*nor[0] + (fy )*nor[1] + (fz+1)*nor[2] + d < 0.0f) return 1;
+ if((fx+1)*nor[0] + (fy )*nor[1] + (fz+1)*nor[2] + d < 0.0f) return 1;
+ if((fx )*nor[0] + (fy+1)*nor[1] + (fz+1)*nor[2] + d < 0.0f) return 1;
+ if((fx+1)*nor[0] + (fy+1)*nor[1] + (fz+1)*nor[2] + d < 0.0f) return 1;
+ }
+ else {
+ if((fx+1)*nor[0] + (fy )*nor[1] + (fz )*nor[2] + d > 0.0f) return 1;
+ if((fx )*nor[0] + (fy+1)*nor[1] + (fz )*nor[2] + d > 0.0f) return 1;
+ if((fx+1)*nor[0] + (fy+1)*nor[1] + (fz )*nor[2] + d > 0.0f) return 1;
+
+ if((fx )*nor[0] + (fy )*nor[1] + (fz+1)*nor[2] + d > 0.0f) return 1;
+ if((fx+1)*nor[0] + (fy )*nor[1] + (fz+1)*nor[2] + d > 0.0f) return 1;
+ if((fx )*nor[0] + (fy+1)*nor[1] + (fz+1)*nor[2] + d > 0.0f) return 1;
+ if((fx+1)*nor[0] + (fy+1)*nor[1] + (fz+1)*nor[2] + d > 0.0f) return 1;
+ }
+
+ return 0;
+}
+
+static void ocwrite(Octree *oc, RayFace *face, int quad, short x, short y, short z, float rtf[][3])
+{
+ Branch *br;
+ Node *no;
+ short a, oc0, oc1, oc2, oc3, oc4, oc5;
+
+ x<<=2;
+ y<<=1;
+
+ br= oc->adrbranch[0];
+
+ if(oc->ocres==512) {
+ oc0= ((x & 1024)+(y & 512)+(z & 256))>>8;
+ br= addbranch(oc, br, oc0);
+ }
+ if(oc->ocres>=256) {
+ oc0= ((x & 512)+(y & 256)+(z & 128))>>7;
+ br= addbranch(oc, br, oc0);
+ }
+ if(oc->ocres>=128) {
+ oc0= ((x & 256)+(y & 128)+(z & 64))>>6;
+ br= addbranch(oc, br, oc0);
+ }
+
+ oc0= ((x & 128)+(y & 64)+(z & 32))>>5;
+ oc1= ((x & 64)+(y & 32)+(z & 16))>>4;
+ oc2= ((x & 32)+(y & 16)+(z & 8))>>3;
+ oc3= ((x & 16)+(y & 8)+(z & 4))>>2;
+ oc4= ((x & 8)+(y & 4)+(z & 2))>>1;
+ oc5= ((x & 4)+(y & 2)+(z & 1));
+
+ br= addbranch(oc, br,oc0);
+ br= addbranch(oc, br,oc1);
+ br= addbranch(oc, br,oc2);
+ br= addbranch(oc, br,oc3);
+ br= addbranch(oc, br,oc4);
+ no= (Node *)br->b[oc5];
+ if(no==NULL) br->b[oc5]= (Branch *)(no= addnode(oc));
+
+ while(no->next) no= no->next;
+
+ a= 0;
+ if(no->v[7]) { /* node full */
+ no->next= addnode(oc);
+ no= no->next;
+ }
+ else {
+ while(no->v[a]!=NULL) a++;
+ }
+
+ no->v[a]= (RayFace*) RE_rayobject_align(face);
+
+ if(quad)
+ calc_ocval_face(rtf[0], rtf[1], rtf[2], rtf[3], x>>2, y>>1, z, &no->ov[a]);
+ else
+ calc_ocval_face(rtf[0], rtf[1], rtf[2], NULL, x>>2, y>>1, z, &no->ov[a]);
+}
+
+static void d2dda(Octree *oc, short b1, short b2, short c1, short c2, char *ocface, short rts[][3], float rtf[][3])
+{
+ int ocx1,ocx2,ocy1,ocy2;
+ int x,y,dx=0,dy=0;
+ float ox1,ox2,oy1,oy2;
+ float labda,labdao,labdax,labday,ldx,ldy;
+
+ ocx1= rts[b1][c1];
+ ocy1= rts[b1][c2];
+ ocx2= rts[b2][c1];
+ ocy2= rts[b2][c2];
+
+ if(ocx1==ocx2 && ocy1==ocy2) {
+ ocface[oc->ocres*ocx1+ocy1]= 1;
+ return;
+ }
+
+ ox1= rtf[b1][c1];
+ oy1= rtf[b1][c2];
+ ox2= rtf[b2][c1];
+ oy2= rtf[b2][c2];
+
+ if(ox1!=ox2) {
+ if(ox2-ox1>0.0f) {
+ labdax= (ox1-ocx1-1.0f)/(ox1-ox2);
+ ldx= -1.0f/(ox1-ox2);
+ dx= 1;
+ } else {
+ labdax= (ox1-ocx1)/(ox1-ox2);
+ ldx= 1.0f/(ox1-ox2);
+ dx= -1;
+ }
+ } else {
+ labdax=1.0f;
+ ldx=0;
+ }
+
+ if(oy1!=oy2) {
+ if(oy2-oy1>0.0f) {
+ labday= (oy1-ocy1-1.0f)/(oy1-oy2);
+ ldy= -1.0f/(oy1-oy2);
+ dy= 1;
+ } else {
+ labday= (oy1-ocy1)/(oy1-oy2);
+ ldy= 1.0f/(oy1-oy2);
+ dy= -1;
+ }
+ } else {
+ labday=1.0f;
+ ldy=0;
+ }
+
+ x=ocx1; y=ocy1;
+ labda= MIN2(labdax, labday);
+
+ while(TRUE) {
+
+ if(x<0 || y<0 || x>=oc->ocres || y>=oc->ocres);
+ else ocface[oc->ocres*x+y]= 1;
+
+ labdao=labda;
+ if(labdax==labday) {
+ labdax+=ldx;
+ x+=dx;
+ labday+=ldy;
+ y+=dy;
+ } else {
+ if(labdax<labday) {
+ labdax+=ldx;
+ x+=dx;
+ } else {
+ labday+=ldy;
+ y+=dy;
+ }
+ }
+ labda=MIN2(labdax,labday);
+ if(labda==labdao) break;
+ if(labda>=1.0f) break;
+ }
+ ocface[oc->ocres*ocx2+ocy2]=1;
+}
+
+static void filltriangle(Octree *oc, short c1, short c2, char *ocface, short *ocmin, short *ocmax)
+{
+ int a, x, y, y1, y2;
+
+ for(x=ocmin[c1];x<=ocmax[c1];x++) {
+ a= oc->ocres*x;
+ for(y=ocmin[c2];y<=ocmax[c2];y++) {
+ if(ocface[a+y]) {
+ y++;
+ while(ocface[a+y] && y!=ocmax[c2]) y++;
+ for(y1=ocmax[c2];y1>y;y1--) {
+ if(ocface[a+y1]) {
+ for(y2=y;y2<=y1;y2++) ocface[a+y2]=1;
+ y1=0;
+ }
+ }
+ y=ocmax[c2];
+ }
+ }
+ }
+}
+
+static void RE_rayobject_octree_free(RayObject *tree)
+{
+ Octree *oc= (Octree*)tree;
+
+#if 0
+ printf("branches %d nodes %d\n", oc->branchcount, oc->nodecount);
+ printf("raycount %d \n", raycount);
+ printf("ray coherent %d \n", coherent_ray);
+ printf("accepted %d rejected %d\n", accepted, rejected);
+#endif
+ if(oc->ocface)
+ MEM_freeN(oc->ocface);
+
+ if(oc->adrbranch) {
+ int a= 0;
+ while(oc->adrbranch[a]) {
+ MEM_freeN(oc->adrbranch[a]);
+ oc->adrbranch[a]= NULL;
+ a++;
+ }
+ MEM_freeN(oc->adrbranch);
+ oc->adrbranch= NULL;
+ }
+ oc->branchcount= 0;
+
+ if(oc->adrnode) {
+ int a= 0;
+ while(oc->adrnode[a]) {
+ MEM_freeN(oc->adrnode[a]);
+ oc->adrnode[a]= NULL;
+ a++;
+ }
+ MEM_freeN(oc->adrnode);
+ oc->adrnode= NULL;
+ }
+ oc->nodecount= 0;
+
+ MEM_freeN(oc);
+}
+
+
+RayObject *RE_rayobject_octree_create(int ocres, int size)
+{
+ Octree *oc= MEM_callocN(sizeof(Octree), "Octree");
+ assert( RE_rayobject_isAligned(oc) ); /* RayObject API assumes real data to be 4-byte aligned */
+
+ oc->rayobj.api = &octree_api;
+
+ oc->ocres = ocres;
+
+ oc->ro_nodes = (RayFace**)MEM_callocN(sizeof(RayFace*)*size, "octree rayobject nodes");
+ oc->ro_nodes_size = size;
+ oc->ro_nodes_used = 0;
+
+
+ return RE_rayobject_unalignRayAPI((RayObject*) oc);
+}
+
+
+static void RE_rayobject_octree_add(RayObject *tree, RayObject *node)
+{
+ Octree *oc = (Octree*)tree;
+
+ assert( RE_rayobject_isRayFace(node) );
+ assert( oc->ro_nodes_used < oc->ro_nodes_size );
+ oc->ro_nodes[ oc->ro_nodes_used++ ] = (RayFace*)RE_rayobject_align(node);
+}
+
+static void octree_fill_rayface(Octree *oc, RayFace *face)
+{
+ float ocfac[3], rtf[4][3];
+ float co1[3], co2[3], co3[3], co4[3];
+ short rts[4][3];
+ short ocmin[3], ocmax[3];
+ char *ocface= oc->ocface; // front, top, size view of face, to fill in
+ int a, b, c, oc1, oc2, oc3, oc4, x, y, z, ocres2;
+
+ ocfac[0]= oc->ocfacx;
+ ocfac[1]= oc->ocfacy;
+ ocfac[2]= oc->ocfacz;
+
+ ocres2= oc->ocres*oc->ocres;
+
+ VECCOPY(co1, face->v1);
+ VECCOPY(co2, face->v2);
+ VECCOPY(co3, face->v3);
+ if(face->v4)
+ VECCOPY(co4, face->v4);
+
+ for(c=0;c<3;c++) {
+ rtf[0][c]= (co1[c]-oc->min[c])*ocfac[c] ;
+ rts[0][c]= (short)rtf[0][c];
+ rtf[1][c]= (co2[c]-oc->min[c])*ocfac[c] ;
+ rts[1][c]= (short)rtf[1][c];
+ rtf[2][c]= (co3[c]-oc->min[c])*ocfac[c] ;
+ rts[2][c]= (short)rtf[2][c];
+ if(RE_rayface_isQuad(face)) {
+ rtf[3][c]= (co4[c]-oc->min[c])*ocfac[c] ;
+ rts[3][c]= (short)rtf[3][c];
+ }
+ }
+
+ for(c=0;c<3;c++) {
+ oc1= rts[0][c];
+ oc2= rts[1][c];
+ oc3= rts[2][c];
+ if(!RE_rayface_isQuad(face)) {
+ ocmin[c]= MIN3(oc1,oc2,oc3);
+ ocmax[c]= MAX3(oc1,oc2,oc3);
+ }
+ else {
+ oc4= rts[3][c];
+ ocmin[c]= MIN4(oc1,oc2,oc3,oc4);
+ ocmax[c]= MAX4(oc1,oc2,oc3,oc4);
+ }
+ if(ocmax[c]>oc->ocres-1) ocmax[c]=oc->ocres-1;
+ if(ocmin[c]<0) ocmin[c]=0;
+ }
+
+ if(ocmin[0]==ocmax[0] && ocmin[1]==ocmax[1] && ocmin[2]==ocmax[2]) {
+ ocwrite(oc, face, RE_rayface_isQuad(face), ocmin[0], ocmin[1], ocmin[2], rtf);
+ }
+ else {
+
+ d2dda(oc, 0,1,0,1,ocface+ocres2,rts,rtf);
+ d2dda(oc, 0,1,0,2,ocface,rts,rtf);
+ d2dda(oc, 0,1,1,2,ocface+2*ocres2,rts,rtf);
+ d2dda(oc, 1,2,0,1,ocface+ocres2,rts,rtf);
+ d2dda(oc, 1,2,0,2,ocface,rts,rtf);
+ d2dda(oc, 1,2,1,2,ocface+2*ocres2,rts,rtf);
+ if(!RE_rayface_isQuad(face)) {
+ d2dda(oc, 2,0,0,1,ocface+ocres2,rts,rtf);
+ d2dda(oc, 2,0,0,2,ocface,rts,rtf);
+ d2dda(oc, 2,0,1,2,ocface+2*ocres2,rts,rtf);
+ }
+ else {
+ d2dda(oc, 2,3,0,1,ocface+ocres2,rts,rtf);
+ d2dda(oc, 2,3,0,2,ocface,rts,rtf);
+ d2dda(oc, 2,3,1,2,ocface+2*ocres2,rts,rtf);
+ d2dda(oc, 3,0,0,1,ocface+ocres2,rts,rtf);
+ d2dda(oc, 3,0,0,2,ocface,rts,rtf);
+ d2dda(oc, 3,0,1,2,ocface+2*ocres2,rts,rtf);
+ }
+ /* nothing todo with triangle..., just fills :) */
+ filltriangle(oc, 0,1,ocface+ocres2,ocmin,ocmax);
+ filltriangle(oc, 0,2,ocface,ocmin,ocmax);
+ filltriangle(oc, 1,2,ocface+2*ocres2,ocmin,ocmax);
+
+ /* init static vars here */
+ face_in_node(face, 0,0,0, rtf);
+
+ for(x=ocmin[0];x<=ocmax[0];x++) {
+ a= oc->ocres*x;
+ for(y=ocmin[1];y<=ocmax[1];y++) {
+ if(ocface[a+y+ocres2]) {
+ b= oc->ocres*y+2*ocres2;
+ for(z=ocmin[2];z<=ocmax[2];z++) {
+ if(ocface[b+z] && ocface[a+z]) {
+ if(face_in_node(NULL, x, y, z, rtf))
+ ocwrite(oc, face, RE_rayface_isQuad(face), x,y,z, rtf);
+ }
+ }
+ }
+ }
+ }
+
+ /* same loops to clear octree, doubt it can be done smarter */
+ for(x=ocmin[0];x<=ocmax[0];x++) {
+ a= oc->ocres*x;
+ for(y=ocmin[1];y<=ocmax[1];y++) {
+ /* x-y */
+ ocface[a+y+ocres2]= 0;
+
+ b= oc->ocres*y + 2*ocres2;
+ for(z=ocmin[2];z<=ocmax[2];z++) {
+ /* y-z */
+ ocface[b+z]= 0;
+ /* x-z */
+ ocface[a+z]= 0;
+ }
+ }
+ }
+ }
+}
+
+static void RE_rayobject_octree_done(RayObject *tree)
+{
+ Octree *oc = (Octree*)tree;
+ int c;
+ float t00, t01, t02;
+ int ocres2 = oc->ocres*oc->ocres;
+
+ INIT_MINMAX(oc->min, oc->max);
+
+ /* Calculate Bounding Box */
+ for(c=0; c<oc->ro_nodes_used; c++)
+ RE_rayobject_merge_bb( RE_rayobject_unalignRayFace(oc->ro_nodes[c]), oc->min, oc->max);
+
+ /* Alloc memory */
+ oc->adrbranch= MEM_callocN(sizeof(void *)*BRANCH_ARRAY, "octree branches");
+ oc->adrnode= MEM_callocN(sizeof(void *)*NODE_ARRAY, "octree nodes");
+
+ oc->adrbranch[0]=(Branch *)MEM_callocN(4096*sizeof(Branch), "makeoctree");
+
+ /* the lookup table, per face, for which nodes to fill in */
+ oc->ocface= MEM_callocN( 3*ocres2 + 8, "ocface");
+ memset(oc->ocface, 0, 3*ocres2);
+
+ for(c=0;c<3;c++) { /* octree enlarge, still needed? */
+ oc->min[c]-= 0.01f;
+ oc->max[c]+= 0.01f;
+ }
+
+ t00= oc->max[0]-oc->min[0];
+ t01= oc->max[1]-oc->min[1];
+ t02= oc->max[2]-oc->min[2];
+
+ /* this minus 0.1 is old safety... seems to be needed? */
+ oc->ocfacx= (oc->ocres-0.1)/t00;
+ oc->ocfacy= (oc->ocres-0.1)/t01;
+ oc->ocfacz= (oc->ocres-0.1)/t02;
+
+ oc->ocsize= sqrt(t00*t00+t01*t01+t02*t02); /* global, max size octree */
+
+ for(c=0; c<oc->ro_nodes_used; c++)
+ {
+ octree_fill_rayface(oc, oc->ro_nodes[c]);
+ }
+
+ MEM_freeN(oc->ocface);
+ oc->ocface = NULL;
+ MEM_freeN(oc->ro_nodes);
+ oc->ro_nodes = NULL;
+
+ printf("%f %f - %f\n", oc->min[0], oc->max[0], oc->ocfacx );
+ printf("%f %f - %f\n", oc->min[1], oc->max[1], oc->ocfacy );
+ printf("%f %f - %f\n", oc->min[2], oc->max[2], oc->ocfacz );
+}
+
+static void RE_rayobject_octree_bb(RayObject *tree, float *min, float *max)
+{
+ Octree *oc = (Octree*)tree;
+ DO_MINMAX(oc->min, min, max);
+ DO_MINMAX(oc->max, min, max);
+}
+
+/* check all faces in this node */
+static int testnode(Octree *oc, Isect *is, Node *no, OcVal ocval)
+{
+ short nr=0;
+
+ /* return on any first hit */
+ if(is->mode==RE_RAY_SHADOW) {
+
+ for(; no; no = no->next)
+ for(nr=0; nr<8; nr++)
+ {
+ RayFace *face = no->v[nr];
+ OcVal *ov = no->ov+nr;
+
+ if(!face) break;
+
+ if( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) )
+ {
+ if( RE_rayobject_intersect( RE_rayobject_unalignRayFace(face),is) )
+ return 1;
+ }
+ }
+ }
+ else
+ { /* else mirror or glass or shadowtra, return closest face */
+ int found= 0;
+
+ for(; no; no = no->next)
+ for(nr=0; nr<8; nr++)
+ {
+ RayFace *face = no->v[nr];
+ OcVal *ov = no->ov+nr;
+
+ if(!face) break;
+
+ if( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) )
+ {
+ if( RE_rayobject_intersect( RE_rayobject_unalignRayFace(face),is) )
+ found= 1;
+ }
+ }
+
+ return found;
+ }
+
+ return 0;
+}
+
+/* find the Node for the octree coord x y z */
+static Node *ocread(Octree *oc, int x, int y, int z)
+{
+ Branch *br;
+ int oc1;
+
+ x<<=2;
+ y<<=1;
+
+ br= oc->adrbranch[0];
+
+ if(oc->ocres==512) {
+ oc1= ((x & 1024)+(y & 512)+(z & 256))>>8;
+ br= br->b[oc1];
+ if(br==NULL) {
+ return NULL;
+ }
+ }
+ if(oc->ocres>=256) {
+ oc1= ((x & 512)+(y & 256)+(z & 128))>>7;
+ br= br->b[oc1];
+ if(br==NULL) {
+ return NULL;
+ }
+ }
+ if(oc->ocres>=128) {
+ oc1= ((x & 256)+(y & 128)+(z & 64))>>6;
+ br= br->b[oc1];
+ if(br==NULL) {
+ return NULL;
+ }
+ }
+
+ oc1= ((x & 128)+(y & 64)+(z & 32))>>5;
+ br= br->b[oc1];
+ if(br) {
+ oc1= ((x & 64)+(y & 32)+(z & 16))>>4;
+ br= br->b[oc1];
+ if(br) {
+ oc1= ((x & 32)+(y & 16)+(z & 8))>>3;
+ br= br->b[oc1];
+ if(br) {
+ oc1= ((x & 16)+(y & 8)+(z & 4))>>2;
+ br= br->b[oc1];
+ if(br) {
+ oc1= ((x & 8)+(y & 4)+(z & 2))>>1;
+ br= br->b[oc1];
+ if(br) {
+ oc1= ((x & 4)+(y & 2)+(z & 1));
+ return (Node *)br->b[oc1];
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int cliptest(float p, float q, float *u1, float *u2)
+{
+ float r;
+
+ if(p<0.0f) {
+ if(q<p) return 0;
+ else if(q<0.0f) {
+ r= q/p;
+ if(r>*u2) return 0;
+ else if(r>*u1) *u1=r;
+ }
+ }
+ else {
+ if(p>0.0f) {
+ if(q<0.0f) return 0;
+ else if(q<p) {
+ r= q/p;
+ if(r<*u1) return 0;
+ else if(r<*u2) *u2=r;
+ }
+ }
+ else if(q<0.0f) return 0;
+ }
+ return 1;
+}
+
+/* extensive coherence checks/storage cancels out the benefit of it, and gives errors... we
+ need better methods, sample code commented out below (ton) */
+
+/*
+
+in top: static int coh_nodes[16*16*16][6];
+in makeoctree: memset(coh_nodes, 0, sizeof(coh_nodes));
+
+static void add_coherence_test(int ocx1, int ocx2, int ocy1, int ocy2, int ocz1, int ocz2)
+{
+ short *sp;
+
+ sp= coh_nodes[ (ocx2 & 15) + 16*(ocy2 & 15) + 256*(ocz2 & 15) ];
+ sp[0]= ocx1; sp[1]= ocy1; sp[2]= ocz1;
+ sp[3]= ocx2; sp[4]= ocy2; sp[5]= ocz2;
+
+}
+
+static int do_coherence_test(int ocx1, int ocx2, int ocy1, int ocy2, int ocz1, int ocz2)
+{
+ short *sp;
+
+ sp= coh_nodes[ (ocx2 & 15) + 16*(ocy2 & 15) + 256*(ocz2 & 15) ];
+ if(sp[0]==ocx1 && sp[1]==ocy1 && sp[2]==ocz1 &&
+ sp[3]==ocx2 && sp[4]==ocy2 && sp[5]==ocz2) return 1;
+ return 0;
+}
+
+*/
+
+/* return 1: found valid intersection */
+/* starts with is->orig.face */
+static int RE_rayobject_octree_intersect(RayObject *tree, Isect *is)
+{
+ Octree *oc= (Octree*)tree;
+ Node *no;
+ OcVal ocval;
+ float vec1[3], vec2[3], start[3], end[3];
+ float u1,u2,ox1,ox2,oy1,oy2,oz1,oz2;
+ float labdao,labdax,ldx,labday,ldy,labdaz,ldz, ddalabda;
+ float olabda = 0;
+ int dx,dy,dz;
+ int xo,yo,zo,c1=0;
+ int ocx1,ocx2,ocy1, ocy2,ocz1,ocz2;
+
+ /* clip with octree */
+ if(oc->branchcount==0) return 0;
+
+ /* do this before intersect calls */
+#if 0
+ is->facecontr= NULL; /* to check shared edge */
+ is->obcontr= 0;
+ is->faceisect= is->isect= 0; /* shared edge, quad half flag */
+ is->userdata= oc->userdata;
+#endif
+
+ VECCOPY( start, is->start );
+ VECADDFAC( end, is->start, is->vec, is->labda );
+ ldx= is->vec[0]*is->labda;
+ olabda = is->labda;
+ u1= 0.0f;
+ u2= 1.0f;
+
+ /* clip with octree cube */
+ if(cliptest(-ldx, start[0]-oc->min[0], &u1,&u2)) {
+ if(cliptest(ldx, oc->max[0]-start[0], &u1,&u2)) {
+ ldy= is->vec[1]*is->labda;
+ if(cliptest(-ldy, start[1]-oc->min[1], &u1,&u2)) {
+ if(cliptest(ldy, oc->max[1]-start[1], &u1,&u2)) {
+ ldz = is->vec[2]*is->labda;
+ if(cliptest(-ldz, start[2]-oc->min[2], &u1,&u2)) {
+ if(cliptest(ldz, oc->max[2]-start[2], &u1,&u2)) {
+ c1=1;
+ if(u2<1.0f) {
+ end[0] = start[0]+u2*ldx;
+ end[1] = start[1]+u2*ldy;
+ end[2] = start[2]+u2*ldz;
+ }
+
+ if(u1>0.0f) {
+ start[0] += u1*ldx;
+ start[1] += u1*ldy;
+ start[2] += u1*ldz;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(c1==0) return 0;
+
+ /* reset static variables in ocread */
+ //ocread(oc, oc->ocres, 0, 0);
+
+ /* setup 3dda to traverse octree */
+ ox1= (start[0]-oc->min[0])*oc->ocfacx;
+ oy1= (start[1]-oc->min[1])*oc->ocfacy;
+ oz1= (start[2]-oc->min[2])*oc->ocfacz;
+ ox2= (end[0]-oc->min[0])*oc->ocfacx;
+ oy2= (end[1]-oc->min[1])*oc->ocfacy;
+ oz2= (end[2]-oc->min[2])*oc->ocfacz;
+
+ ocx1= (int)ox1;
+ ocy1= (int)oy1;
+ ocz1= (int)oz1;
+ ocx2= (int)ox2;
+ ocy2= (int)oy2;
+ ocz2= (int)oz2;
+
+ if(ocx1==ocx2 && ocy1==ocy2 && ocz1==ocz2) {
+ no= ocread(oc, ocx1, ocy1, ocz1);
+ if(no) {
+ /* exact intersection with node */
+ vec1[0]= ox1; vec1[1]= oy1; vec1[2]= oz1;
+ vec2[0]= ox2; vec2[1]= oy2; vec2[2]= oz2;
+ calc_ocval_ray(&ocval, (float)ocx1, (float)ocy1, (float)ocz1, vec1, vec2);
+ if( testnode(oc, is, no, ocval) ) return 1;
+ }
+ }
+ else {
+ int found = 0;
+ //static int coh_ocx1,coh_ocx2,coh_ocy1, coh_ocy2,coh_ocz1,coh_ocz2;
+ float dox, doy, doz;
+ int eqval;
+
+ /* calc labda en ld */
+ dox= ox1-ox2;
+ doy= oy1-oy2;
+ doz= oz1-oz2;
+
+ if(dox<-FLT_EPSILON) {
+ ldx= -1.0f/dox;
+ labdax= (ocx1-ox1+1.0f)*ldx;
+ dx= 1;
+ } else if(dox>FLT_EPSILON) {
+ ldx= 1.0f/dox;
+ labdax= (ox1-ocx1)*ldx;
+ dx= -1;
+ } else {
+ labdax=1.0f;
+ ldx=0;
+ dx= 0;
+ }
+
+ if(doy<-FLT_EPSILON) {
+ ldy= -1.0f/doy;
+ labday= (ocy1-oy1+1.0f)*ldy;
+ dy= 1;
+ } else if(doy>FLT_EPSILON) {
+ ldy= 1.0f/doy;
+ labday= (oy1-ocy1)*ldy;
+ dy= -1;
+ } else {
+ labday=1.0f;
+ ldy=0;
+ dy= 0;
+ }
+
+ if(doz<-FLT_EPSILON) {
+ ldz= -1.0f/doz;
+ labdaz= (ocz1-oz1+1.0f)*ldz;
+ dz= 1;
+ } else if(doz>FLT_EPSILON) {
+ ldz= 1.0f/doz;
+ labdaz= (oz1-ocz1)*ldz;
+ dz= -1;
+ } else {
+ labdaz=1.0f;
+ ldz=0;
+ dz= 0;
+ }
+
+ xo=ocx1; yo=ocy1; zo=ocz1;
+ labdao= ddalabda= MIN3(labdax,labday,labdaz);
+
+ vec2[0]= ox1;
+ vec2[1]= oy1;
+ vec2[2]= oz1;
+
+ /* this loop has been constructed to make sure the first and last node of ray
+ are always included, even when ddalabda==1.0f or larger */
+
+ while(TRUE) {
+
+ no= ocread(oc, xo, yo, zo);
+ if(no) {
+
+ /* calculate ray intersection with octree node */
+ VECCOPY(vec1, vec2);
+ // dox,y,z is negative
+ vec2[0]= ox1-ddalabda*dox;
+ vec2[1]= oy1-ddalabda*doy;
+ vec2[2]= oz1-ddalabda*doz;
+ calc_ocval_ray(&ocval, (float)xo, (float)yo, (float)zo, vec1, vec2);
+
+ //is->labda = (u1+ddalabda*(u2-u1))*olabda;
+ if( testnode(oc, is, no, ocval) )
+ found = 1;
+
+ if(is->labda < (u1+ddalabda*(u2-u1))*olabda)
+ return found;
+ }
+
+
+ labdao= ddalabda;
+
+ /* traversing ocree nodes need careful detection of smallest values, with proper
+ exceptions for equal labdas */
+ eqval= (labdax==labday);
+ if(labday==labdaz) eqval += 2;
+ if(labdax==labdaz) eqval += 4;
+
+ if(eqval) { // only 4 cases exist!
+ if(eqval==7) { // x=y=z
+ xo+=dx; labdax+=ldx;
+ yo+=dy; labday+=ldy;
+ zo+=dz; labdaz+=ldz;
+ }
+ else if(eqval==1) { // x=y
+ if(labday < labdaz) {
+ xo+=dx; labdax+=ldx;
+ yo+=dy; labday+=ldy;
+ }
+ else {
+ zo+=dz; labdaz+=ldz;
+ }
+ }
+ else if(eqval==2) { // y=z
+ if(labdax < labday) {
+ xo+=dx; labdax+=ldx;
+ }
+ else {
+ yo+=dy; labday+=ldy;
+ zo+=dz; labdaz+=ldz;
+ }
+ }
+ else { // x=z
+ if(labday < labdax) {
+ yo+=dy; labday+=ldy;
+ }
+ else {
+ xo+=dx; labdax+=ldx;
+ zo+=dz; labdaz+=ldz;
+ }
+ }
+ }
+ else { // all three different, just three cases exist
+ eqval= (labdax<labday);
+ if(labday<labdaz) eqval += 2;
+ if(labdax<labdaz) eqval += 4;
+
+ if(eqval==7 || eqval==5) { // x smallest
+ xo+=dx; labdax+=ldx;
+ }
+ else if(eqval==2 || eqval==6) { // y smallest
+ yo+=dy; labday+=ldy;
+ }
+ else { // z smallest
+ zo+=dz; labdaz+=ldz;
+ }
+
+ }
+
+ ddalabda=MIN3(labdax,labday,labdaz);
+ if(ddalabda==labdao) break;
+ /* to make sure the last node is always checked */
+ if(labdao>=1.0f) break;
+ }
+ }
+
+ /* reached end, no intersections found */
+ return 0;
+}
+
+
+
diff --git a/source/blender/render/intern/source/rayobject_raycounter.c b/source/blender/render/intern/source/rayobject_raycounter.c
new file mode 100644
index 00000000000..4e5a5ddb844
--- /dev/null
+++ b/source/blender/render/intern/source/rayobject_raycounter.c
@@ -0,0 +1,87 @@
+/**
+ * $Id: rayobject_raycounter.c 23649 2009-10-06 02:56:11Z jaguarandi $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include "rayobject.h"
+#include "raycounter.h"
+
+#ifdef RE_RAYCOUNTER
+
+void RE_RC_INFO(RayCounter *info)
+{
+ printf("----------- Raycast counter --------\n");
+ printf("Rays total: %llu\n", info->raycast.test );
+ printf("Rays hit: %llu\n", info->raycast.hit );
+ printf("\n");
+ printf("BB tests: %llu\n", info->bb.test );
+ printf("BB hits: %llu\n", info->bb.hit );
+ printf("\n");
+ printf("SIMD BB tests: %llu\n", info->simd_bb.test );
+ printf("SIMD BB hits: %llu\n", info->simd_bb.hit );
+ printf("\n");
+ printf("Primitives tests: %llu\n", info->faces.test );
+ printf("Primitives hits: %llu\n", info->faces.hit );
+ printf("------------------------------------\n");
+ printf("Shadow last-hit tests per ray: %f\n", info->rayshadow_last_hit.test / ((float)info->raycast.test) );
+ printf("Shadow last-hit hits per ray: %f\n", info->rayshadow_last_hit.hit / ((float)info->raycast.test) );
+ printf("\n");
+ printf("Hint tests per ray: %f\n", info->raytrace_hint.test / ((float)info->raycast.test) );
+ printf("Hint hits per ray: %f\n", info->raytrace_hint.hit / ((float)info->raycast.test) );
+ printf("\n");
+ printf("BB tests per ray: %f\n", info->bb.test / ((float)info->raycast.test) );
+ printf("BB hits per ray: %f\n", info->bb.hit / ((float)info->raycast.test) );
+ printf("\n");
+ printf("SIMD tests per ray: %f\n", info->simd_bb.test / ((float)info->raycast.test) );
+ printf("SIMD hits per ray: %f\n", info->simd_bb.hit / ((float)info->raycast.test) );
+ printf("\n");
+ printf("Primitives tests per ray: %f\n", info->faces.test / ((float)info->raycast.test) );
+ printf("Primitives hits per ray: %f\n", info->faces.hit / ((float)info->raycast.test) );
+ printf("------------------------------------\n");
+}
+
+void RE_RC_MERGE(RayCounter *dest, RayCounter *tmp)
+{
+ dest->faces.test += tmp->faces.test;
+ dest->faces.hit += tmp->faces.hit;
+
+ dest->bb.test += tmp->bb.test;
+ dest->bb.hit += tmp->bb.hit;
+
+ dest->simd_bb.test += tmp->simd_bb.test;
+ dest->simd_bb.hit += tmp->simd_bb.hit;
+
+ dest->raycast.test += tmp->raycast.test;
+ dest->raycast.hit += tmp->raycast.hit;
+
+ dest->rayshadow_last_hit.test += tmp->rayshadow_last_hit.test;
+ dest->rayshadow_last_hit.hit += tmp->rayshadow_last_hit.hit;
+
+ dest->raytrace_hint.test += tmp->raytrace_hint.test;
+ dest->raytrace_hint.hit += tmp->raytrace_hint.hit;
+}
+
+#endif
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index 684f02d222f..1dec0d2a6b2 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -379,25 +379,6 @@ void renderspothalo(ShadeInput *shi, float *col, float alpha)
/* ---------------- shaders ----------------------- */
-static double Normalize_d(double *n)
-{
- double d;
-
- d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
-
- if(d>0.00000000000000001) {
- d= sqrt(d);
-
- n[0]/=d;
- n[1]/=d;
- n[2]/=d;
- } else {
- n[0]=n[1]=n[2]= 0.0;
- d= 0.0;
- }
- return d;
-}
-
/* mix of 'real' fresnel and allowing control. grad defines blending gradient */
float fresnel_fac(float *view, float *vn, float grad, float fac)
{
@@ -436,10 +417,10 @@ static float area_lamp_energy(float (*area)[3], float *co, float *vn)
VECSUB(vec[2], co, area[2]);
VECSUB(vec[3], co, area[3]);
- Normalize_d(vec[0]);
- Normalize_d(vec[1]);
- Normalize_d(vec[2]);
- Normalize_d(vec[3]);
+ normalize_dv3(vec[0]);
+ normalize_dv3(vec[1]);
+ normalize_dv3(vec[2]);
+ normalize_dv3(vec[3]);
/* cross product */
CROSS(cross[0], vec[0], vec[1]);
@@ -447,10 +428,10 @@ static float area_lamp_energy(float (*area)[3], float *co, float *vn)
CROSS(cross[2], vec[2], vec[3]);
CROSS(cross[3], vec[3], vec[0]);
- Normalize_d(cross[0]);
- Normalize_d(cross[1]);
- Normalize_d(cross[2]);
- Normalize_d(cross[3]);
+ normalize_dv3(cross[0]);
+ normalize_dv3(cross[1]);
+ normalize_dv3(cross[2]);
+ normalize_dv3(cross[3]);
/* angles */
rad[0]= vec[0][0]*vec[1][0]+ vec[0][1]*vec[1][1]+ vec[0][2]*vec[1][2];
diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c
index 847db912025..67da11f4988 100644
--- a/source/blender/render/intern/source/strand.c
+++ b/source/blender/render/intern/source/strand.c
@@ -970,7 +970,7 @@ StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm,
int a, totvert, totface;
totvert= dm->getNumVerts(dm);
- totface= dm->getNumFaces(dm);
+ totface= dm->getNumTessFaces(dm);
for(mesh=re->strandsurface.first; mesh; mesh=mesh->next)
if(mesh->obr.ob == obr->ob && mesh->obr.par == obr->par
@@ -1004,7 +1004,7 @@ StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm,
mul_m4_v3(mat, co[a]);
}
- mface= dm->getFaceArray(dm);
+ mface= dm->getTessFaceArray(dm);
for(a=0; a<mesh->totface; a++, mface++) {
mesh->face[a][0]= mface->v1;
mesh->face[a][1]= mface->v2;
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 2be62d5a8b2..5726ce47df7 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -28,7 +28,7 @@ set(INC
.
../nodes
../gpu
- ../blenfont
+ ../blenfont ../bmesh
../blenlib
../makesdna
../makesrna
diff --git a/source/blender/windowmanager/SConscript b/source/blender/windowmanager/SConscript
index cbaf74ddc10..ed0cce49489 100644
--- a/source/blender/windowmanager/SConscript
+++ b/source/blender/windowmanager/SConscript
@@ -9,7 +9,7 @@ sources = env.Glob('intern/*.c')
incs = '. ../editors/include ../python ../makesdna ../blenlib ../blenkernel'
incs += ' ../nodes ../imbuf ../blenloader ../render/extern/include'
incs += ' ../radiosity/extern/include ../../kernel/gen_system'
-incs += ' ../makesrna ../gpu ../blenfont'
+incs += ' ../makesrna ../gpu ../blenfont ../bmesh'
incs += ' #/intern/guardedalloc #/intern/memutil #/intern/ghost'
incs += ' #/intern/elbeem #/extern/glew/include'
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 82ef6a1b80e..a0202d2b4cc 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -201,6 +201,7 @@ typedef struct wmNotifier {
#define ND_TRANSFORM_DONE (18<<16)
#define ND_WORLD (92<<16)
#define ND_LAYER_CONTENT (101<<16)
+#define ND_LAYER_CONTENT (101<<16)
/* NC_OBJECT Object */
#define ND_TRANSFORM (18<<16)
@@ -361,7 +362,7 @@ typedef struct wmEvent {
short customdatafree;
int pad2;
void *customdata; /* ascii, unicode, mouse coords, angles, vectors, dragdrop info */
-
+ double delay;
} wmEvent;
/* ************** custom wmEvent data ************** */
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index fab3f05ca01..c15916cf3d4 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -1720,9 +1720,12 @@ void wm_event_do_handlers(bContext *C)
}
}
+ if (win->lasttime == 0.0)
+ win->lasttime = PIL_check_seconds_timer();
+
while( (event= win->queue.first) ) {
int action = WM_HANDLER_CONTINUE;
-
+
if((G.f & G_DEBUG) && event && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))
printf("pass on evt %d val %d\n", event->type, event->val);
@@ -1859,8 +1862,10 @@ void wm_event_do_handlers(bContext *C)
BLI_remlink(&win->queue, event);
wm_event_free(event);
+ win->lasttime = PIL_check_seconds_timer();
}
+
/* only add mousemove when queue was read entirely */
if(win->addmousemove && win->eventstate) {
wmEvent tevent= *(win->eventstate);
@@ -2286,7 +2291,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
switch (type) {
/* mouse move */
case GHOST_kEventCursorMove: {
- if(win->active) {
+ if(win->active) {
+
GHOST_TEventCursorData *cd= customdata;
wmEvent *lastevent= win->queue.last;
@@ -2347,6 +2353,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
event.type= MOUSEPAN;
break;
}
+
#if defined(__APPLE__) && defined(GHOST_COCOA)
//Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
event.x= evt->x = pd->x;
@@ -2372,7 +2379,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
case GHOST_kEventButtonUp: {
GHOST_TEventButtonData *bd= customdata;
event.val= (type==GHOST_kEventButtonDown) ? KM_PRESS:KM_RELEASE; /* Note!, this starts as 0/1 but later is converted to KM_PRESS/KM_RELEASE by tweak */
-
+
if (bd->button == GHOST_kButtonMaskLeft)
event.type= LEFTMOUSE;
else if (bd->button == GHOST_kButtonMaskRight)
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index a797b461025..34a6359b6dc 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -63,6 +63,7 @@
#include "BKE_material.h" /* clear_matcopybuf */
#include "BLI_blenlib.h"
+#include "BLI_cellalloc.h"
#include "RE_pipeline.h" /* RE_ free stuff */
@@ -457,8 +458,11 @@ void WM_exit(bContext *C)
GHOST_DisposeSystemPaths();
- if(MEM_get_memory_blocks_in_use()!=0) {
- printf("Error Totblock: %d\n", MEM_get_memory_blocks_in_use());
+ if(MEM_get_memory_blocks_in_use()!=0 || BLI_cellalloc_get_totblock()!=0) {
+ printf("Error Totblock: %d\n",
+ BLI_cellalloc_get_totblock()+MEM_get_memory_blocks_in_use());
+ BLI_cellalloc_printleaks();
+ BLI_cellalloc_destroy();
MEM_printmemlist();
}
wm_autosave_delete();
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index cda771d7eb6..12862f559d4 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -2221,15 +2221,15 @@ int WM_gesture_circle_modal(bContext *C, wmOperator *op, wmEvent *event)
int sx, sy;
if(event->type== MOUSEMOVE) {
- wm_subwindow_getorigin(CTX_wm_window(C), gesture->swinid, &sx, &sy);
+ wm_subwindow_getorigin(CTX_wm_window(C), gesture->swinid, &sx, &sy);
- rect->xmin= event->x - sx;
- rect->ymin= event->y - sy;
+ rect->xmin= event->x - sx;
+ rect->ymin= event->y - sy;
- wm_gesture_tag_redraw(C);
+ wm_gesture_tag_redraw(C);
- if(gesture->mode)
- gesture_circle_apply(C, op);
+ if(gesture->mode)
+ gesture_circle_apply(C, op);
}
else if (event->type==EVT_MODAL_MAP) {
switch (event->val) {
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index be33264cafd..44200294b6c 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -74,7 +74,7 @@
#include "GPU_extensions.h"
/* the global to talk to ghost */
-static GHOST_SystemHandle g_system= NULL;
+GHOST_SystemHandle g_system= NULL;
/* set by commandline */
static int prefsizx= 0, prefsizy= 0, prefstax= 0, prefstay= 0, initialstate= GHOST_kWindowStateNormal;
@@ -905,7 +905,9 @@ static int wm_window_timer(const bContext *C)
void wm_window_process_events(const bContext *C)
{
- int hasevent= GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */
+ int hasevent= 0;
+
+ hasevent = GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */
if(hasevent)
GHOST_DispatchEvents(g_system);