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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>2012-02-21 05:40:04 +0400
committerTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>2012-02-21 05:40:04 +0400
commit69289c978eace478bf992517473960d540895815 (patch)
tree493d2c9bec32f761468b082fbbb015c748b71685
parent5f093d6a5867a365900158fcca71296852787aac (diff)
parentbe674afdadaa1ab966147755e224e8bbda6807db (diff)
Merged changes in the trunk up to revision 44266 (including BMesh).
Freestyle edge/face marks were ported to BMesh. Conflicts resolved: source/blender/editors/mesh/editface.c source/blender/editors/space_view3d/drawobject.c source/blender/makesdna/DNA_meshdata_types.h source/blender/blenkernel/intern/editderivedmesh.c
-rw-r--r--intern/cycles/blender/blender_mesh.cpp8
-rw-r--r--intern/dualcon/intern/MemoryAllocator.h12
-rw-r--r--intern/dualcon/intern/octree.cpp4259
-rw-r--r--intern/dualcon/intern/octree.h1551
-rw-r--r--intern/smoke/intern/FLUID_3D.cpp4
-rw-r--r--release/scripts/modules/bpy_types.py39
-rw-r--r--release/scripts/startup/bl_operators/mesh.py44
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_follow_active.py20
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_lightmap.py25
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_smart_project.py13
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py12
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py31
-rw-r--r--source/blender/CMakeLists.txt1
-rw-r--r--source/blender/SConscript1
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h228
-rw-r--r--source/blender/blenkernel/BKE_armature.h1
-rw-r--r--source/blender/blenkernel/BKE_blender.h1
-rw-r--r--source/blender/blenkernel/BKE_bmesh.h16
-rw-r--r--source/blender/blenkernel/BKE_cdderivedmesh.h55
-rw-r--r--source/blender/blenkernel/BKE_customdata.h32
-rw-r--r--source/blender/blenkernel/BKE_key.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh.h125
-rw-r--r--source/blender/blenkernel/BKE_modifier.h7
-rw-r--r--source/blender/blenkernel/BKE_multires.h8
-rw-r--r--source/blender/blenkernel/BKE_paint.h7
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h11
-rw-r--r--source/blender/blenkernel/BKE_tessmesh.h94
-rw-r--r--source/blender/blenkernel/CMakeLists.txt9
-rw-r--r--source/blender/blenkernel/SConscript1
-rw-r--r--source/blender/blenkernel/intern/BME_Customdata.c198
-rw-r--r--source/blender/blenkernel/intern/BME_conversions.c650
-rw-r--r--source/blender/blenkernel/intern/BME_eulers.c973
-rw-r--r--source/blender/blenkernel/intern/BME_mesh.c285
-rw-r--r--source/blender/blenkernel/intern/BME_structure.c628
-rw-r--r--source/blender/blenkernel/intern/BME_tools.c1343
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c822
-rw-r--r--source/blender/blenkernel/intern/anim.c95
-rw-r--r--source/blender/blenkernel/intern/armature.c14
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c101
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c1063
-rw-r--r--source/blender/blenkernel/intern/cloth.c9
-rw-r--r--source/blender/blenkernel/intern/collision.c1
-rw-r--r--source/blender/blenkernel/intern/constraint.c10
-rw-r--r--source/blender/blenkernel/intern/customdata.c387
-rw-r--r--source/blender/blenkernel/intern/displist.c9
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c165
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c1706
-rw-r--r--source/blender/blenkernel/intern/effect.c2
-rw-r--r--source/blender/blenkernel/intern/fluidsim.c4
-rw-r--r--source/blender/blenkernel/intern/image.c41
-rw-r--r--source/blender/blenkernel/intern/key.c73
-rw-r--r--source/blender/blenkernel/intern/library.c2
-rw-r--r--source/blender/blenkernel/intern/mesh.c1495
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c76
-rw-r--r--source/blender/blenkernel/intern/modifiers_bmesh.c171
-rw-r--r--source/blender/blenkernel/intern/multires.c371
-rw-r--r--source/blender/blenkernel/intern/navmesh_conversion.c4
-rw-r--r--source/blender/blenkernel/intern/object.c47
-rw-r--r--source/blender/blenkernel/intern/particle.c60
-rw-r--r--source/blender/blenkernel/intern/particle_system.c45
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c2
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c5
-rw-r--r--source/blender/blenkernel/intern/smoke.c55
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c885
-rw-r--r--source/blender/blenlib/BLI_array.h6
-rw-r--r--source/blender/blenlib/BLI_scanfill.h6
-rwxr-xr-xsource/blender/blenlib/BLI_smallhash.h73
-rwxr-xr-xsource/blender/blenlib/BLI_sparsemap.h81
-rw-r--r--source/blender/blenlib/BLI_threads.h1
-rw-r--r--source/blender/blenlib/CMakeLists.txt3
-rw-r--r--source/blender/blenlib/SConscript2
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c2
-rw-r--r--source/blender/blenlib/intern/pbvh.c2
-rw-r--r--source/blender/blenlib/intern/scanfill.c190
-rw-r--r--source/blender/blenlib/intern/smallhash.c281
-rw-r--r--source/blender/blenlib/intern/threads.c5
-rw-r--r--source/blender/blenloader/SConscript2
-rw-r--r--source/blender/blenloader/intern/readfile.c92
-rw-r--r--source/blender/blenloader/intern/writefile.c130
-rw-r--r--source/blender/blenpluginapi/SConscript2
-rw-r--r--source/blender/bmesh/CMakeLists.txt137
-rw-r--r--source/blender/bmesh/SConscript40
-rw-r--r--source/blender/bmesh/bmesh.h382
-rw-r--r--source/blender/bmesh/bmesh_class.h190
-rw-r--r--source/blender/bmesh/bmesh_error.h72
-rw-r--r--source/blender/bmesh/bmesh_iterators.h136
-rw-r--r--source/blender/bmesh/bmesh_marking.h75
-rw-r--r--source/blender/bmesh/bmesh_operator_api.h555
-rw-r--r--source/blender/bmesh/bmesh_operators.h107
-rw-r--r--source/blender/bmesh/bmesh_queries.h123
-rw-r--r--source/blender/bmesh/bmesh_walkers.h139
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c777
-rw-r--r--source/blender/bmesh/intern/bmesh_inline.c71
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c984
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c417
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators_inline.c160
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c910
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c625
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c769
-rw-r--r--source/blender/bmesh/intern/bmesh_newcore.c2024
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c1145
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c1376
-rw-r--r--source/blender/bmesh/intern/bmesh_operators_private.h106
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c1069
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h98
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c658
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.c1103
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.h106
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.c266
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_impl.c911
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_private.h89
-rw-r--r--source/blender/bmesh/operators/bmo_bevel.c881
-rw-r--r--source/blender/bmesh/operators/bmo_connect.c414
-rw-r--r--source/blender/bmesh/operators/bmo_create.c1412
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c559
-rw-r--r--source/blender/bmesh/operators/bmo_dupe.c512
-rw-r--r--source/blender/bmesh/operators/bmo_edgesplit.c426
-rw-r--r--source/blender/bmesh/operators/bmo_extrude.c591
-rw-r--r--source/blender/bmesh/operators/bmo_join_triangles.c373
-rw-r--r--source/blender/bmesh/operators/bmo_mesh_conv.c906
-rw-r--r--source/blender/bmesh/operators/bmo_mirror.c126
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c734
-rw-r--r--source/blender/bmesh/operators/bmo_removedoubles.c590
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide.c1104
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide.h66
-rw-r--r--source/blender/bmesh/operators/bmo_triangulate.c219
-rw-r--r--source/blender/bmesh/operators/bmo_utils.c1311
-rw-r--r--source/blender/bmesh/tools/BME_bevel.c1011
-rw-r--r--source/blender/collada/ArmatureExporter.cpp183
-rw-r--r--source/blender/collada/ArmatureExporter.h19
-rw-r--r--source/blender/collada/GeometryExporter.cpp4
-rw-r--r--source/blender/collada/MeshImporter.cpp7
-rw-r--r--source/blender/collada/SceneExporter.cpp49
-rw-r--r--source/blender/collada/SceneExporter.h2
-rw-r--r--source/blender/collada/TransformWriter.cpp30
-rw-r--r--source/blender/editors/animation/SConscript2
-rw-r--r--source/blender/editors/armature/SConscript1
-rw-r--r--source/blender/editors/armature/editarmature.c4
-rw-r--r--source/blender/editors/armature/meshlaplacian.c52
-rw-r--r--source/blender/editors/armature/reeb.c13
-rw-r--r--source/blender/editors/curve/SConscript2
-rw-r--r--source/blender/editors/curve/editcurve.c18
-rw-r--r--source/blender/editors/curve/editfont.c4
-rw-r--r--source/blender/editors/datafiles/SConscript2
-rw-r--r--source/blender/editors/gpencil/SConscript2
-rw-r--r--source/blender/editors/include/ED_mesh.h247
-rw-r--r--source/blender/editors/include/ED_object.h4
-rw-r--r--source/blender/editors/include/ED_util.h8
-rw-r--r--source/blender/editors/include/ED_uvedit.h27
-rw-r--r--source/blender/editors/include/ED_view3d.h20
-rw-r--r--source/blender/editors/interface/SConscript2
-rw-r--r--source/blender/editors/interface/interface_templates.c2
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt14
-rw-r--r--source/blender/editors/mesh/SConscript1
-rw-r--r--source/blender/editors/mesh/bmesh_select.c2767
-rw-r--r--source/blender/editors/mesh/bmesh_selecthistory.c69
-rw-r--r--source/blender/editors/mesh/bmesh_tools.c4690
-rw-r--r--source/blender/editors/mesh/bmesh_utils.c1139
-rw-r--r--source/blender/editors/mesh/editface.c695
-rw-r--r--source/blender/editors/mesh/editmesh.c2074
-rw-r--r--source/blender/editors/mesh/editmesh_add.c1656
-rw-r--r--source/blender/editors/mesh/editmesh_bvh.c418
-rw-r--r--source/blender/editors/mesh/editmesh_bvh.h67
-rw-r--r--source/blender/editors/mesh/editmesh_lib.c3070
-rw-r--r--source/blender/editors/mesh/editmesh_loop.c427
-rw-r--r--source/blender/editors/mesh/editmesh_mods.c4527
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c6832
-rwxr-xr-xsource/blender/editors/mesh/knifetool.c2314
-rw-r--r--source/blender/editors/mesh/loopcut.c331
-rw-r--r--source/blender/editors/mesh/mesh_data.c417
-rw-r--r--source/blender/editors/mesh/mesh_intern.h133
-rw-r--r--source/blender/editors/mesh/mesh_navmesh.c111
-rw-r--r--source/blender/editors/mesh/mesh_ops.c47
-rw-r--r--source/blender/editors/mesh/meshtools.c199
-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.c28
-rw-r--r--source/blender/editors/object/object_bake.c31
-rw-r--r--source/blender/editors/object/object_edit.c20
-rw-r--r--source/blender/editors/object/object_hook.c55
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_lattice.c4
-rw-r--r--source/blender/editors/object/object_modifier.c106
-rw-r--r--source/blender/editors/object/object_ops.c3
-rw-r--r--source/blender/editors/object/object_relations.c24
-rw-r--r--source/blender/editors/object/object_transform.c57
-rw-r--r--source/blender/editors/object/object_vgroup.c184
-rw-r--r--source/blender/editors/physics/SConscript2
-rw-r--r--source/blender/editors/physics/particle_edit.c14
-rw-r--r--source/blender/editors/physics/particle_object.c6
-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.c18
-rw-r--r--source/blender/editors/screen/CMakeLists.txt1
-rw-r--r--source/blender/editors/screen/SConscript2
-rw-r--r--source/blender/editors/screen/screen_ops.c12
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt1
-rw-r--r--source/blender/editors/sculpt_paint/SConscript2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c15
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c8
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c508
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c81
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c95
-rw-r--r--source/blender/editors/space_api/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_api/SConscript2
-rw-r--r--source/blender/editors/space_buttons/SConscript2
-rw-r--r--source/blender/editors/space_clip/clip_ops.c3
-rw-r--r--source/blender/editors/space_image/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_image/SConscript2
-rw-r--r--source/blender/editors/space_image/space_image.c23
-rw-r--r--source/blender/editors/space_info/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_info/SConscript2
-rw-r--r--source/blender/editors/space_info/info_stats.c29
-rw-r--r--source/blender/editors/space_node/SConscript2
-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/drawmesh.c217
-rw-r--r--source/blender/editors/space_view3d/drawobject.c679
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c216
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c25
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c184
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c115
-rw-r--r--source/blender/editors/space_view3d/view3d_toolbar.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c2
-rw-r--r--source/blender/editors/transform/CMakeLists.txt1
-rw-r--r--source/blender/editors/transform/SConscript2
-rw-r--r--source/blender/editors/transform/transform.c991
-rw-r--r--source/blender/editors/transform/transform.h28
-rw-r--r--source/blender/editors/transform/transform_conversions.c452
-rw-r--r--source/blender/editors/transform/transform_generics.c23
-rw-r--r--source/blender/editors/transform/transform_manipulator.c88
-rw-r--r--source/blender/editors/transform/transform_orientations.c105
-rw-r--r--source/blender/editors/transform/transform_snap.c73
-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.c77
-rw-r--r--source/blender/editors/util/ed_util.c8
-rw-r--r--source/blender/editors/util/editmode_undo.c22
-rw-r--r--source/blender/editors/util/undo.c15
-rw-r--r--source/blender/editors/uvedit/CMakeLists.txt1
-rw-r--r--source/blender/editors/uvedit/SConscript2
-rw-r--r--source/blender/editors/uvedit/uvedit_buttons.c77
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c506
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h39
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c2357
-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_smart_stitch.c434
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c735
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c42
-rw-r--r--source/blender/gpu/intern/gpu_material.c2
-rw-r--r--source/blender/imbuf/intern/indexer.c9
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h28
-rw-r--r--source/blender/makesdna/DNA_defs.h3
-rw-r--r--source/blender/makesdna/DNA_key_types.h7
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h22
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h46
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h9
-rw-r--r--source/blender/makesdna/DNA_vec_types.h4
-rw-r--r--source/blender/makesdna/intern/SConscript2
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c3
-rw-r--r--source/blender/makesrna/RNA_access.h5
-rw-r--r--source/blender/makesrna/SConscript3
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt1
-rw-r--r--source/blender/makesrna/intern/SConscript2
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c1624
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c17
-rw-r--r--source/blender/makesrna/intern/rna_mesh_utils.h111
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c42
-rw-r--r--source/blender/makesrna/intern/rna_object.c9
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c10
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c2
-rw-r--r--source/blender/modifiers/CMakeLists.txt2
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h1
-rw-r--r--source/blender/modifiers/SConscript2
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c8
-rw-r--r--source/blender/modifiers/intern/MOD_array.c645
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c88
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c10
-rw-r--r--source/blender/modifiers/intern/MOD_boolean_util.c35
-rw-r--r--source/blender/modifiers/intern/MOD_build.c158
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c2
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c4
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c4
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c26
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c2
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c1259
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c47
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c55
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c2
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c4
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c113
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c10
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c353
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c4
-rw-r--r--source/blender/modifiers/intern/MOD_ngoninterp.c331
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c97
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c20
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c6
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c31
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c173
-rw-r--r--source/blender/modifiers/intern/MOD_shapekey.c4
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c2
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c2
-rw-r--r--source/blender/modifiers/intern/MOD_smooth.c2
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c317
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c2
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c2
-rw-r--r--source/blender/modifiers/intern/MOD_util.c33
-rw-r--r--source/blender/modifiers/intern/MOD_util.h4
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c71
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c4
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c2
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c2
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c2
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c6
-rw-r--r--source/blender/render/SConscript2
-rw-r--r--source/blender/render/intern/source/convertblender.c30
-rw-r--r--source/blender/render/intern/source/pixelshading.c2
-rw-r--r--source/blender/render/intern/source/render_texture.c2
-rw-r--r--source/blender/render/intern/source/shadeoutput.c2
-rw-r--r--source/blender/render/intern/source/strand.c4
-rw-r--r--source/blender/windowmanager/SConscript2
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c16
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c76
-rw-r--r--source/blender/windowmanager/intern/wm_files.c26
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c5
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c20
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c16
-rw-r--r--source/blender/windowmanager/intern/wm_window.c8
-rw-r--r--source/blenderplayer/CMakeLists.txt2
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c36
-rw-r--r--source/creator/CMakeLists.txt1
-rw-r--r--source/creator/creator.c2
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp2
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.cpp10
-rw-r--r--source/gameengine/GamePlayer/common/GPC_Canvas.cpp5
-rw-r--r--source/gameengine/Ketsji/KX_NavMeshObject.cpp2
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsController.cpp16
345 files changed, 57786 insertions, 36155 deletions
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index bc43809e46c..c7844782e78 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -115,9 +115,9 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
/* create vertex color attributes */
{
- BL::Mesh::vertex_colors_iterator l;
+ BL::Mesh::tessface_vertex_colors_iterator l;
- for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) {
+ for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) {
if(!mesh_need_attribute(scene, mesh, ustring(l->name().c_str())))
continue;
@@ -147,9 +147,9 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
/* create uv map attributes */
{
- BL::Mesh::uv_textures_iterator l;
+ BL::Mesh::tessface_uv_textures_iterator l;
- for(b_mesh.uv_textures.begin(l); l != b_mesh.uv_textures.end(); ++l) {
+ for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
Attribute::Standard std = (l->active_render())? Attribute::STD_UV: Attribute::STD_NONE;
ustring name = ustring(l->name().c_str());
diff --git a/intern/dualcon/intern/MemoryAllocator.h b/intern/dualcon/intern/MemoryAllocator.h
index de9dca175a4..a1be0978409 100644
--- a/intern/dualcon/intern/MemoryAllocator.h
+++ b/intern/dualcon/intern/MemoryAllocator.h
@@ -43,8 +43,8 @@
class VirtualMemoryAllocator
{
public:
- virtual UCHAR * allocate( ) = 0 ;
- virtual void deallocate( UCHAR * obj ) = 0 ;
+ virtual void * allocate( ) = 0 ;
+ virtual void deallocate( void * obj ) = 0 ;
virtual void destroy( ) = 0 ;
virtual void printInfo( ) = 0 ;
@@ -161,7 +161,7 @@ public:
/**
* Allocation method
*/
- UCHAR * allocate ( )
+ void * allocate ( )
{
if ( available == 0 )
{
@@ -170,13 +170,13 @@ public:
// printf("Allocating %d\n", header[ allocated ]) ;
available -- ;
- return stack[ available >> HEAP_BASE ][ available & HEAP_MASK ] ;
+ return (void*)stack[ available >> HEAP_BASE ][ available & HEAP_MASK ] ;
}
/**
* De-allocation method
*/
- void deallocate ( UCHAR * obj )
+ void deallocate ( void * obj )
{
if ( available == stacksize )
{
@@ -184,7 +184,7 @@ public:
}
// printf("De-allocating %d\n", ( obj - data ) / N ) ;
- stack[ available >> HEAP_BASE ][ available & HEAP_MASK ] = obj ;
+ stack[ available >> HEAP_BASE ][ available & HEAP_MASK ] = (UCHAR*)obj ;
available ++ ;
// printf("%d %d\n", allocated, header[ allocated ]) ;
}
diff --git a/intern/dualcon/intern/octree.cpp b/intern/dualcon/intern/octree.cpp
index 90dbf5376a2..38b130f979b 100644
--- a/intern/dualcon/intern/octree.cpp
+++ b/intern/dualcon/intern/octree.cpp
@@ -15,7 +15,7 @@
* 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): Tao Ju
+ * Contributor(s): Tao Ju, Nicholas Bishop
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -42,12 +42,12 @@
#define dc_printf(...) do {} while(0)
#endif
-Octree::Octree( ModelReader* mr,
+Octree::Octree(ModelReader* mr,
DualConAllocOutput alloc_output_func,
DualConAddVert add_vert_func,
DualConAddQuad add_quad_func,
DualConFlags flags, DualConMode dualcon_mode, int depth,
- float threshold, float sharpness )
+ float threshold, float sharpness)
: use_flood_fill(flags & DUALCON_FLOOD_FILL),
/* note on `use_manifold':
@@ -72,956 +72,574 @@ Octree::Octree( ModelReader* mr,
add_vert(add_vert_func),
add_quad(add_quad_func)
{
- this->thresh = threshold ;
- this->reader = mr ;
- this->dimen = 1 << GRID_DIMENSION ;
- this->range = reader->getBoundingBox( this->origin ) ;
- this->nodeCount = this->nodeSpace = 0;
- this->maxDepth = depth ;
- this->mindimen = ( dimen >> maxDepth ) ;
- this->minshift = ( GRID_DIMENSION - maxDepth ) ;
- this->buildTable( ) ;
-
- flood_bytes = use_flood_fill ? FLOOD_FILL_BYTES : 0;
- leaf_extra_bytes = flood_bytes + CINDY_BYTES;
-
-#ifdef USE_HERMIT
- leaf_node_bytes = 7 + leaf_extra_bytes;
-#else
- leaf_node_bytes = 3 + leaf_extra_bytes;
-#endif
+ thresh = threshold;
+ reader = mr;
+ dimen = 1 << GRID_DIMENSION;
+ range = reader->getBoundingBox(origin);
+ nodeCount = nodeSpace = 0;
+ maxDepth = depth;
+ mindimen =(dimen >> maxDepth);
+ minshift =(GRID_DIMENSION - maxDepth);
+ buildTable();
-#ifdef QIANYI
- dc_printf("Origin: (%f %f %f), Dimension: %f\n", origin[0], origin[1], origin[2], range) ;
-#endif
-
- this->maxTrianglePerCell = 0 ;
+ maxTrianglePerCell = 0;
// Initialize memory
#ifdef IN_VERBOSE_MODE
- dc_printf("Range: %f origin: %f, %f,%f \n", range, origin[0], origin[1], origin[2] ) ;
- dc_printf("Initialize memory...\n") ;
+ dc_printf("Range: %f origin: %f, %f,%f \n", range, origin[0], origin[1], origin[2]);
+ dc_printf("Initialize memory...\n");
#endif
- initMemory( ) ;
- this->root = createInternal( 0 ) ;
+ initMemory();
+ root = (Node*)createInternal(0);
// Read MC table
#ifdef IN_VERBOSE_MODE
- dc_printf("Reading contour table...\n") ;
+ dc_printf("Reading contour table...\n");
#endif
- this->cubes = new Cubes();
+ cubes = new Cubes();
}
-Octree::~Octree( )
+Octree::~Octree()
{
- freeMemory( ) ;
+ freeMemory();
}
void Octree::scanConvert()
{
// Scan triangles
#if DC_DEBUG
- clock_t start, finish ;
- start = clock( ) ;
+ clock_t start, finish;
+ start = clock();
#endif
- this->addTrian( ) ;
- this->resetMinimalEdges( ) ;
- this->preparePrimalEdgesMask( this->root ) ;
+ addTrian();
+ resetMinimalEdges();
+ preparePrimalEdgesMask(&root->internal);
#if DC_DEBUG
- finish = clock( ) ;
+ finish = clock();
dc_printf("Time taken: %f seconds \n",
- (double)(finish - start) / CLOCKS_PER_SEC ) ;
+ (double)(finish - start) / CLOCKS_PER_SEC);
#endif
// Generate signs
// Find holes
#if DC_DEBUG
- dc_printf("Patching...\n") ;
- start = clock( ) ;
+ dc_printf("Patching...\n");
+ start = clock();
#endif
- this->trace( ) ;
+ trace();
#if DC_DEBUG
- finish = clock( ) ;
- dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC ) ;
+ finish = clock();
+ dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
#ifdef IN_VERBOSE_MODE
- dc_printf("Holes: %d Average Length: %f Max Length: %d \n", numRings, (float)totRingLengths / (float) numRings, maxRingLength ) ;
+ dc_printf("Holes: %d Average Length: %f Max Length: %d \n", numRings,(float)totRingLengths /(float) numRings, maxRingLength);
#endif
#endif
// Check again
- int tnumRings = numRings ;
- this->trace( ) ;
+ int tnumRings = numRings;
+ trace();
#ifdef IN_VERBOSE_MODE
- dc_printf("Holes after patching: %d \n", numRings) ;
+ dc_printf("Holes after patching: %d \n", numRings);
#endif
- numRings = tnumRings ;
+ numRings = tnumRings;
#if DC_DEBUG
- dc_printf("Building signs...\n") ;
- start = clock( ) ;
+ dc_printf("Building signs...\n");
+ start = clock();
#endif
- this->buildSigns( ) ;
+ buildSigns();
#if DC_DEBUG
- finish = clock( ) ;
- dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC ) ;
+ finish = clock();
+ dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
#endif
if(use_flood_fill) {
/*
- start = clock( ) ;
- this->floodFill( ) ;
+ start = clock();
+ floodFill();
// Check again
- tnumRings = numRings ;
- this->trace( ) ;
- dc_printf("Holes after filling: %d \n", numRings) ;
- numRings = tnumRings ;
- this->buildSigns( ) ;
- finish = clock( ) ;
- dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC ) ;
+ tnumRings = numRings;
+ trace();
+ dc_printf("Holes after filling: %d \n", numRings);
+ numRings = tnumRings;
+ buildSigns();
+ finish = clock();
+ dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
*/
#if DC_DEBUG
- start = clock( ) ;
+ start = clock();
dc_printf("Removing components...\n");
#endif
- this->floodFill( ) ;
- this->buildSigns( ) ;
+ floodFill();
+ buildSigns();
// dc_printf("Checking...\n");
- // this->floodFill( ) ;
+ // floodFill();
#if DC_DEBUG
- finish = clock( ) ;
- dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC ) ;
+ finish = clock();
+ dc_printf("Time taken: %f seconds \n",(double)(finish - start) / CLOCKS_PER_SEC);
#endif
}
// Output
-#ifdef OUTPUT_REPAIRED
#if DC_DEBUG
- start = clock( ) ;
+ start = clock();
#endif
writeOut();
#if DC_DEBUG
- finish = clock( ) ;
-#endif
- // dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC ) ;
-#ifdef CINDY
- this->writeTags( "tags.txt" ) ;
- dc_printf("Tags output to tags.txt\n") ;
-#endif
-
+ finish = clock();
#endif
+ // dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
// Print info
#ifdef IN_VERBOSE_MODE
- printMemUsage( ) ;
+ printMemUsage();
#endif
}
-#if 0
-void Octree::writeOut( char* fname )
+void Octree::initMemory()
{
- dc_printf( "\n" ) ;
- if ( strstr( fname, ".ply" ) != NULL )
- {
- dc_printf("Writing PLY file format.\n") ;
- this->outType = 1 ;
- writePLY( fname ) ;
- }
- else if ( strstr( fname, ".off" ) != NULL )
- {
- dc_printf("Writing OFF file format.\n") ;
- this->outType = 0 ;
- writeOFF( fname ) ;
- }
- else if ( strstr( fname, ".sof" ) != NULL )
- {
- dc_printf("Writing Signed Octree File format.\n") ;
- this->outType = 2 ;
- writeOctree( fname ) ;
- }
- else if ( strstr( fname, ".dcf" ) != NULL )
- {
-#ifdef USE_HERMIT
- dc_printf("Writing Dual Contouring File format.\n") ;
- this->outType = 3 ;
- writeDCF( fname ) ;
-#else
- dc_printf("Can not write Dual Contouring File format in non-DC mode.\n") ;
-#endif
- }
-#ifdef USE_HERMIT
- else if ( strstr( fname, ".sog" ) != NULL )
- {
- dc_printf("Writing signed octree with geometry.\n") ;
- this->outType = 4 ;
- writeOctreeGeom( fname ) ;
- }
-#endif
- /*
- else if ( strstr( fname, ".sof" ) != NULL )
- {
- dc_printf("Writing SOF file format.\n") ;
- this->outType = 2 ;
- writeOctree( fname ) ;
- }
- */
- else
- {
- dc_printf("Unknown output format.\n") ;
- }
+ leafalloc[0] = new MemoryAllocator<sizeof(LeafNode)>();
+ leafalloc[1] = new MemoryAllocator<sizeof(LeafNode) + sizeof(float) * EDGE_FLOATS>();
+ leafalloc[2] = new MemoryAllocator<sizeof(LeafNode) + sizeof(float) * EDGE_FLOATS * 2>();
+ leafalloc[3] = new MemoryAllocator<sizeof(LeafNode) + sizeof(float) * EDGE_FLOATS * 3>();
+ alloc[0] = new MemoryAllocator<sizeof(InternalNode)>();
+ alloc[1] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node*)>();
+ alloc[2] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node*) * 2>();
+ alloc[3] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node*) * 3>();
+ alloc[4] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node*) * 4>();
+ alloc[5] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node*) * 5>();
+ alloc[6] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node*) * 6>();
+ alloc[7] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node*) * 7>();
+ alloc[8] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node*) * 8>();
}
-#endif
-void Octree::initMemory( )
+void Octree::freeMemory()
{
-#ifdef USE_HERMIT
- const int leaf_node_bytes = 7;
-#else
- const int leaf_node_bytes = 3;
-#endif
-
- if(use_flood_fill) {
- const int bytes = leaf_node_bytes + CINDY_BYTES + FLOOD_FILL_BYTES;
- this->leafalloc[ 0 ] = new MemoryAllocator< bytes > ( ) ;
- this->leafalloc[ 1 ] = new MemoryAllocator< bytes + EDGE_BYTES > ( ) ;
- this->leafalloc[ 2 ] = new MemoryAllocator< bytes + EDGE_BYTES * 2 > ( ) ;
- this->leafalloc[ 3 ] = new MemoryAllocator< bytes + EDGE_BYTES * 3 > ( ) ;
- }
- else {
- const int bytes = leaf_node_bytes + CINDY_BYTES;
- this->leafalloc[ 0 ] = new MemoryAllocator< bytes > ( ) ;
- this->leafalloc[ 1 ] = new MemoryAllocator< bytes + EDGE_BYTES > ( ) ;
- this->leafalloc[ 2 ] = new MemoryAllocator< bytes + EDGE_BYTES * 2 > ( ) ;
- this->leafalloc[ 3 ] = new MemoryAllocator< bytes + EDGE_BYTES * 3 > ( ) ;
- }
-
- this->alloc[ 0 ] = new MemoryAllocator< INTERNAL_NODE_BYTES > ( ) ;
- this->alloc[ 1 ] = new MemoryAllocator< INTERNAL_NODE_BYTES + POINTER_BYTES > ( ) ;
- this->alloc[ 2 ] = new MemoryAllocator< INTERNAL_NODE_BYTES + POINTER_BYTES*2 > ( ) ;
- this->alloc[ 3 ] = new MemoryAllocator< INTERNAL_NODE_BYTES + POINTER_BYTES*3 > ( ) ;
- this->alloc[ 4 ] = new MemoryAllocator< INTERNAL_NODE_BYTES + POINTER_BYTES*4 > ( ) ;
- this->alloc[ 5 ] = new MemoryAllocator< INTERNAL_NODE_BYTES + POINTER_BYTES*5 > ( ) ;
- this->alloc[ 6 ] = new MemoryAllocator< INTERNAL_NODE_BYTES + POINTER_BYTES*6 > ( ) ;
- this->alloc[ 7 ] = new MemoryAllocator< INTERNAL_NODE_BYTES + POINTER_BYTES*7 > ( ) ;
- this->alloc[ 8 ] = new MemoryAllocator< INTERNAL_NODE_BYTES + POINTER_BYTES*8 > ( ) ;
-}
-
-void Octree::freeMemory( )
-{
- for ( int i = 0 ; i < 9 ; i ++ )
+ for(int i = 0; i < 9; i ++)
{
- alloc[i]->destroy() ;
- delete alloc[i] ;
+ alloc[i]->destroy();
+ delete alloc[i];
}
- for ( int i = 0 ; i < 4 ; i ++ )
+ for(int i = 0; i < 4; i ++)
{
- leafalloc[i]->destroy() ;
- delete leafalloc[i] ;
+ leafalloc[i]->destroy();
+ delete leafalloc[i];
}
}
-void Octree::printMemUsage( )
+void Octree::printMemUsage()
{
- int totalbytes = 0 ;
- dc_printf("********* Internal nodes: \n") ;
- for ( int i = 0 ; i < 9 ; i ++ )
+ int totalbytes = 0;
+ dc_printf("********* Internal nodes: \n");
+ for(int i = 0; i < 9; i ++)
{
- this->alloc[ i ]->printInfo() ;
+ alloc[i]->printInfo();
- totalbytes += alloc[i]->getAll( ) * alloc[i]->getBytes() ;
+ totalbytes += alloc[i]->getAll() * alloc[i]->getBytes();
}
- dc_printf("********* Leaf nodes: \n") ;
- int totalLeafs = 0 ;
- for ( int i = 0 ; i < 4 ; i ++ )
+ dc_printf("********* Leaf nodes: \n");
+ int totalLeafs = 0;
+ for(int i = 0; i < 4; i ++)
{
- this->leafalloc[ i ]->printInfo() ;
+ leafalloc[i]->printInfo();
- totalbytes += leafalloc[i]->getAll( ) * leafalloc[i]->getBytes() ;
- totalLeafs += leafalloc[i]->getAllocated() ;
+ totalbytes += leafalloc[i]->getAll() * leafalloc[i]->getBytes();
+ totalLeafs += leafalloc[i]->getAllocated();
}
- dc_printf("Total allocated bytes on disk: %d \n", totalbytes) ;
- dc_printf("Total leaf nodes: %d\n", totalLeafs ) ;
-}
-
-void Octree::resetMinimalEdges( )
-{
- this->cellProcParity( this->root, 0, maxDepth ) ;
-}
-
-void Octree::writeModel( char* fname )
-{
- reader->reset() ;
-
- int nFace = reader->getNumTriangles() ;
- Triangle* trian ;
- // int unitcount = 10000;
- int count = 0 ;
- int nVert = nFace * 3 ;
- FILE* modelfout = fopen( "model.off", "w" ) ;
- fprintf( modelfout, "OFF\n" ) ;
- fprintf( modelfout, "%d %d 0\n", nVert, nFace ) ;
-
- //int total = this->reader->getNumTriangles() ;
- dc_printf( "Start writing model to OFF...\n" ) ;
- srand(0) ;
- while ( ( trian = reader->getNextTriangle() ) != NULL )
- {
- // Drop polygons
- {
- int i, j ;
-
- // Blow up the triangle
- float mid[3] = {0, 0, 0} ;
- for ( i = 0 ; i < 3 ; i ++ )
- for ( j = 0 ; j < 3 ; j ++ )
- {
- trian->vt[i][j] = dimen * ( trian->vt[i][j] - origin[j] ) / range ;
-
- mid[j] += trian->vt[i][j] / 3 ;
- }
-
- // Generate projections
- // LONG cube[2][3] = { { 0, 0, 0 }, { dimen, dimen, dimen } } ;
- int trig[3][3] ;
-
- // Blowing up the triangle to the grid
- for ( i = 0 ; i < 3 ; i ++ )
- for ( j = 0 ; j < 3 ; j ++ )
- {
- trig[i][j] = (int) (trian->vt[i][j]) ;
- // Perturb end points, if set so
- }
-
-
- for ( i = 0 ; i < 3 ; i ++ )
- {
- fprintf( modelfout, "%f %f %f\n",
- (float)(((double) trig[i][0] / dimen) * range + origin[0]) ,
- (float)(((double) trig[i][1] / dimen) * range + origin[1]) ,
- (float)(((double) trig[i][2] / dimen) * range + origin[2]) ) ;
- }
- }
- delete trian ;
-
- count ++ ;
-
- }
-
- for ( int i = 0 ; i < nFace ; i ++ )
- {
- fprintf( modelfout, "3 %d %d %d\n", 3 * i + 2, 3 * i + 1, 3 * i ) ;
- }
-
- fclose( modelfout ) ;
-
-}
-
-#ifdef CINDY
-void Octree::writeTags( char* fname )
-{
- FILE* fout = fopen( fname, "w" ) ;
-
- clearCindyBits( root, maxDepth ) ;
- readVertices() ;
- outputTags( root, maxDepth, fout ) ;
-
- fclose ( fout ) ;
-}
-
-void Octree::readVertices( )
-{
- int total = this->reader->getNumVertices() ;
- reader->reset() ;
- float v[3] ;
- int st[3] = {0,0,0};
- int unitcount = 1000 ;
- dc_printf( "\nRead in original %d vertices...\n", total ) ;
-
- for ( int i = 0 ; i < total ; i ++ )
- {
- reader->getNextVertex( v ) ;
- // Blowing up the triangle to the grid
- float mid[3] = {0, 0, 0} ;
- for ( int j = 0 ; j < 3 ; j ++ )
- {
- v[j] = dimen * ( v[j] - origin[j] ) / range ;
- }
-
-// dc_printf("vertex: %f %f %f, dimen: %d\n", v[0], v[1], v[2], dimen ) ;
- readVertex ( root, st, dimen, maxDepth, v, i ) ;
-
-
- if ( i % unitcount == 0 )
- {
- putchar ( 13 ) ;
-
- switch ( ( i / unitcount ) % 4 )
- {
- case 0 : dc_printf("-");
- break ;
- case 1 : dc_printf("/") ;
- break ;
- case 2 : dc_printf("|");
- break ;
- case 3 : dc_printf("\\") ;
- break ;
- }
-
- float percent = (float) i / total ;
- /*
- int totbars = 50 ;
- int bars = (int)( percent * totbars ) ;
- for ( int i = 0 ; i < bars ; i ++ )
- {
- putchar( 219 ) ;
- }
- for ( i = bars ; i < totbars ; i ++ )
- {
- putchar( 176 ) ;
- }
- */
-
- dc_printf(" %d vertices: ", i ) ;
- dc_printf( " %f%% complete.", 100 * percent ) ;
- }
-
- }
- putchar ( 13 ) ;
- dc_printf(" \n");
-}
-
-void Octree::readVertex( UCHAR* node, int st[3], int len, int height, float v[3], int index )
-{
- int nst[3] ;
- nst[0] = ( (int) v[0] / mindimen ) * mindimen ;
- nst[1] = ( (int) v[1] / mindimen ) * mindimen ;
- nst[2] = ( (int) v[2] / mindimen ) * mindimen ;
-
- UCHAR* cell = this->locateLeafCheck( nst ) ;
- if ( cell == NULL )
- {
- dc_printf("Cell %d %d %d is not found!\n", nst[0]/ mindimen, nst[1]/ mindimen, nst[2]/ mindimen) ;
- return ;
- }
-
- setOriginalIndex( cell, index ) ;
-
-
- /*
- int i ;
- if ( height == 0 )
- {
- // Leaf cell, assign index
- dc_printf("Setting: %d\n", index ) ;
- setOriginalIndex( node, index ) ;
- }
- else
- {
- len >>= 1 ;
- // Internal cell, check and recur
- int x = ( v[0] > st[0] + len ) ? 1 : 0 ;
- int y = ( v[1] > st[1] + len ) ? 1 : 0 ;
- int z = ( v[2] > st[2] + len ) ? 1 : 0 ;
- int child = x * 4 + y * 2 + z ;
-
- int count = 0 ;
- for ( i = 0 ; i < 8 ; i ++ )
- {
- if ( i == child && hasChild( node, i ) )
- {
- int nst[3] ;
- nst[0] = st[0] + vertmap[i][0] * len ;
- nst[1] = st[1] + vertmap[i][1] * len ;
- nst[2] = st[2] + vertmap[i][2] * len ;
-
- dc_printf("Depth: %d -- child %d vertex: %f %f %f in %f %f %f\n", height - 1, child, v[0]/mindimen, v[1]/mindimen, v[2]/mindimen,
- nst[0]/mindimen, nst[1]/mindimen, nst[2]/mindimen, len/mindimen ) ;
-
- readVertex( getChild( node, count ), nst, len, height - 1, v, index ) ;
- count ++ ;
- }
- }
- }
- */
-}
-
-void Octree::outputTags( UCHAR* node, int height, FILE* fout )
-{
- int i ;
-
- if ( height == 0 )
- {
- // Leaf cell, generate
- int smask = getSignMask( node ) ;
-
- if(use_manifold) {
- int comps = manifold_table[ smask ].comps ;
- if ( comps != 1 )
- {
- return ;
- }
- }
- else
- {
- if ( smask == 0 || smask == 255 )
- {
- return ;
- }
- }
-
- int rindex = getMinimizerIndex( node ) ;
- int oindex = getOriginalIndex( node ) ;
-
- if ( oindex >= 0 )
- {
- fprintf( fout, "%d: %d\n", rindex, oindex ) ;
- }
-
- }
- else
- {
- // Internal cell, recur
- int count = 0 ;
- for ( i = 0 ; i < 8 ; i ++ )
- {
- if ( hasChild( node, i ) )
- {
- outputTags( getChild( node, count ), height - 1, fout ) ;
- count ++ ;
- }
- }
- }
+ dc_printf("Total allocated bytes on disk: %d \n", totalbytes);
+ dc_printf("Total leaf nodes: %d\n", totalLeafs);
}
-void Octree::clearCindyBits( UCHAR* node, int height )
+void Octree::resetMinimalEdges()
{
- int i;
-
- if ( height == 0 )
- {
- // Leaf cell,
- {
- setOriginalIndex( node, - 1 ) ;
- }
- }
- else
- {
- // Internal cell, recur
- int count = 0 ;
- for ( i = 0 ; i < 8 ; i ++ )
- {
- if ( hasChild( node, i ) )
- {
- clearCindyBits( getChild( node, count ), height - 1 ) ;
- count ++ ;
- }
- }
- }
+ cellProcParity(root, 0, maxDepth);
}
-#endif
-void Octree::addTrian( )
+void Octree::addTrian()
{
- Triangle* trian ;
- int count = 0 ;
+ Triangle* trian;
+ int count = 0;
#if DC_DEBUG
- int total = this->reader->getNumTriangles() ;
- int unitcount = 1000 ;
- dc_printf( "\nScan converting to depth %d...\n", maxDepth ) ;
+ int total = reader->getNumTriangles();
+ int unitcount = 1000;
+ dc_printf("\nScan converting to depth %d...\n", maxDepth);
#endif
- srand(0) ;
+ srand(0);
- while ( ( trian = reader->getNextTriangle() ) != NULL )
+ while((trian = reader->getNextTriangle()) != NULL)
{
// Drop triangles
{
- addTrian ( trian, count ) ;
+ addTrian(trian, count);
}
- delete trian ;
+ delete trian;
- count ++ ;
+ count ++;
#if DC_DEBUG
- if ( count % unitcount == 0 )
+ if(count % unitcount == 0)
{
- putchar ( 13 ) ;
+ putchar(13);
- switch ( ( count / unitcount ) % 4 )
+ switch((count / unitcount) % 4)
{
case 0 : dc_printf("-");
- break ;
- case 1 : dc_printf("/") ;
- break ;
+ break;
+ case 1 : dc_printf("/");
+ break;
case 2 : dc_printf("|");
- break ;
- case 3 : dc_printf("\\") ;
- break ;
+ break;
+ case 3 : dc_printf("\\");
+ break;
}
- float percent = (float) count / total ;
+ float percent =(float) count / total;
/*
- int totbars = 50 ;
- int bars = (int)( percent * totbars ) ;
- for ( int i = 0 ; i < bars ; i ++ )
+ int totbars = 50;
+ int bars =(int)(percent * totbars);
+ for(int i = 0; i < bars; i ++)
{
- putchar( 219 ) ;
+ putchar(219);
}
- for ( i = bars ; i < totbars ; i ++ )
+ for(i = bars; i < totbars; i ++)
{
- putchar( 176 ) ;
+ putchar(176);
}
*/
- dc_printf(" %d triangles: ", count ) ;
- dc_printf( " %f%% complete.", 100 * percent ) ;
+ dc_printf(" %d triangles: ", count);
+ dc_printf(" %f%% complete.", 100 * percent);
}
#endif
}
- putchar ( 13 ) ;
+ putchar(13);
}
-void Octree::addTrian( Triangle* trian, int triind )
+void Octree::addTrian(Triangle* trian, int triind)
{
- int i, j ;
+ int i, j;
// Blowing up the triangle to the grid
- float mid[3] = {0, 0, 0} ;
- for ( i = 0 ; i < 3 ; i ++ )
- for ( j = 0 ; j < 3 ; j ++ )
+ float mid[3] = {0, 0, 0};
+ for(i = 0; i < 3; i ++)
+ for(j = 0; j < 3; j ++)
{
- trian->vt[i][j] = dimen * ( trian->vt[i][j] - origin[j] ) / range ;
- mid[j] += trian->vt[i][j] / 3 ;
+ trian->vt[i][j] = dimen *(trian->vt[i][j] - origin[j]) / range;
+ mid[j] += trian->vt[i][j] / 3;
}
// Generate projections
- LONG cube[2][3] = { { 0, 0, 0 }, { dimen, dimen, dimen } } ;
- LONG trig[3][3] ;
+ LONG cube[2][3] = {{0, 0, 0}, {dimen, dimen, dimen}};
+ LONG trig[3][3];
- for ( i = 0 ; i < 3 ; i ++ )
- for ( j = 0 ; j < 3 ; j ++ )
+ for(i = 0; i < 3; i ++)
+ for( j = 0; j < 3; j ++)
{
- trig[i][j] = (LONG) (trian->vt[i][j]) ;
+ trig[i][j] =(LONG)(trian->vt[i][j]);
// Perturb end points, if set so
}
// Add to the octree
- // int start[3] = { 0, 0, 0 } ;
- LONG errorvec = (LONG) ( 0 ) ;
- Projections* proj = new Projections( cube, trig, errorvec, triind ) ;
- root = addTrian( root, proj, maxDepth ) ;
+ // int start[3] = {0, 0, 0};
+ LONG errorvec =(LONG)(0);
+ Projections* proj = new Projections(cube, trig, errorvec, triind);
+ root = (Node*)addTrian(&root->internal, proj, maxDepth);
- delete proj->inherit ;
- delete proj ;
+ delete proj->inherit;
+ delete proj;
}
-UCHAR* Octree::addTrian( UCHAR* node, Projections* p, int height )
+InternalNode* Octree::addTrian(InternalNode* node, Projections* p, int height)
{
- int i ;
- int vertdiff[8][3] = {{0,0,0},{0,0,1},{0,1,-1},{0,0,1},{1,-1,-1},{0,0,1},{0,1,-1},{0,0,1}} ;
- UCHAR boxmask = p->getBoxMask( ) ;
- Projections* subp = new Projections( p ) ;
+ int i;
+ int vertdiff[8][3] = {{0,0,0},{0,0,1},{0,1,-1},{0,0,1},{1,-1,-1},{0,0,1},{0,1,-1},{0,0,1}};
+ UCHAR boxmask = p->getBoxMask();
+ Projections* subp = new Projections(p);
- int count = 0 ;
- int tempdiff[3] = {0,0,0} ;
- for ( i = 0 ; i < 8 ; i ++ )
+ int count = 0;
+ int tempdiff[3] = {0,0,0};
+ for(i = 0; i < 8; i ++)
{
- tempdiff[0] += vertdiff[i][0] ;
- tempdiff[1] += vertdiff[i][1] ;
- tempdiff[2] += vertdiff[i][2] ;
+ tempdiff[0] += vertdiff[i][0];
+ tempdiff[1] += vertdiff[i][1];
+ tempdiff[2] += vertdiff[i][2];
/* Quick pruning using bounding box */
- if ( boxmask & ( 1 << i ) )
+ if(boxmask &(1 << i))
{
- subp->shift( tempdiff ) ;
- tempdiff[0] = tempdiff[1] = tempdiff[2] = 0 ;
+ subp->shift(tempdiff);
+ tempdiff[0] = tempdiff[1] = tempdiff[2] = 0;
/* Pruning using intersection test */
- if ( subp->isIntersecting() )
- // if ( subp->getIntersectionMasks( cedgemask, edgemask ) )
+ if(subp->isIntersecting())
+ // if(subp->getIntersectionMasks(cedgemask, edgemask))
{
- if ( ! hasChild( node, i ) )
+ if(! hasChild(node, i))
{
- if ( height == 1 )
+ if(height == 1)
{
- node = addLeafChild( node, i, count, createLeaf(0) ) ;
+ node = addLeafChild(node, i, count, createLeaf(0));
}
else
{
- node = addInternalChild( node, i, count, createInternal(0) ) ;
+ node = addInternalChild(node, i, count, createInternal(0));
}
}
- UCHAR* chd = getChild( node, count ) ;
+ Node* chd = getChild(node, count);
- if ( ! isLeaf( node, i ) )
+ if(! isLeaf(node, i))
{
- // setChild( node, count, addTrian ( chd, subp, height - 1, vertmask[i], edgemask ) ) ;
- setChild( node, count, addTrian ( chd, subp, height - 1 ) ) ;
+ // setChild(node, count, addTrian(chd, subp, height - 1, vertmask[i], edgemask));
+ setChild(node, count, (Node*)addTrian(&chd->internal, subp, height - 1));
}
else
{
- setChild( node, count, updateCell( chd, subp ) ) ;
+ setChild(node, count, (Node*)updateCell(&chd->leaf, subp));
}
}
}
- if ( hasChild( node, i ) )
+ if(hasChild(node, i))
{
- count ++ ;
+ count ++;
}
}
- delete subp ;
- return node ;
+ delete subp;
+
+ return node;
}
-UCHAR* Octree::updateCell( UCHAR* node, Projections* p )
+LeafNode* Octree::updateCell(LeafNode* node, Projections* p)
{
- int i ;
+ int i;
// Edge connectivity
- int mask[3] = { 0, 4, 8 } ;
- int oldc = 0, newc = 0 ;
- float offs[3] ;
-#ifdef USE_HERMIT
- float a[3], b[3], c[3] ;
-#endif
+ int mask[3] = {0, 4, 8 };
+ int oldc = 0, newc = 0;
+ float offs[3];
+ float a[3], b[3], c[3];
- for ( i = 0 ; i < 3 ; i ++ )
+ for(i = 0; i < 3; i ++)
{
- if ( ! getEdgeParity( node, mask[i] ) )
+ if(! getEdgeParity(node, mask[i]))
{
- if ( p->isIntersectingPrimary( i ) )
+ if(p->isIntersectingPrimary(i))
{
- // this->actualQuads ++ ;
- setEdge( node, mask[i] ) ;
- offs[ newc ] = p->getIntersectionPrimary( i ) ;
-#ifdef USE_HERMIT
- a[ newc ] = (float) p->inherit->norm[0] ;
- b[ newc ] = (float) p->inherit->norm[1] ;
- c[ newc ] = (float) p->inherit->norm[2] ;
-#endif
- newc ++ ;
+ // actualQuads ++;
+ setEdge(node, mask[i]);
+ offs[newc] = p->getIntersectionPrimary(i);
+ a[newc] =(float) p->inherit->norm[0];
+ b[newc] =(float) p->inherit->norm[1];
+ c[newc] =(float) p->inherit->norm[2];
+ newc ++;
}
}
else
{
-#ifndef USE_HERMIT
- offs[ newc ] = getEdgeOffset( node, oldc ) ;
-#else
- offs[ newc ] = getEdgeOffsetNormal( node, oldc, a[ newc ], b[ newc ], c[ newc ] ) ;
-#endif
+ offs[newc] = getEdgeOffsetNormal(node, oldc, a[newc], b[newc], c[newc]);
-// if ( p->isIntersectingPrimary( i ) )
+// if(p->isIntersectingPrimary(i))
{
- // dc_printf("Multiple intersections!\n") ;
+ // dc_printf("Multiple intersections!\n");
-// setPatchEdge( node, i ) ;
+// setPatchEdge(node, i);
}
- oldc ++ ;
- newc ++ ;
+ oldc ++;
+ newc ++;
}
}
- if ( newc > oldc )
+ if(newc > oldc)
{
// New offsets added, update this node
-#ifndef USE_HERMIT
- node = updateEdgeOffsets( node, oldc, newc, offs ) ;
-#else
- node = updateEdgeOffsetsNormals( node, oldc, newc, offs, a, b, c ) ;
-#endif
+ node = updateEdgeOffsetsNormals(node, oldc, newc, offs, a, b, c);
}
-
-
- return node ;
+ return node;
}
-void Octree::preparePrimalEdgesMask( UCHAR* node )
+void Octree::preparePrimalEdgesMask(InternalNode* node)
{
- int count = 0 ;
- for ( int i = 0 ; i < 8 ; i ++ )
+ int count = 0;
+ for(int i = 0; i < 8; i ++)
{
- if ( hasChild( node, i ) )
+ if(hasChild(node, i))
{
- if ( isLeaf( node, i ) )
- {
- createPrimalEdgesMask( getChild( node, count ) ) ;
- }
+ if(isLeaf(node, i))
+ createPrimalEdgesMask(&getChild(node, count)->leaf);
else
- {
- preparePrimalEdgesMask( getChild( node, count ) ) ;
- }
+ preparePrimalEdgesMask(&getChild(node, count)->internal);
- count ++ ;
+ count ++;
}
}
}
-void Octree::trace( )
+void Octree::trace()
{
- int st[3] = { 0, 0, 0, } ;
- this->numRings = 0 ;
- this->totRingLengths = 0 ;
- this->maxRingLength = 0 ;
+ int st[3] = {0, 0, 0,};
+ numRings = 0;
+ totRingLengths = 0;
+ maxRingLength = 0;
- PathList* chdpath = NULL ;
- this->root = trace( this->root, st, dimen, maxDepth, chdpath ) ;
+ PathList* chdpath = NULL;
+ root = trace(root, st, dimen, maxDepth, chdpath);
- if ( chdpath != NULL )
+ if(chdpath != NULL)
{
- dc_printf("there are incomplete rings.\n") ;
- printPaths( chdpath ) ;
+ dc_printf("there are incomplete rings.\n");
+ printPaths(chdpath);
};
}
-UCHAR* Octree::trace( UCHAR* node, int* st, int len, int depth, PathList*& paths)
+Node* Octree::trace(Node* newnode, int* st, int len, int depth, PathList*& paths)
{
- UCHAR* newnode = node ;
- len >>= 1 ;
- PathList* chdpaths[ 8 ] ;
- UCHAR* chd[ 8 ] ;
- int nst[ 8 ][ 3 ] ;
- int i, j ;
+ len >>= 1;
+ PathList* chdpaths[8];
+ Node* chd[8];
+ int nst[8][3];
+ int i, j;
// Get children paths
- int chdleaf[ 8 ] ;
- fillChildren( newnode, chd, chdleaf ) ;
+ int chdleaf[8];
+ fillChildren(&newnode->internal, chd, chdleaf);
- // int count = 0 ;
- for ( i = 0 ; i < 8 ; i ++ )
+ // int count = 0;
+ for(i = 0; i < 8; i ++)
{
- for ( j = 0 ; j < 3 ; j ++ )
+ for(j = 0; j < 3; j ++)
{
- nst[ i ][ j ] = st[ j ] + len * vertmap[ i ][ j ] ;
+ nst[i][j] = st[j] + len * vertmap[i][j];
}
- if ( chd[ i ] == NULL || isLeaf( node, i ) )
+ if(chd[i] == NULL || isLeaf(&newnode->internal, i))
{
- chdpaths[ i ] = NULL ;
+ chdpaths[i] = NULL;
}
else
{
- trace( chd[ i ], nst[i], len, depth - 1, chdpaths[ i ] ) ;
+ trace(chd[i], nst[i], len, depth - 1, chdpaths[i]);
}
}
// Get connectors on the faces
- PathList* conn[ 12 ] ;
- UCHAR* nf[2] ;
- int lf[2] ;
- int df[2] = { depth - 1, depth - 1 } ;
- int* nstf[ 2 ];
+ PathList* conn[12];
+ Node* nf[2];
+ int lf[2];
+ int df[2] = {depth - 1, depth - 1};
+ int* nstf[2];
- fillChildren( newnode, chd, chdleaf ) ;
+ fillChildren(&newnode->internal, chd, chdleaf);
- for ( i = 0 ; i < 12 ; i ++ )
+ for(i = 0; i < 12; i ++)
{
- int c[ 2 ] = { cellProcFaceMask[ i ][ 0 ], cellProcFaceMask[ i ][ 1 ] };
+ int c[2] = {cellProcFaceMask[i][0], cellProcFaceMask[i][1]};
- for ( int j = 0 ; j < 2 ; j ++ )
+ for(int j = 0; j < 2; j ++)
{
- lf[j] = chdleaf[ c[j] ] ;
- nf[j] = chd[ c[j] ] ;
- nstf[j] = nst[ c[j] ] ;
+ lf[j] = chdleaf[c[j]];
+ nf[j] = chd[c[j]];
+ nstf[j] = nst[c[j]];
}
- conn[ i ] = NULL ;
+ conn[i] = NULL;
- findPaths( nf, lf, df, nstf, depth - 1, cellProcFaceMask[ i ][ 2 ], conn[ i ] ) ;
+ findPaths((Node**)nf, lf, df, nstf, depth - 1, cellProcFaceMask[i][2], conn[i]);
- //if ( conn[i] )
+ //if(conn[i])
//{
- // printPath( conn[i] ) ;
+ // printPath(conn[i]);
//}
}
// Connect paths
- PathList* rings = NULL ;
- combinePaths( chdpaths[0], chdpaths[1], conn[8], rings ) ;
- combinePaths( chdpaths[2], chdpaths[3], conn[9], rings ) ;
- combinePaths( chdpaths[4], chdpaths[5], conn[10], rings ) ;
- combinePaths( chdpaths[6], chdpaths[7], conn[11], rings ) ;
-
- combinePaths( chdpaths[0], chdpaths[2], conn[4], rings ) ;
- combinePaths( chdpaths[4], chdpaths[6], conn[5], rings ) ;
- combinePaths( chdpaths[0], NULL, conn[6], rings ) ;
- combinePaths( chdpaths[4], NULL, conn[7], rings ) ;
-
- combinePaths( chdpaths[0], chdpaths[4], conn[0], rings ) ;
- combinePaths( chdpaths[0], NULL, conn[1], rings ) ;
- combinePaths( chdpaths[0], NULL, conn[2], rings ) ;
- combinePaths( chdpaths[0], NULL, conn[3], rings ) ;
+ PathList* rings = NULL;
+ combinePaths(chdpaths[0], chdpaths[1], conn[8], rings);
+ combinePaths(chdpaths[2], chdpaths[3], conn[9], rings);
+ combinePaths(chdpaths[4], chdpaths[5], conn[10], rings);
+ combinePaths(chdpaths[6], chdpaths[7], conn[11], rings);
+
+ combinePaths(chdpaths[0], chdpaths[2], conn[4], rings);
+ combinePaths(chdpaths[4], chdpaths[6], conn[5], rings);
+ combinePaths(chdpaths[0], NULL, conn[6], rings);
+ combinePaths(chdpaths[4], NULL, conn[7], rings);
+
+ combinePaths(chdpaths[0], chdpaths[4], conn[0], rings);
+ combinePaths(chdpaths[0], NULL, conn[1], rings);
+ combinePaths(chdpaths[0], NULL, conn[2], rings);
+ combinePaths(chdpaths[0], NULL, conn[3], rings);
// By now, only chdpaths[0] and rings have contents
// Process rings
- if ( rings )
+ if(rings)
{
- // printPath( rings ) ;
+ // printPath(rings);
/* Let's count first */
- PathList* trings = rings ;
- while ( trings )
+ PathList* trings = rings;
+ while(trings)
{
- this->numRings ++ ;
- this->totRingLengths += trings->length ;
- if ( trings->length > this->maxRingLength )
+ numRings ++;
+ totRingLengths += trings->length;
+ if(trings->length > maxRingLength)
{
- this->maxRingLength = trings->length ;
+ maxRingLength = trings->length;
}
- trings = trings->next ;
+ trings = trings->next;
}
- // printPath( rings ) ;
- newnode = patch( newnode, st, ( len << 1 ), rings ) ;
+ // printPath(rings);
+ newnode = patch(newnode, st,(len << 1), rings);
}
// Return incomplete paths
- paths = chdpaths[0] ;
- return newnode ;
+ paths = chdpaths[0];
+ return newnode;
}
-void Octree::findPaths( UCHAR* node[2], int leaf[2], int depth[2], int* st[2], int maxdep, int dir, PathList*& paths )
+void Octree::findPaths(Node* node[2], int leaf[2], int depth[2], int* st[2], int maxdep, int dir, PathList*& paths)
{
- if ( ! ( node[0] && node[1] ) )
+ if(!(node[0] && node[1]))
{
- return ;
+ return;
}
- if ( ! ( leaf[0] && leaf[1] ) )
+ if(!(leaf[0] && leaf[1]))
{
// Not at the bottom, recur
// Fill children nodes
- int i, j ;
- UCHAR* chd[ 2 ][ 8 ] ;
- int chdleaf[ 2 ][ 8 ] ;
- int nst[ 2 ][ 8 ][ 3 ] ;
+ int i, j;
+ Node* chd[2][8];
+ int chdleaf[2][8];
+ int nst[2][8][3];
- for ( j = 0 ; j < 2 ; j ++ )
+ for(j = 0; j < 2; j ++)
{
- if ( ! leaf[j] )
+ if(! leaf[j])
{
- fillChildren( node[j], chd[j], chdleaf[j] ) ;
+ fillChildren(&node[j]->internal, chd[j], chdleaf[j]);
- int len = ( dimen >> ( maxDepth - depth[j] + 1 ) ) ;
- for ( i = 0 ; i < 8 ; i ++ )
+ int len =(dimen >>(maxDepth - depth[j] + 1));
+ for(i = 0; i < 8; i ++)
{
- for ( int k = 0 ; k < 3 ; k ++ )
+ for(int k = 0; k < 3; k ++)
{
- nst[ j ][ i ][ k ] = st[ j ][ k ] + len * vertmap[ i ][ k ] ;
+ nst[j][i][k] = st[j][k] + len * vertmap[i][k];
}
}
@@ -1029,2428 +647,1626 @@ void Octree::findPaths( UCHAR* node[2], int leaf[2], int depth[2], int* st[2], i
}
// 4 face calls
- UCHAR* nf[2] ;
- int df[2] ;
- int lf[2] ;
- int* nstf[2] ;
- for ( i = 0 ; i < 4 ; i ++ )
+ Node* nf[2];
+ int df[2];
+ int lf[2];
+ int* nstf[2];
+ for(i = 0; i < 4; i ++)
{
- int c[2] = { faceProcFaceMask[ dir ][ i ][ 0 ], faceProcFaceMask[ dir ][ i ][ 1 ] };
- for ( int j = 0 ; j < 2 ; j ++ )
+ int c[2] = {faceProcFaceMask[dir][i][0], faceProcFaceMask[dir][i][1]};
+ for(int j = 0; j < 2; j ++)
{
- if ( leaf[j] )
+ if(leaf[j])
{
- lf[j] = leaf[j] ;
- nf[j] = node[j] ;
- df[j] = depth[j] ;
- nstf[j] = st[j] ;
+ lf[j] = leaf[j];
+ nf[j] = node[j];
+ df[j] = depth[j];
+ nstf[j] = st[j];
}
else
{
- lf[j] = chdleaf[ j ][ c[j] ] ;
- nf[j] = chd[ j ][ c[j] ] ;
- df[j] = depth[j] - 1 ;
- nstf[j] = nst[ j ][ c[j] ] ;
+ lf[j] = chdleaf[j][c[j]];
+ nf[j] = chd[j][c[j]];
+ df[j] = depth[j] - 1;
+ nstf[j] = nst[j][c[j]];
}
}
- findPaths( nf, lf, df, nstf, maxdep - 1, faceProcFaceMask[ dir ][ i ][ 2 ], paths ) ;
+ findPaths(nf, lf, df, nstf, maxdep - 1, faceProcFaceMask[dir][i][2], paths);
}
}
else
{
// At the bottom, check this face
- int ind = ( depth[0] == maxdep ? 0 : 1 ) ;
- int fcind = 2 * dir + ( 1 - ind ) ;
- if ( getFaceParity( node[ ind ], fcind ) )
+ int ind =(depth[0] == maxdep ? 0 : 1);
+ int fcind = 2 * dir +(1 - ind);
+ if(getFaceParity((LeafNode*)node[ind], fcind))
{
// Add into path
- PathElement* ele1 = new PathElement ;
- PathElement* ele2 = new PathElement ;
+ PathElement* ele1 = new PathElement;
+ PathElement* ele2 = new PathElement;
- ele1->pos[0] = st[0][0] ;
- ele1->pos[1] = st[0][1] ;
- ele1->pos[2] = st[0][2] ;
+ ele1->pos[0] = st[0][0];
+ ele1->pos[1] = st[0][1];
+ ele1->pos[2] = st[0][2];
- ele2->pos[0] = st[1][0] ;
- ele2->pos[1] = st[1][1] ;
- ele2->pos[2] = st[1][2] ;
+ ele2->pos[0] = st[1][0];
+ ele2->pos[1] = st[1][1];
+ ele2->pos[2] = st[1][2];
- ele1->next = ele2 ;
- ele2->next = NULL ;
+ ele1->next = ele2;
+ ele2->next = NULL;
- PathList* lst = new PathList ;
- lst->head = ele1 ;
- lst->tail = ele2 ;
- lst->length = 2 ;
- lst->next = paths ;
- paths = lst ;
+ PathList* lst = new PathList;
+ lst->head = ele1;
+ lst->tail = ele2;
+ lst->length = 2;
+ lst->next = paths;
+ paths = lst;
- // int l = ( dimen >> maxDepth ) ;
+ // int l =(dimen >> maxDepth);
}
}
}
-void Octree::combinePaths( PathList*& list1, PathList* list2, PathList* paths, PathList*& rings )
+void Octree::combinePaths(PathList*& list1, PathList* list2, PathList* paths, PathList*& rings)
{
// Make new list of paths
- PathList* nlist = NULL ;
+ PathList* nlist = NULL;
// Search for each connectors in paths
- PathList* tpaths = paths ;
- PathList* tlist, * pre ;
- while ( tpaths )
+ PathList* tpaths = paths;
+ PathList* tlist, * pre;
+ while(tpaths)
{
- PathList* singlist = tpaths ;
- PathList* templist ;
- tpaths = tpaths->next ;
- singlist->next = NULL ;
+ PathList* singlist = tpaths;
+ PathList* templist;
+ tpaths = tpaths->next;
+ singlist->next = NULL;
// Look for hookup in list1
- tlist = list1 ;
- pre = NULL ;
- while ( tlist )
+ tlist = list1;
+ pre = NULL;
+ while(tlist)
{
- if ( (templist = combineSinglePath( list1, pre, tlist, singlist, NULL, singlist )) != NULL )
+ if((templist = combineSinglePath(list1, pre, tlist, singlist, NULL, singlist)) != NULL)
{
- singlist = templist ;
- continue ;
+ singlist = templist;
+ continue;
}
- pre = tlist ;
- tlist = tlist->next ;
+ pre = tlist;
+ tlist = tlist->next;
}
// Look for hookup in list2
- tlist = list2 ;
- pre = NULL ;
- while ( tlist )
+ tlist = list2;
+ pre = NULL;
+ while(tlist)
{
- if ( (templist = combineSinglePath( list2, pre, tlist, singlist, NULL, singlist )) != NULL )
+ if((templist = combineSinglePath(list2, pre, tlist, singlist, NULL, singlist)) != NULL)
{
- singlist = templist ;
- continue ;
+ singlist = templist;
+ continue;
}
- pre = tlist ;
- tlist = tlist->next ;
+ pre = tlist;
+ tlist = tlist->next;
}
// Look for hookup in nlist
- tlist = nlist ;
- pre = NULL ;
- while ( tlist )
+ tlist = nlist;
+ pre = NULL;
+ while(tlist)
{
- if ( (templist = combineSinglePath( nlist, pre, tlist, singlist, NULL, singlist )) != NULL )
+ if((templist = combineSinglePath(nlist, pre, tlist, singlist, NULL, singlist)) != NULL)
{
- singlist = templist ;
- continue ;
+ singlist = templist;
+ continue;
}
- pre = tlist ;
- tlist = tlist->next ;
+ pre = tlist;
+ tlist = tlist->next;
}
// Add to nlist or rings
- if ( isEqual( singlist->head, singlist->tail ) )
+ if(isEqual(singlist->head, singlist->tail))
{
- PathElement* temp = singlist->head ;
- singlist->head = temp->next ;
- delete temp ;
- singlist->length -- ;
- singlist->tail->next = singlist->head ;
-
- singlist->next = rings ;
- rings = singlist ;
+ PathElement* temp = singlist->head;
+ singlist->head = temp->next;
+ delete temp;
+ singlist->length --;
+ singlist->tail->next = singlist->head;
+
+ singlist->next = rings;
+ rings = singlist;
}
else
{
- singlist->next = nlist ;
- nlist = singlist ;
+ singlist->next = nlist;
+ nlist = singlist;
}
}
// Append list2 and nlist to the end of list1
- tlist = list1 ;
- if ( tlist != NULL )
+ tlist = list1;
+ if(tlist != NULL)
{
- while ( tlist->next != NULL )
+ while(tlist->next != NULL)
{
- tlist = tlist->next ;
+ tlist = tlist->next;
}
- tlist->next = list2 ;
+ tlist->next = list2;
}
else
{
- tlist = list2 ;
- list1 = list2 ;
+ tlist = list2;
+ list1 = list2;
}
- if ( tlist != NULL )
+ if(tlist != NULL)
{
- while ( tlist->next != NULL )
+ while(tlist->next != NULL)
{
- tlist = tlist->next ;
+ tlist = tlist->next;
}
- tlist->next = nlist ;
+ tlist->next = nlist;
}
else
{
- tlist = nlist ;
- list1 = nlist ;
+ tlist = nlist;
+ list1 = nlist;
}
}
-PathList* Octree::combineSinglePath( PathList*& head1, PathList* pre1, PathList*& list1, PathList*& head2, PathList* pre2, PathList*& list2 )
+PathList* Octree::combineSinglePath(PathList*& head1, PathList* pre1, PathList*& list1, PathList*& head2, PathList* pre2, PathList*& list2)
{
- if ( isEqual( list1->head, list2->head ) || isEqual( list1->tail, list2->tail ) )
+ if(isEqual(list1->head, list2->head) || isEqual(list1->tail, list2->tail))
{
// Reverse the list
- if ( list1->length < list2->length )
+ if(list1->length < list2->length)
{
// Reverse list1
- PathElement* prev = list1->head ;
- PathElement* next = prev->next ;
- prev->next = NULL ;
- while ( next != NULL )
+ PathElement* prev = list1->head;
+ PathElement* next = prev->next;
+ prev->next = NULL;
+ while(next != NULL)
{
- PathElement* tnext = next->next ;
- next->next = prev ;
+ PathElement* tnext = next->next;
+ next->next = prev;
- prev = next ;
- next = tnext ;
+ prev = next;
+ next = tnext;
}
- list1->tail = list1->head ;
- list1->head = prev ;
+ list1->tail = list1->head;
+ list1->head = prev;
}
else
{
// Reverse list2
- PathElement* prev = list2->head ;
- PathElement* next = prev->next ;
- prev->next = NULL ;
- while ( next != NULL )
+ PathElement* prev = list2->head;
+ PathElement* next = prev->next;
+ prev->next = NULL;
+ while(next != NULL)
{
- PathElement* tnext = next->next ;
- next->next = prev ;
+ PathElement* tnext = next->next;
+ next->next = prev;
- prev = next ;
- next = tnext ;
+ prev = next;
+ next = tnext;
}
- list2->tail = list2->head ;
- list2->head = prev ;
+ list2->tail = list2->head;
+ list2->head = prev;
}
}
- if ( isEqual( list1->head, list2->tail ) )
+ if(isEqual(list1->head, list2->tail))
{
// Easy case
- PathElement* temp = list1->head->next ;
- delete list1->head ;
- list2->tail->next = temp ;
+ PathElement* temp = list1->head->next;
+ delete list1->head;
+ list2->tail->next = temp;
- PathList* nlist = new PathList ;
- nlist->length = list1->length + list2->length - 1 ;
- nlist->head = list2->head ;
- nlist->tail = list1->tail ;
- nlist->next = NULL ;
+ PathList* nlist = new PathList;
+ nlist->length = list1->length + list2->length - 1;
+ nlist->head = list2->head;
+ nlist->tail = list1->tail;
+ nlist->next = NULL;
- deletePath( head1, pre1, list1 ) ;
- deletePath( head2, pre2, list2 ) ;
+ deletePath(head1, pre1, list1);
+ deletePath(head2, pre2, list2);
- return nlist ;
+ return nlist;
}
- else if ( isEqual( list1->tail, list2->head ) )
+ else if(isEqual(list1->tail, list2->head))
{
// Easy case
- PathElement* temp = list2->head->next ;
- delete list2->head ;
- list1->tail->next = temp ;
+ PathElement* temp = list2->head->next;
+ delete list2->head;
+ list1->tail->next = temp;
- PathList* nlist = new PathList ;
- nlist->length = list1->length + list2->length - 1 ;
- nlist->head = list1->head ;
- nlist->tail = list2->tail ;
- nlist->next = NULL ;
+ PathList* nlist = new PathList;
+ nlist->length = list1->length + list2->length - 1;
+ nlist->head = list1->head;
+ nlist->tail = list2->tail;
+ nlist->next = NULL;
- deletePath( head1, pre1, list1 ) ;
- deletePath( head2, pre2, list2 ) ;
+ deletePath(head1, pre1, list1);
+ deletePath(head2, pre2, list2);
- return nlist ;
+ return nlist;
}
- return NULL ;
+ return NULL;
}
-void Octree::deletePath( PathList*& head, PathList* pre, PathList*& curr )
+void Octree::deletePath(PathList*& head, PathList* pre, PathList*& curr)
{
- PathList* temp = curr ;
- curr = temp->next ;
- delete temp ;
+ PathList* temp = curr;
+ curr = temp->next;
+ delete temp;
- if ( pre == NULL )
+ if(pre == NULL)
{
- head = curr ;
+ head = curr;
}
else
{
- pre->next = curr ;
+ pre->next = curr;
}
}
-void Octree::printElement( PathElement* ele )
+void Octree::printElement(PathElement* ele)
{
- if ( ele != NULL )
+ if(ele != NULL)
{
- dc_printf( " (%d %d %d)", ele->pos[0], ele->pos[1], ele->pos[2] ) ;
+ dc_printf("(%d %d %d)", ele->pos[0], ele->pos[1], ele->pos[2]);
}
}
-void Octree::printPath( PathList* path )
+void Octree::printPath(PathList* path)
{
PathElement* n = path->head;
- int same = 0 ;
+ int same = 0;
#if DC_DEBUG
- int len = ( dimen >> maxDepth ) ;
+ int len =(dimen >> maxDepth);
#endif
- while ( n && ( same == 0 || n != path->head ) )
+ while(n &&(same == 0 || n != path->head))
{
- same ++ ;
- dc_printf( " (%d %d %d)", n->pos[0] / len, n->pos[1] / len, n->pos[2] / len ) ;
- n = n->next ;
+ same ++;
+ dc_printf("(%d %d %d)", n->pos[0] / len, n->pos[1] / len, n->pos[2] / len);
+ n = n->next;
}
- if ( n == path->head )
+ if(n == path->head)
{
- dc_printf(" Ring!\n") ;
+ dc_printf(" Ring!\n");
}
else
{
- dc_printf(" %p end!\n", n) ;
+ dc_printf(" %p end!\n", n);
}
}
-void Octree::printPath( PathElement* path )
+void Octree::printPath(PathElement* path)
{
PathElement *n = path;
- int same = 0 ;
+ int same = 0;
#if DC_DEBUG
- int len = ( dimen >> maxDepth ) ;
+ int len =(dimen >> maxDepth);
#endif
- while ( n && ( same == 0 || n != path ) )
+ while(n &&(same == 0 || n != path))
{
- same ++ ;
- dc_printf( " (%d %d %d)", n->pos[0] / len, n->pos[1] / len, n->pos[2] / len ) ;
- n = n->next ;
+ same ++;
+ dc_printf("(%d %d %d)", n->pos[0] / len, n->pos[1] / len, n->pos[2] / len);
+ n = n->next;
}
- if ( n == path )
+ if(n == path)
{
- dc_printf(" Ring!\n") ;
+ dc_printf(" Ring!\n");
}
else
{
- dc_printf(" %p end!\n", n) ;
+ dc_printf(" %p end!\n", n);
}
}
-void Octree::printPaths( PathList* path )
+void Octree::printPaths(PathList* path)
{
- PathList* iter = path ;
- int i = 0 ;
- while ( iter != NULL )
+ PathList* iter = path;
+ int i = 0;
+ while(iter != NULL)
{
- dc_printf("Path %d:\n", i) ;
- printPath( iter ) ;
- iter = iter->next ;
- i ++ ;
+ dc_printf("Path %d:\n", i);
+ printPath(iter);
+ iter = iter->next;
+ i ++;
}
}
-UCHAR* Octree::patch( UCHAR* node, int st[3], int len, PathList* rings )
+Node* Octree::patch(Node* newnode, int st[3], int len, PathList* rings)
{
#ifdef IN_DEBUG_MODE
dc_printf("Call to PATCH with rings: \n");
- printPaths( rings ) ;
+ printPaths(rings);
#endif
/* Do nothing but couting
- PathList* tlist = rings ;
- PathList* ttlist ;
- PathElement* telem, * ttelem ;
- while ( tlist!= NULL )
+ PathList* tlist = rings;
+ PathList* ttlist;
+ PathElement* telem, * ttelem;
+ while(tlist!= NULL)
{
- // printPath( tlist ) ;
- this->numRings ++ ;
- this->totRingLengths += tlist->length ;
- if ( tlist->length > this->maxRingLength )
+ // printPath(tlist);
+ numRings ++;
+ totRingLengths += tlist->length;
+ if(tlist->length > maxRingLength)
{
- this->maxRingLength = tlist->length ;
+ maxRingLength = tlist->length;
}
- ttlist = tlist ;
- tlist = tlist->next ;
+ ttlist = tlist;
+ tlist = tlist->next;
}
- return node ;
+ return node;
*/
/* Pass onto separate calls in each direction */
- UCHAR* newnode = node ;
- if ( len == mindimen )
+ if(len == mindimen)
{
- dc_printf("Error! should have no list by now.\n") ;
- exit(0) ;
+ dc_printf("Error! should have no list by now.\n");
+ exit(0);
}
// YZ plane
- PathList* xlists[2] ;
- newnode = patchSplit( newnode, st, len, rings, 0, xlists[0], xlists[1] ) ;
+ PathList* xlists[2];
+ newnode = patchSplit(newnode, st, len, rings, 0, xlists[0], xlists[1]);
// XZ plane
- PathList* ylists[4] ;
- newnode = patchSplit( newnode, st, len, xlists[0], 1, ylists[0], ylists[1] ) ;
- newnode = patchSplit( newnode, st, len, xlists[1], 1, ylists[2], ylists[3] ) ;
+ PathList* ylists[4];
+ newnode = patchSplit(newnode, st, len, xlists[0], 1, ylists[0], ylists[1]);
+ newnode = patchSplit(newnode, st, len, xlists[1], 1, ylists[2], ylists[3]);
// XY plane
- PathList* zlists[8] ;
- newnode = patchSplit( newnode, st, len, ylists[0], 2, zlists[0], zlists[1] ) ;
- newnode = patchSplit( newnode, st, len, ylists[1], 2, zlists[2], zlists[3] ) ;
- newnode = patchSplit( newnode, st, len, ylists[2], 2, zlists[4], zlists[5] ) ;
- newnode = patchSplit( newnode, st, len, ylists[3], 2, zlists[6], zlists[7] ) ;
+ PathList* zlists[8];
+ newnode = patchSplit(newnode, st, len, ylists[0], 2, zlists[0], zlists[1]);
+ newnode = patchSplit(newnode, st, len, ylists[1], 2, zlists[2], zlists[3]);
+ newnode = patchSplit(newnode, st, len, ylists[2], 2, zlists[4], zlists[5]);
+ newnode = patchSplit(newnode, st, len, ylists[3], 2, zlists[6], zlists[7]);
// Recur
- len >>= 1 ;
- int count = 0 ;
- for ( int i = 0 ; i < 8 ; i ++ )
+ len >>= 1;
+ int count = 0;
+ for(int i = 0; i < 8; i ++)
{
- if ( zlists[i] != NULL )
+ if(zlists[i] != NULL)
{
- int nori[3] = {
+ int nori[3] = {
st[0] + len * vertmap[i][0] ,
st[1] + len * vertmap[i][1] ,
- st[2] + len * vertmap[i][2] } ;
- patch( getChild( newnode , count ), nori, len, zlists[i] ) ;
+ st[2] + len * vertmap[i][2]};
+ patch(getChild(&newnode->internal , count), nori, len, zlists[i]);
}
- if ( hasChild( newnode, i ) )
+ if(hasChild(&newnode->internal, i))
{
- count ++ ;
+ count ++;
}
}
#ifdef IN_DEBUG_MODE
- dc_printf("Return from PATCH\n") ;
+ dc_printf("Return from PATCH\n");
#endif
- return newnode ;
+ return newnode;
}
-UCHAR* Octree::patchSplit( UCHAR* node, int st[3], int len, PathList* rings, int dir, PathList*& nrings1, PathList*& nrings2 )
+Node* Octree::patchSplit(Node* newnode, int st[3], int len, PathList* rings,
+ int dir, PathList*& nrings1, PathList*& nrings2)
{
#ifdef IN_DEBUG_MODE
dc_printf("Call to PATCHSPLIT with direction %d and rings: \n", dir);
- printPaths( rings ) ;
+ printPaths(rings);
#endif
- UCHAR* newnode = node ;
- nrings1 = NULL ;
- nrings2 = NULL ;
- PathList* tmp ;
- while ( rings != NULL )
+ nrings1 = NULL;
+ nrings2 = NULL;
+ PathList* tmp;
+ while(rings != NULL)
{
// Process this ring
- newnode = patchSplitSingle( newnode, st, len, rings->head, dir, nrings1, nrings2 ) ;
+ newnode = patchSplitSingle(newnode, st, len, rings->head, dir, nrings1, nrings2);
// Delete this ring from the group
- tmp = rings ;
- rings = rings->next ;
- delete tmp ;
+ tmp = rings;
+ rings = rings->next;
+ delete tmp;
}
#ifdef IN_DEBUG_MODE
dc_printf("Return from PATCHSPLIT with \n");
- dc_printf("Rings gourp 1:\n") ;
- printPaths( nrings1 ) ;
- dc_printf("Rings group 2:\n") ;
- printPaths( nrings2 ) ;
+ dc_printf("Rings gourp 1:\n");
+ printPaths(nrings1);
+ dc_printf("Rings group 2:\n");
+ printPaths(nrings2);
#endif
- return newnode ;
+ return newnode;
}
-UCHAR* Octree::patchSplitSingle( UCHAR* node, int st[3], int len, PathElement* head, int dir, PathList*& nrings1, PathList*& nrings2 )
+Node* Octree::patchSplitSingle(Node* newnode, int st[3], int len, PathElement* head, int dir, PathList*& nrings1, PathList*& nrings2)
{
#ifdef IN_DEBUG_MODE
- dc_printf("Call to PATCHSPLITSINGLE with direction %d and path: \n", dir );
- printPath( head ) ;
+ dc_printf("Call to PATCHSPLITSINGLE with direction %d and path: \n", dir);
+ printPath(head);
#endif
- UCHAR* newnode = node ;
-
- if ( head == NULL )
+ if(head == NULL)
{
#ifdef IN_DEBUG_MODE
- dc_printf("Return from PATCHSPLITSINGLE with head==NULL.\n") ;
+ dc_printf("Return from PATCHSPLITSINGLE with head==NULL.\n");
#endif
return newnode;
}
else
{
- // printPath( head ) ;
+ // printPath(head);
}
// Walk along the ring to find pair of intersections
- PathElement* pre1 = NULL ;
- PathElement* pre2 = NULL ;
- int side = findPair ( head, st[ dir ] + len / 2 , dir, pre1, pre2 ) ;
+ PathElement* pre1 = NULL;
+ PathElement* pre2 = NULL;
+ int side = findPair(head, st[dir] + len / 2 , dir, pre1, pre2);
/*
- if ( pre1 == pre2 )
+ if(pre1 == pre2)
{
- int edgelen = ( dimen >> maxDepth ) ;
- dc_printf("Location: %d %d %d Direction: %d Reso: %d\n", st[0]/edgelen, st[1]/edgelen, st[2]/edgelen, dir, len/edgelen) ;
- printPath( head ) ;
- exit( 0 ) ;
+ int edgelen =(dimen >> maxDepth);
+ dc_printf("Location: %d %d %d Direction: %d Reso: %d\n", st[0]/edgelen, st[1]/edgelen, st[2]/edgelen, dir, len/edgelen);
+ printPath(head);
+ exit(0);
}
*/
- if ( side )
+ if(side)
{
// Entirely on one side
- PathList* nring = new PathList( ) ;
- nring->head = head ;
+ PathList* nring = new PathList();
+ nring->head = head;
- if ( side == -1 )
+ if(side == -1)
{
- nring->next = nrings1 ;
- nrings1 = nring ;
+ nring->next = nrings1;
+ nrings1 = nring;
}
else
{
- nring->next = nrings2 ;
- nrings2 = nring ;
+ nring->next = nrings2;
+ nrings2 = nring;
}
}
else
{
// Break into two parts
- PathElement* nxt1 = pre1->next ;
- PathElement* nxt2 = pre2->next ;
- pre1->next = nxt2 ;
- pre2->next = nxt1 ;
+ PathElement* nxt1 = pre1->next;
+ PathElement* nxt2 = pre2->next;
+ pre1->next = nxt2;
+ pre2->next = nxt1;
- newnode = connectFace( newnode, st, len, dir, pre1, pre2 ) ;
+ newnode = connectFace(newnode, st, len, dir, pre1, pre2);
- if ( isEqual( pre1, pre1->next ) )
+ if(isEqual(pre1, pre1->next))
{
- if ( pre1 == pre1->next )
+ if(pre1 == pre1->next)
{
- delete pre1 ;
- pre1 = NULL ;
+ delete pre1;
+ pre1 = NULL;
}
else
{
- PathElement* temp = pre1->next ;
- pre1->next = temp->next ;
- delete temp ;
+ PathElement* temp = pre1->next;
+ pre1->next = temp->next;
+ delete temp;
}
}
- if ( isEqual( pre2, pre2->next ) )
+ if(isEqual(pre2, pre2->next))
{
- if ( pre2 == pre2->next )
+ if(pre2 == pre2->next)
{
- delete pre2 ;
- pre2 = NULL ;
+ delete pre2;
+ pre2 = NULL;
}
else
{
- PathElement* temp = pre2->next ;
- pre2->next = temp->next ;
- delete temp ;
+ PathElement* temp = pre2->next;
+ pre2->next = temp->next;
+ delete temp;
}
}
- compressRing ( pre1 ) ;
- compressRing ( pre2 ) ;
+ compressRing(pre1);
+ compressRing(pre2);
// Recur
- newnode = patchSplitSingle( newnode, st, len, pre1, dir, nrings1, nrings2 ) ;
- newnode = patchSplitSingle( newnode, st, len, pre2, dir, nrings1, nrings2 ) ;
+ newnode = patchSplitSingle(newnode, st, len, pre1, dir, nrings1, nrings2);
+ newnode = patchSplitSingle(newnode, st, len, pre2, dir, nrings1, nrings2);
}
#ifdef IN_DEBUG_MODE
dc_printf("Return from PATCHSPLITSINGLE with \n");
- dc_printf("Rings gourp 1:\n") ;
- printPaths( nrings1 ) ;
- dc_printf("Rings group 2:\n") ;
- printPaths( nrings2 ) ;
+ dc_printf("Rings gourp 1:\n");
+ printPaths(nrings1);
+ dc_printf("Rings group 2:\n");
+ printPaths(nrings2);
#endif
- return newnode ;
+ return newnode;
}
-UCHAR* Octree::connectFace( UCHAR* node, int st[3], int len, int dir, PathElement* f1, PathElement* f2 )
+Node* Octree::connectFace(Node* newnode, int st[3], int len, int dir,
+ PathElement* f1, PathElement* f2)
{
#ifdef IN_DEBUG_MODE
- dc_printf("Call to CONNECTFACE with direction %d and length %d path: \n", dir, len );
- dc_printf("Path (low side): \n" ) ;
- printPath( f1 ) ;
-// checkPath( f1 ) ;
- dc_printf("Path (high side): \n" ) ;
- printPath( f2 ) ;
-// checkPath( f2 ) ;
+ dc_printf("Call to CONNECTFACE with direction %d and length %d path: \n", dir, len);
+ dc_printf("Path(low side): \n");
+ printPath(f1);
+// checkPath(f1);
+ dc_printf("Path(high side): \n");
+ printPath(f2);
+// checkPath(f2);
#endif
- UCHAR* newnode = node ;
-
// Setup 2D
- int pos = st[ dir ] + len / 2 ;
- int xdir = ( dir + 1 ) % 3 ;
- int ydir = ( dir + 2 ) % 3 ;
+ int pos = st[dir] + len / 2;
+ int xdir =(dir + 1) % 3;
+ int ydir =(dir + 2) % 3;
// Use existing intersections on f1 and f2
- int x1, y1, x2, y2 ;
- float p1, q1, p2, q2 ;
+ int x1, y1, x2, y2;
+ float p1, q1, p2, q2;
- getFacePoint( f2->next, dir, x1, y1, p1, q1 ) ;
- getFacePoint( f2, dir, x2, y2, p2, q2 ) ;
+ getFacePoint(f2->next, dir, x1, y1, p1, q1);
+ getFacePoint(f2, dir, x2, y2, p2, q2);
- float dx = x2 + p2 - x1 - p1 ;
- float dy = y2 + q2 - y1 - q1 ;
+ float dx = x2 + p2 - x1 - p1;
+ float dy = y2 + q2 - y1 - q1;
// Do adapted Bresenham line drawing
- float rx = p1, ry = q1 ;
- int incx = 1, incy = 1 ;
- int lx = x1, ly = y1 ;
- int hx = x2, hy = y2 ;
- int choice ;
- if ( x2 < x1 )
+ float rx = p1, ry = q1;
+ int incx = 1, incy = 1;
+ int lx = x1, ly = y1;
+ int hx = x2, hy = y2;
+ int choice;
+ if(x2 < x1)
{
- incx = -1 ;
- rx = 1 - rx ;
- lx = x2 ;
- hx = x1 ;
+ incx = -1;
+ rx = 1 - rx;
+ lx = x2;
+ hx = x1;
}
- if ( y2 < y1 )
+ if(y2 < y1)
{
- incy = -1 ;
- ry = 1 - ry ;
- ly = y2 ;
- hy = y1 ;
+ incy = -1;
+ ry = 1 - ry;
+ ly = y2;
+ hy = y1;
}
- float sx = dx * incx ;
- float sy = dy * incy ;
+ float sx = dx * incx;
+ float sy = dy * incy;
- int ori[3] ;
- ori[ dir ] = pos / mindimen ;
- ori[ xdir ] = x1 ;
- ori[ ydir ] = y1 ;
- int walkdir ;
- int inc ;
- float alpha ;
-
- PathElement* curEleN = f1 ;
- PathElement* curEleP = f2->next ;
- UCHAR *nodeN = NULL, *nodeP = NULL ;
- UCHAR *curN = locateLeaf( newnode, len, f1->pos ) ;
- UCHAR *curP = locateLeaf( newnode, len, f2->next->pos ) ;
- if ( curN == NULL || curP == NULL )
- {
- exit(0) ;
- }
- int stN[3], stP[3] ;
- int lenN, lenP ;
+ int ori[3];
+ ori[dir] = pos / mindimen;
+ ori[xdir] = x1;
+ ori[ydir] = y1;
+ int walkdir;
+ int inc;
+ float alpha;
+
+ PathElement* curEleN = f1;
+ PathElement* curEleP = f2->next;
+ Node *nodeN = NULL, *nodeP = NULL;
+ LeafNode *curN = locateLeaf(&newnode->internal, len, f1->pos);
+ LeafNode *curP = locateLeaf(&newnode->internal, len, f2->next->pos);
+ if(curN == NULL || curP == NULL)
+ {
+ exit(0);
+ }
+ int stN[3], stP[3];
+ int lenN, lenP;
/* Unused code, leaving for posterity
- float stpt[3], edpt[3] ;
- stpt[ dir ] = edpt[ dir ] = (float) pos ;
- stpt[ xdir ] = ( x1 + p1 ) * mindimen ;
- stpt[ ydir ] = ( y1 + q1 ) * mindimen ;
- edpt[ xdir ] = ( x2 + p2 ) * mindimen ;
- edpt[ ydir ] = ( y2 + q2 ) * mindimen ;
+ float stpt[3], edpt[3];
+ stpt[dir] = edpt[dir] =(float) pos;
+ stpt[xdir] =(x1 + p1) * mindimen;
+ stpt[ydir] =(y1 + q1) * mindimen;
+ edpt[xdir] =(x2 + p2) * mindimen;
+ edpt[ydir] =(y2 + q2) * mindimen;
*/
- while( ori[ xdir ] != x2 || ori[ ydir ] != y2 )
+ while(ori[xdir] != x2 || ori[ydir] != y2)
{
- int next ;
- if ( sy * (1 - rx) > sx * (1 - ry) )
+ int next;
+ if(sy *(1 - rx) > sx *(1 - ry))
{
- choice = 1 ;
- next = ori[ ydir ] + incy ;
- if ( next < ly || next > hy )
+ choice = 1;
+ next = ori[ydir] + incy;
+ if(next < ly || next > hy)
{
- choice = 4 ;
- next = ori[ xdir ] + incx ;
+ choice = 4;
+ next = ori[xdir] + incx;
}
}
else
{
- choice = 2 ;
- next = ori[ xdir ] + incx ;
- if ( next < lx || next > hx )
+ choice = 2;
+ next = ori[xdir] + incx;
+ if(next < lx || next > hx)
{
- choice = 3 ;
- next = ori[ ydir ] + incy ;
+ choice = 3;
+ next = ori[ydir] + incy;
}
}
- if ( choice & 1 )
+ if(choice & 1)
{
- ori[ ydir ] = next ;
- if ( choice == 1 )
+ ori[ydir] = next;
+ if(choice == 1)
{
- rx += ( sy == 0 ? 0 : (1 - ry) * sx / sy ) ;
- ry = 0 ;
+ rx +=(sy == 0 ? 0 :(1 - ry) * sx / sy );
+ ry = 0;
}
- walkdir = 2 ;
- inc = incy ;
- alpha = x2 < x1 ? 1 - rx : rx ;
+ walkdir = 2;
+ inc = incy;
+ alpha = x2 < x1 ? 1 - rx : rx;
}
else
{
- ori[ xdir ] = next ;
- if ( choice == 2 )
+ ori[xdir] = next;
+ if(choice == 2)
{
- ry += ( sx == 0 ? 0 : (1 - rx) * sy / sx ) ;
- rx = 0 ;
+ ry +=(sx == 0 ? 0 :(1 - rx) * sy / sx);
+ rx = 0;
}
- walkdir = 1 ;
- inc = incx ;
- alpha = y2 < y1 ? 1 - ry : ry ;
+ walkdir = 1;
+ inc = incx;
+ alpha = y2 < y1 ? 1 - ry : ry;
}
// Get the exact location of the marcher
- int nori[3] = { ori[0] * mindimen, ori[1] * mindimen, ori[2] * mindimen } ;
- float spt[3] = { (float) nori[0], (float) nori[1], (float) nori[2] } ;
- spt[ ( dir + ( 3 - walkdir ) ) % 3 ] += alpha * mindimen ;
- if ( inc < 0 )
+ int nori[3] = {ori[0] * mindimen, ori[1] * mindimen, ori[2] * mindimen};
+ float spt[3] = {(float) nori[0],(float) nori[1],(float) nori[2]};
+ spt[(dir +(3 - walkdir)) % 3] += alpha * mindimen;
+ if(inc < 0)
{
- spt[ ( dir + walkdir ) % 3 ] += mindimen ;
+ spt[(dir + walkdir) % 3] += mindimen;
}
- // dc_printf("new x,y: %d %d\n", ori[ xdir ] / edgelen, ori[ ydir ] / edgelen ) ;
- // dc_printf("nori: %d %d %d alpha: %f walkdir: %d\n", nori[0], nori[1], nori[2], alpha, walkdir ) ;
- // dc_printf("%f %f %f\n", spt[0], spt[1], spt[2] ) ;
+ // dc_printf("new x,y: %d %d\n", ori[xdir] / edgelen, ori[ydir] / edgelen);
+ // dc_printf("nori: %d %d %d alpha: %f walkdir: %d\n", nori[0], nori[1], nori[2], alpha, walkdir);
+ // dc_printf("%f %f %f\n", spt[0], spt[1], spt[2]);
// Locate the current cells on both sides
- newnode = locateCell( newnode, st, len, nori, dir, 1, nodeN, stN, lenN ) ;
- newnode = locateCell( newnode, st, len, nori, dir, 0, nodeP, stP, lenP ) ;
+ newnode = locateCell(&newnode->internal, st, len, nori, dir, 1, nodeN, stN, lenN);
+ newnode = locateCell(&newnode->internal, st, len, nori, dir, 0, nodeP, stP, lenP);
- updateParent( newnode, len, st ) ;
+ updateParent(&newnode->internal, len, st);
- int flag = 0 ;
+ int flag = 0;
// Add the cells to the rings and fill in the patch
- PathElement* newEleN ;
- if ( curEleN->pos[0] != stN[0] || curEleN->pos[1] != stN[1] || curEleN->pos[2] != stN[2] )
+ PathElement* newEleN;
+ if(curEleN->pos[0] != stN[0] || curEleN->pos[1] != stN[1] || curEleN->pos[2] != stN[2])
{
- if ( curEleN->next->pos[0] != stN[0] || curEleN->next->pos[1] != stN[1] || curEleN->next->pos[2] != stN[2] )
+ if(curEleN->next->pos[0] != stN[0] || curEleN->next->pos[1] != stN[1] || curEleN->next->pos[2] != stN[2])
{
- newEleN = new PathElement ;
- newEleN->next = curEleN->next ;
- newEleN->pos[0] = stN[0] ;
- newEleN->pos[1] = stN[1] ;
- newEleN->pos[2] = stN[2] ;
+ newEleN = new PathElement;
+ newEleN->next = curEleN->next;
+ newEleN->pos[0] = stN[0];
+ newEleN->pos[1] = stN[1];
+ newEleN->pos[2] = stN[2];
- curEleN->next = newEleN ;
+ curEleN->next = newEleN;
}
else
{
- newEleN = curEleN->next ;
+ newEleN = curEleN->next;
}
- curN = patchAdjacent( newnode, len, curEleN->pos, curN, newEleN->pos, nodeN, walkdir, inc, dir, 1, alpha ) ;
+ curN = patchAdjacent(&newnode->internal, len, curEleN->pos, curN,
+ newEleN->pos, (LeafNode*)nodeN, walkdir,
+ inc, dir, 1, alpha);
- curEleN = newEleN ;
- flag ++ ;
+ curEleN = newEleN;
+ flag ++;
}
- PathElement* newEleP ;
- if ( curEleP->pos[0] != stP[0] || curEleP->pos[1] != stP[1] || curEleP->pos[2] != stP[2] )
+ PathElement* newEleP;
+ if(curEleP->pos[0] != stP[0] || curEleP->pos[1] != stP[1] || curEleP->pos[2] != stP[2])
{
- if ( f2->pos[0] != stP[0] || f2->pos[1] != stP[1] || f2->pos[2] != stP[2] )
+ if(f2->pos[0] != stP[0] || f2->pos[1] != stP[1] || f2->pos[2] != stP[2])
{
- newEleP = new PathElement ;
- newEleP->next = curEleP ;
- newEleP->pos[0] = stP[0] ;
- newEleP->pos[1] = stP[1] ;
- newEleP->pos[2] = stP[2] ;
+ newEleP = new PathElement;
+ newEleP->next = curEleP;
+ newEleP->pos[0] = stP[0];
+ newEleP->pos[1] = stP[1];
+ newEleP->pos[2] = stP[2];
- f2->next = newEleP ;
+ f2->next = newEleP;
}
else
{
- newEleP = f2 ;
+ newEleP = f2;
}
- curP = patchAdjacent( newnode, len, curEleP->pos, curP, newEleP->pos, nodeP, walkdir, inc, dir, 0, alpha ) ;
+ curP = patchAdjacent(&newnode->internal, len, curEleP->pos, curP,
+ newEleP->pos, (LeafNode*)nodeP, walkdir,
+ inc, dir, 0, alpha);
- curEleP = newEleP ;
- flag ++ ;
+ curEleP = newEleP;
+ flag ++;
}
/*
- if ( flag == 0 )
+ if(flag == 0)
{
- dc_printf("error: non-synchronized patching! at \n") ;
+ dc_printf("error: non-synchronized patching! at \n");
}
*/
}
#ifdef IN_DEBUG_MODE
dc_printf("Return from CONNECTFACE with \n");
- dc_printf("Path (low side):\n") ;
- printPath( f1 ) ;
- checkPath( f1 ) ;
- dc_printf("Path (high side):\n") ;
- printPath( f2 ) ;
- checkPath( f2 ) ;
+ dc_printf("Path(low side):\n");
+ printPath(f1);
+ checkPath(f1);
+ dc_printf("Path(high side):\n");
+ printPath(f2);
+ checkPath(f2);
#endif
- return newnode ;
+ return newnode;
}
-UCHAR* Octree::patchAdjacent( UCHAR* node, int len, int st1[3], UCHAR* leaf1, int st2[3], UCHAR* leaf2, int walkdir, int inc, int dir, int side, float alpha )
+LeafNode* Octree::patchAdjacent(InternalNode* node, int len, int st1[3],
+ LeafNode* leaf1, int st2[3], LeafNode* leaf2,
+ int walkdir, int inc, int dir, int side,
+ float alpha)
{
#ifdef IN_DEBUG_MODE
- dc_printf("Before patching.\n") ;
- printInfo( st1 ) ;
- printInfo( st2 ) ;
- dc_printf("-----------------%d %d %d ; %d %d %d\n", st1[0], st2[1], st1[2], st2[0], st2[1], st2[2] ) ;
+ dc_printf("Before patching.\n");
+ printInfo(st1);
+ printInfo(st2);
+ dc_printf("-----------------%d %d %d; %d %d %d\n", st1[0], st2[1], st1[2], st2[0], st2[1], st2[2]);
#endif
// Get edge index on each leaf
- int edgedir = ( dir + ( 3 - walkdir ) ) % 3 ;
- int incdir = ( dir + walkdir ) % 3 ;
- int ind1 = ( edgedir == 1 ? ( dir + 3 - edgedir ) % 3 - 1 : 2 - ( dir + 3 - edgedir ) % 3 ) ;
- int ind2 = ( edgedir == 1 ? ( incdir + 3 - edgedir ) % 3 - 1 : 2 - ( incdir + 3 - edgedir ) % 3 ) ;
+ int edgedir =(dir +(3 - walkdir)) % 3;
+ int incdir =(dir + walkdir) % 3;
+ int ind1 =(edgedir == 1 ?(dir + 3 - edgedir) % 3 - 1 : 2 -(dir + 3 - edgedir) % 3);
+ int ind2 =(edgedir == 1 ?(incdir + 3 - edgedir) % 3 - 1 : 2 -(incdir + 3 - edgedir) % 3);
- int eind1 = ( ( edgedir << 2 ) | ( side << ind1 ) | ( ( inc > 0 ? 1 : 0 ) << ind2 ) ) ;
- int eind2 = ( ( edgedir << 2 ) | ( side << ind1 ) | ( ( inc > 0 ? 0 : 1 ) << ind2 ) ) ;
+ int eind1 =((edgedir << 2) |(side << ind1) |((inc > 0 ? 1 : 0) << ind2));
+ int eind2 =((edgedir << 2) |(side << ind1) |((inc > 0 ? 0 : 1) << ind2));
#ifdef IN_DEBUG_MODE
- dc_printf("Index 1: %d Alpha 1: %f Index 2: %d Alpha 2: %f\n", eind1, alpha, eind2, alpha ) ;
+ dc_printf("Index 1: %d Alpha 1: %f Index 2: %d Alpha 2: %f\n", eind1, alpha, eind2, alpha);
/*
- if ( alpha < 0 || alpha > 1 )
+ if(alpha < 0 || alpha > 1)
{
- dc_printf("Index 1: %d Alpha 1: %f Index 2: %d Alpha 2: %f\n", eind1, alpha, eind2, alpha ) ;
- printInfo( st1 ) ;
- printInfo( st2 ) ;
+ dc_printf("Index 1: %d Alpha 1: %f Index 2: %d Alpha 2: %f\n", eind1, alpha, eind2, alpha);
+ printInfo(st1);
+ printInfo(st2);
}
*/
#endif
// Flip edge parity
- UCHAR* nleaf1 = flipEdge( leaf1, eind1, alpha ) ;
- UCHAR* nleaf2 = flipEdge( leaf2, eind2, alpha ) ;
+ LeafNode* nleaf1 = flipEdge(leaf1, eind1, alpha);
+ LeafNode* nleaf2 = flipEdge(leaf2, eind2, alpha);
// Update parent link
- updateParent( node, len, st1, nleaf1 ) ;
- updateParent( node, len, st2, nleaf2 ) ;
- // updateParent( nleaf1, mindimen, st1 ) ;
- // updateParent( nleaf2, mindimen, st2 ) ;
+ updateParent(node, len, st1, nleaf1);
+ updateParent(node, len, st2, nleaf2);
+ // updateParent(nleaf1, mindimen, st1);
+ // updateParent(nleaf2, mindimen, st2);
/*
- float m[3] ;
- dc_printf("Adding new point: %f %f %f\n", spt[0], spt[1], spt[2] ) ;
- getMinimizer( leaf1, m ) ;
- dc_printf("Cell %d now has minimizer %f %f %f\n", leaf1, m[0], m[1], m[2] ) ;
- getMinimizer( leaf2, m ) ;
- dc_printf("Cell %d now has minimizer %f %f %f\n", leaf2, m[0], m[1], m[2] ) ;
+ float m[3];
+ dc_printf("Adding new point: %f %f %f\n", spt[0], spt[1], spt[2]);
+ getMinimizer(leaf1, m);
+ dc_printf("Cell %d now has minimizer %f %f %f\n", leaf1, m[0], m[1], m[2]);
+ getMinimizer(leaf2, m);
+ dc_printf("Cell %d now has minimizer %f %f %f\n", leaf2, m[0], m[1], m[2]);
*/
#ifdef IN_DEBUG_MODE
- dc_printf("After patching.\n") ;
- printInfo( st1 ) ;
- printInfo( st2 ) ;
+ dc_printf("After patching.\n");
+ printInfo(st1);
+ printInfo(st2);
#endif
- return nleaf2 ;
+ return nleaf2;
}
-UCHAR* Octree::locateCell( UCHAR* node, int st[3], int len, int ori[3], int dir, int side, UCHAR*& rleaf, int rst[3], int& rlen )
+Node* Octree::locateCell(InternalNode* node, int st[3], int len, int ori[3], int dir, int side, Node*& rleaf, int rst[3], int& rlen)
{
#ifdef IN_DEBUG_MODE
- // dc_printf("Call to LOCATECELL with node ") ;
- // printNode( node ) ;
+ // dc_printf("Call to LOCATECELL with node ");
+ // printNode(node);
#endif
- UCHAR* newnode = node ;
- int i ;
- len >>= 1 ;
- int ind = 0 ;
- for ( i = 0 ; i < 3 ; i ++ )
+
+ int i;
+ len >>= 1;
+ int ind = 0;
+ for(i = 0; i < 3; i ++)
{
- ind <<= 1 ;
- if ( i == dir && side == 1 )
+ ind <<= 1;
+ if(i == dir && side == 1)
{
- ind |= ( ori[ i ] <= ( st[ i ] + len ) ? 0 : 1 ) ;
+ ind |=(ori[i] <=(st[i] + len) ? 0 : 1);
}
else
{
- ind |= ( ori[ i ] < ( st[ i ] + len ) ? 0 : 1 ) ;
+ ind |=(ori[i] <(st[i] + len) ? 0 : 1);
}
}
#ifdef IN_DEBUG_MODE
- // dc_printf("In LOCATECELL index of ori (%d %d %d) with dir %d side %d in st (%d %d %d, %d) is: %d\n",
- // ori[0], ori[1], ori[2], dir, side, st[0], st[1], st[2], len, ind ) ;
+ // dc_printf("In LOCATECELL index of ori(%d %d %d) with dir %d side %d in st(%d %d %d, %d) is: %d\n",
+ // ori[0], ori[1], ori[2], dir, side, st[0], st[1], st[2], len, ind);
#endif
- rst[0] = st[0] + vertmap[ ind ][ 0 ] * len ;
- rst[1] = st[1] + vertmap[ ind ][ 1 ] * len ;
- rst[2] = st[2] + vertmap[ ind ][ 2 ] * len ;
+ rst[0] = st[0] + vertmap[ind][0] * len;
+ rst[1] = st[1] + vertmap[ind][1] * len;
+ rst[2] = st[2] + vertmap[ind][2] * len;
- if ( hasChild( newnode, ind ) )
+ if(hasChild(node, ind))
{
- int count = getChildCount( newnode, ind ) ;
- UCHAR* chd = getChild( newnode, count ) ;
- if ( isLeaf( newnode, ind ) )
+ int count = getChildCount(node, ind);
+ Node* chd = getChild(node, count);
+ if(isLeaf(node, ind))
{
- rleaf = chd ;
- rlen = len ;
+ rleaf = chd;
+ rlen = len;
}
else
{
// Recur
- setChild( newnode, count, locateCell( chd, rst, len, ori, dir, side, rleaf, rst, rlen ) ) ;
+ setChild(node, count, locateCell(&chd->internal, rst, len, ori, dir, side, rleaf, rst, rlen));
}
}
else
{
// Create a new child here
- if ( len == this->mindimen )
+ if(len == mindimen)
{
- UCHAR* chd = createLeaf( 0 ) ;
- newnode = addChild( newnode, ind, chd, 1 ) ;
- rleaf = chd ;
- rlen = len ;
+ LeafNode* chd = createLeaf(0);
+ node = addChild(node, ind, (Node*)chd, 1);
+ rleaf = (Node*)chd;
+ rlen = len;
}
else
{
// Subdivide the empty cube
- UCHAR* chd = createInternal( 0 ) ;
- newnode = addChild( newnode, ind, locateCell( chd, rst, len, ori, dir, side, rleaf, rst, rlen ), 0 ) ;
+ InternalNode* chd = createInternal(0);
+ node = addChild(node, ind,
+ locateCell(chd, rst, len, ori, dir, side, rleaf, rst, rlen), 0);
}
}
#ifdef IN_DEBUG_MODE
- // dc_printf("Return from LOCATECELL with node ") ;
- // printNode( newnode ) ;
+ // dc_printf("Return from LOCATECELL with node ");
+ // printNode(newnode);
#endif
- return newnode ;
+ return (Node*)node;
}
-void Octree::checkElement( PathElement* ele )
+void Octree::checkElement(PathElement* ele)
{
/*
- if ( ele != NULL && locateLeafCheck( ele->pos ) != ele->node )
+ if(ele != NULL && locateLeafCheck(ele->pos) != ele->node)
{
dc_printf("Screwed! at pos: %d %d %d\n", ele->pos[0]>>minshift, ele->pos[1]>>minshift, ele->pos[2]>>minshift);
- exit( 0 ) ;
+ exit(0);
}
*/
}
-void Octree::checkPath( PathElement* path )
+void Octree::checkPath(PathElement* path)
{
- PathElement *n = path ;
- int same = 0 ;
- while ( n && ( same == 0 || n != path ) )
+ PathElement *n = path;
+ int same = 0;
+ while(n &&(same == 0 || n != path))
{
- same ++ ;
- checkElement( n ) ;
- n = n->next ;
+ same ++;
+ checkElement(n);
+ n = n->next;
}
}
-void Octree::testFacePoint( PathElement* e1, PathElement* e2 )
+void Octree::testFacePoint(PathElement* e1, PathElement* e2)
{
- int i ;
- PathElement * e = NULL ;
- for ( i = 0 ; i < 3 ; i ++ )
+ int i;
+ PathElement * e = NULL;
+ for(i = 0; i < 3; i ++)
{
- if ( e1->pos[i] != e2->pos[i] )
+ if(e1->pos[i] != e2->pos[i])
{
- if ( e1->pos[i] < e2->pos[i] )
+ if(e1->pos[i] < e2->pos[i])
{
- e = e2 ;
+ e = e2;
}
else
{
- e = e1 ;
+ e = e1;
}
- break ;
+ break;
}
}
- int x, y ;
- float p, q ;
- dc_printf("Test.") ;
- getFacePoint( e, i, x, y, p, q ) ;
+ int x, y;
+ float p, q;
+ dc_printf("Test.");
+ getFacePoint(e, i, x, y, p, q);
}
-void Octree::getFacePoint( PathElement* leaf, int dir, int& x, int& y, float& p, float& q )
+void Octree::getFacePoint(PathElement* leaf, int dir, int& x, int& y, float& p, float& q)
{
// Find average intersections
- float avg[3] = {0, 0, 0} ;
- float off[3] ;
- int num = 0, num2 = 0 ;
+ float avg[3] = {0, 0, 0};
+ float off[3];
+ int num = 0, num2 = 0;
- UCHAR* leafnode = locateLeaf( leaf->pos ) ;
- for ( int i = 0 ; i < 4 ; i ++ )
+ LeafNode* leafnode = locateLeaf(leaf->pos);
+ for(int i = 0; i < 4; i ++)
{
- int edgeind = faceMap[ dir * 2 ][ i ] ;
- int nst[3] ;
- for ( int j = 0 ; j < 3 ; j ++ )
+ int edgeind = faceMap[dir * 2][i];
+ int nst[3];
+ for(int j = 0; j < 3; j ++)
{
- nst[j] = leaf->pos[j] + mindimen * vertmap[ edgemap[ edgeind][ 0 ] ][ j ] ;
+ nst[j] = leaf->pos[j] + mindimen * vertmap[edgemap[edgeind][0]][j];
}
- if ( getEdgeIntersectionByIndex( nst, edgeind / 4, off, 1 ) )
+ if(getEdgeIntersectionByIndex(nst, edgeind / 4, off, 1))
{
- avg[0] += off[0] ;
- avg[1] += off[1] ;
- avg[2] += off[2] ;
- num ++ ;
+ avg[0] += off[0];
+ avg[1] += off[1];
+ avg[2] += off[2];
+ num ++;
}
- if ( getEdgeParity( leafnode, edgeind ) )
+ if(getEdgeParity(leafnode, edgeind))
{
- num2 ++ ;
+ num2 ++;
}
}
- if ( num == 0 )
+ if(num == 0)
{
dc_printf("Wrong! dir: %d pos: %d %d %d num: %d\n", dir, leaf->pos[0]>>minshift, leaf->pos[1]>>minshift, leaf->pos[2]>>minshift, num2);
- avg[0] = (float) leaf->pos[0] ;
- avg[1] = (float) leaf->pos[1] ;
- avg[2] = (float) leaf->pos[2] ;
+ avg[0] =(float) leaf->pos[0];
+ avg[1] =(float) leaf->pos[1];
+ avg[2] =(float) leaf->pos[2];
}
else
{
- avg[0] /= num ;
- avg[1] /= num ;
- avg[2] /= num ;
+ avg[0] /= num;
+ avg[1] /= num;
+ avg[2] /= num;
- //avg[0] = (float) leaf->pos[0];
- //avg[1] = (float) leaf->pos[1];
- //avg[2] = (float) leaf->pos[2];
+ //avg[0] =(float) leaf->pos[0];
+ //avg[1] =(float) leaf->pos[1];
+ //avg[2] =(float) leaf->pos[2];
}
- int xdir = ( dir + 1 ) % 3 ;
- int ydir = ( dir + 2 ) % 3 ;
+ int xdir =(dir + 1) % 3;
+ int ydir =(dir + 2) % 3;
- float xf = avg[ xdir ] ;
- float yf = avg[ ydir ] ;
+ float xf = avg[xdir];
+ float yf = avg[ydir];
#ifdef IN_DEBUG_MODE
// Is it outside?
- // PathElement* leaf = leaf1->len < leaf2->len ? leaf1 : leaf2 ;
+ // PathElement* leaf = leaf1->len < leaf2->len ? leaf1 : leaf2;
/*
- float* m = ( leaf == leaf1 ? m1 : m2 ) ;
- if ( xf < leaf->pos[ xdir ] ||
- yf < leaf->pos[ ydir ] ||
- xf > leaf->pos[ xdir ] + leaf->len ||
- yf > leaf->pos[ ydir ] + leaf->len)
+ float* m =(leaf == leaf1 ? m1 : m2);
+ if(xf < leaf->pos[xdir] ||
+ yf < leaf->pos[ydir] ||
+ xf > leaf->pos[xdir] + leaf->len ||
+ yf > leaf->pos[ydir] + leaf->len)
{
- dc_printf("Outside cube (%d %d %d), %d : %d %d %f %f\n", leaf->pos[ 0 ], leaf->pos[1], leaf->pos[2], leaf->len,
- pos, dir, xf, yf) ;
+ dc_printf("Outside cube(%d %d %d), %d : %d %d %f %f\n", leaf->pos[0], leaf->pos[1], leaf->pos[2], leaf->len,
+ pos, dir, xf, yf);
// For now, snap to cell
- xf = m[ xdir ] ;
- yf = m[ ydir ] ;
+ xf = m[xdir];
+ yf = m[ydir];
}
*/
/*
- if ( alpha < 0 || alpha > 1 ||
+ if(alpha < 0 || alpha > 1 ||
xf < leaf->pos[xdir] || xf > leaf->pos[xdir] + leaf->len ||
- yf < leaf->pos[ydir] || yf > leaf->pos[ydir] + leaf->len )
+ yf < leaf->pos[ydir] || yf > leaf->pos[ydir] + leaf->len)
{
- dc_printf("Alpha: %f Address: %d and %d\n", alpha, leaf1->node, leaf2->node ) ;
- dc_printf("GETFACEPOINT result: (%d %d %d) %d min: (%f %f %f) ;(%d %d %d) %d min: (%f %f %f).\n",
+ dc_printf("Alpha: %f Address: %d and %d\n", alpha, leaf1->node, leaf2->node);
+ dc_printf("GETFACEPOINT result:(%d %d %d) %d min:(%f %f %f);(%d %d %d) %d min:(%f %f %f).\n",
leaf1->pos[0], leaf1->pos[1], leaf1->pos[2], leaf1->len, m1[0], m1[1], m1[2],
leaf2->pos[0], leaf2->pos[1], leaf2->pos[2], leaf2->len, m2[0], m2[1], m2[2]);
- dc_printf("Face point at dir %d pos %d: %f %f\n", dir, pos, xf, yf ) ;
+ dc_printf("Face point at dir %d pos %d: %f %f\n", dir, pos, xf, yf);
}
*/
#endif
// Get the integer and float part
- x = ( ( leaf->pos[ xdir ] ) >> minshift ) ;
- y = ( ( leaf->pos[ ydir ] ) >> minshift ) ;
+ x =((leaf->pos[xdir]) >> minshift);
+ y =((leaf->pos[ydir]) >> minshift);
- p = ( xf - leaf->pos[ xdir ] ) / mindimen ;
- q = ( yf - leaf->pos[ ydir ] ) / mindimen ;
+ p =(xf - leaf->pos[xdir]) / mindimen;
+ q =(yf - leaf->pos[ydir]) / mindimen;
#ifdef IN_DEBUG_MODE
- dc_printf("Face point at dir %d : %f %f\n", dir, xf, yf ) ;
+ dc_printf("Face point at dir %d : %f %f\n", dir, xf, yf);
#endif
}
-int Octree::findPair( PathElement* head, int pos, int dir, PathElement*& pre1, PathElement*& pre2 )
+int Octree::findPair(PathElement* head, int pos, int dir, PathElement*& pre1, PathElement*& pre2)
{
- int side = getSide ( head, pos, dir ) ;
- PathElement* cur = head ;
- PathElement* anchor ;
- PathElement* ppre1, *ppre2 ;
+ int side = getSide(head, pos, dir);
+ PathElement* cur = head;
+ PathElement* anchor;
+ PathElement* ppre1, *ppre2;
// Start from this face, find a pair
- anchor = cur ;
- ppre1 = cur ;
- cur = cur->next ;
- while ( cur != anchor && ( getSide( cur, pos, dir ) == side ) )
+ anchor = cur;
+ ppre1 = cur;
+ cur = cur->next;
+ while(cur != anchor &&(getSide(cur, pos, dir) == side))
{
- ppre1 = cur ;
- cur = cur->next ;
+ ppre1 = cur;
+ cur = cur->next;
}
- if ( cur == anchor )
+ if(cur == anchor)
{
// No pair found
- return side ;
+ return side;
}
- side = getSide( cur, pos, dir ) ;
- ppre2 = cur ;
- cur = cur->next ;
- while ( getSide( cur, pos, dir ) == side )
+ side = getSide(cur, pos, dir);
+ ppre2 = cur;
+ cur = cur->next;
+ while(getSide(cur, pos, dir) == side)
{
- ppre2 = cur ;
- cur = cur->next ;
+ ppre2 = cur;
+ cur = cur->next;
}
// Switch pre1 and pre2 if we start from the higher side
- if ( side == -1 )
+ if(side == -1)
{
- cur = ppre1 ;
- ppre1 = ppre2 ;
- ppre2 = cur ;
+ cur = ppre1;
+ ppre1 = ppre2;
+ ppre2 = cur;
}
- pre1 = ppre1 ;
- pre2 = ppre2 ;
+ pre1 = ppre1;
+ pre2 = ppre2;
- return 0 ;
+ return 0;
}
-int Octree::getSide( PathElement* e, int pos, int dir )
+int Octree::getSide(PathElement* e, int pos, int dir)
{
- return ( e->pos[ dir ] < pos ? -1 : 1 ) ;
+ return (e->pos[dir] < pos ? -1 : 1);
}
-int Octree::isEqual( PathElement* e1, PathElement* e2 )
+int Octree::isEqual(PathElement* e1, PathElement* e2)
{
- return ( e1->pos[0] == e2->pos[0] && e1->pos[1] == e2->pos[1] && e1->pos[2] == e2->pos[2] ) ;
+ return (e1->pos[0] == e2->pos[0] && e1->pos[1] == e2->pos[1] && e1->pos[2] == e2->pos[2]);
}
-void Octree::compressRing( PathElement*& ring )
+void Octree::compressRing(PathElement*& ring)
{
- if ( ring == NULL )
+ if(ring == NULL)
{
- return ;
+ return;
}
#ifdef IN_DEBUG_MODE
- dc_printf("Call to COMPRESSRING with path: \n" );
- printPath( ring ) ;
+ dc_printf("Call to COMPRESSRING with path: \n");
+ printPath(ring);
#endif
- PathElement* cur = ring->next->next ;
- PathElement* pre = ring->next ;
- PathElement* prepre = ring ;
- PathElement* anchor = prepre ;
+ PathElement* cur = ring->next->next;
+ PathElement* pre = ring->next;
+ PathElement* prepre = ring;
+ PathElement* anchor = prepre;
do
{
- while ( isEqual( cur, prepre ) )
+ while(isEqual(cur, prepre))
{
// Delete
- if ( cur == prepre )
+ if(cur == prepre)
{
// The ring has shrinked to a point
- delete pre ;
- delete cur ;
- anchor = NULL ;
- break ;
+ delete pre;
+ delete cur;
+ anchor = NULL;
+ break;
}
else
{
- prepre->next = cur->next ;
- delete pre ;
- delete cur ;
- pre = prepre->next ;
- cur = pre->next ;
- anchor = prepre ;
+ prepre->next = cur->next;
+ delete pre;
+ delete cur;
+ pre = prepre->next;
+ cur = pre->next;
+ anchor = prepre;
}
}
- if ( anchor == NULL )
+ if(anchor == NULL)
{
- break ;
+ break;
}
- prepre = pre ;
- pre = cur ;
- cur = cur->next ;
- } while ( prepre != anchor ) ;
+ prepre = pre;
+ pre = cur;
+ cur = cur->next;
+ } while(prepre != anchor);
- ring = anchor ;
+ ring = anchor;
#ifdef IN_DEBUG_MODE
- dc_printf("Return from COMPRESSRING with path: \n" );
- printPath( ring ) ;
+ dc_printf("Return from COMPRESSRING with path: \n");
+ printPath(ring);
#endif
}
-void Octree::buildSigns( )
+void Octree::buildSigns()
{
// First build a lookup table
- // dc_printf("Building up look up table...\n") ;
- int size = 1 << 12 ;
- unsigned char table[ 1 << 12 ] ;
- for ( int i = 0 ; i < size ; i ++ )
+ // dc_printf("Building up look up table...\n");
+ int size = 1 << 12;
+ unsigned char table[1 << 12];
+ for(int i = 0; i < size; i ++)
{
- table[i] = 0 ;
+ table[i] = 0;
}
- for ( int i = 0 ; i < 256 ; i ++ )
+ for(int i = 0; i < 256; i ++)
{
- int ind = 0 ;
- for ( int j = 11 ; j >= 0 ; j -- )
+ int ind = 0;
+ for(int j = 11; j >= 0; j --)
{
- ind <<= 1 ;
- if ( ( ( i >> edgemap[j][0] ) & 1 ) ^ ( ( i >> edgemap[j][1] ) & 1 ) )
+ ind <<= 1;
+ if(((i >> edgemap[j][0]) & 1) ^((i >> edgemap[j][1]) & 1))
{
- ind |= 1 ;
+ ind |= 1;
}
}
- table[ ind ] = i ;
+ table[ind] = i;
}
// Next, traverse the grid
- int sg = 1 ;
- int cube[8] ;
- buildSigns( table, this->root, 0, sg, cube ) ;
+ int sg = 1;
+ int cube[8];
+ buildSigns(table, root, 0, sg, cube);
}
-void Octree::buildSigns( unsigned char table[], UCHAR* node, int isLeaf, int sg, int rvalue[8] )
+void Octree::buildSigns(unsigned char table[], Node* node, int isLeaf, int sg, int rvalue[8])
{
- if ( node == NULL )
+ if(node == NULL)
{
- for ( int i = 0 ; i < 8 ; i ++ )
+ for(int i = 0; i < 8; i ++)
{
- rvalue[i] = sg ;
+ rvalue[i] = sg;
}
- return ;
+ return;
}
- if ( isLeaf == 0 )
+ if(isLeaf == 0)
{
// Internal node
- UCHAR* chd[8] ;
- int leaf[8] ;
- fillChildren( node, chd, leaf ) ;
+ Node* chd[8];
+ int leaf[8];
+ fillChildren(&node->internal, chd, leaf);
// Get the signs at the corners of the first cube
- rvalue[0] = sg ;
- int oris[8] ;
- buildSigns( table, chd[0], leaf[0], sg, oris ) ;
+ rvalue[0] = sg;
+ int oris[8];
+ buildSigns(table, chd[0], leaf[0], sg, oris);
// Get the rest
- int cube[8] ;
- for ( int i = 1 ; i < 8 ; i ++ )
+ int cube[8];
+ for(int i = 1; i < 8; i ++)
{
- buildSigns( table, chd[i], leaf[i], oris[i], cube ) ;
- rvalue[i] = cube[i] ;
+ buildSigns(table, chd[i], leaf[i], oris[i], cube);
+ rvalue[i] = cube[i];
}
}
else
{
// Leaf node
- generateSigns( node, table, sg ) ;
+ generateSigns(&node->leaf, table, sg);
- for ( int i = 0 ; i < 8 ; i ++ )
+ for(int i = 0; i < 8; i ++)
{
- rvalue[i] = getSign( node, i ) ;
+ rvalue[i] = getSign(&node->leaf, i);
}
}
}
-void Octree::floodFill( )
+void Octree::floodFill()
{
- // int threshold = (int) ((dimen/mindimen) * (dimen/mindimen) * 0.5f) ;
- int st[3] = { 0, 0, 0 } ;
+ // int threshold =(int)((dimen/mindimen) *(dimen/mindimen) * 0.5f);
+ int st[3] = {0, 0, 0};
// First, check for largest component
// size stored in -threshold
- this->clearProcessBits( root, maxDepth ) ;
- int threshold = this->floodFill( root, st, dimen, maxDepth, 0 ) ;
+ clearProcessBits(root, maxDepth);
+ int threshold = floodFill(root, st, dimen, maxDepth, 0);
// Next remove
dc_printf("Largest component: %d\n", threshold);
- threshold *= thresh ;
- dc_printf("Removing all components smaller than %d\n", threshold) ;
+ threshold *= thresh;
+ dc_printf("Removing all components smaller than %d\n", threshold);
- int st2[3] = { 0, 0, 0 } ;
- this->clearProcessBits( root, maxDepth ) ;
- this->floodFill( root, st2, dimen, maxDepth, threshold ) ;
+ int st2[3] = {0, 0, 0};
+ clearProcessBits(root, maxDepth);
+ floodFill(root, st2, dimen, maxDepth, threshold);
}
-void Octree::clearProcessBits( UCHAR* node, int height )
+void Octree::clearProcessBits(Node* node, int height)
{
int i;
- if ( height == 0 )
+ if(height == 0)
{
// Leaf cell,
- for ( i = 0 ; i < 12 ; i ++ )
+ for(i = 0; i < 12; i ++)
{
- setOutProcess( node, i ) ;
+ setOutProcess(&node->leaf, i);
}
}
else
{
// Internal cell, recur
- int count = 0 ;
- for ( i = 0 ; i < 8 ; i ++ )
+ int count = 0;
+ for(i = 0; i < 8; i ++)
{
- if ( hasChild( node, i ) )
+ if(hasChild(&node->internal, i))
{
- clearProcessBits( getChild( node, count ), height - 1 ) ;
- count ++ ;
+ clearProcessBits(getChild(&node->internal, count), height - 1);
+ count ++;
}
}
}
}
-/*
-void Octree::floodFill( UCHAR* node, int st[3], int len, int height, int threshold )
+int Octree::floodFill(LeafNode* leaf, int st[3], int len, int height, int threshold)
{
int i, j;
-
- if ( height == 0 )
- {
- // Leaf cell,
- int par, inp ;
-
- // Test if the leaf has intersection edges
- for ( i = 0 ; i < 12 ; i ++ )
- {
- par = getEdgeParity( node, i ) ;
- inp = isInProcess( node, i ) ;
-
- if ( par == 1 && inp == 0 )
- {
- // Intersection edge, hasn't been processed
- // Let's start filling
- GridQueue* queue = new GridQueue() ;
- int total = 1 ;
-
- // Set to in process
- int mst[3] ;
- mst[0] = st[0] + vertmap[edgemap[i][0]][0] * len ;
- mst[1] = st[1] + vertmap[edgemap[i][0]][1] * len ;
- mst[2] = st[2] + vertmap[edgemap[i][0]][2] * len;
- int mdir = i / 4 ;
- setInProcessAll( mst, mdir ) ;
-
- // Put this edge into queue
- queue->pushQueue( mst, mdir ) ;
-
- // Queue processing
- int nst[3], dir ;
- while ( queue->popQueue( nst, dir ) == 1 )
- {
- // dc_printf("nst: %d %d %d, dir: %d\n", nst[0]/mindimen, nst[1]/mindimen, nst[2]/mindimen, dir) ;
- // locations
- int stMask[3][3] = {
- { 0, 0 - len, 0 - len },
- { 0 - len, 0, 0 - len },
- { 0 - len, 0 - len, 0 }
- };
- int cst[2][3] ;
- for ( j = 0 ; j < 3 ; j ++ )
- {
- cst[0][j] = nst[j] ;
- cst[1][j] = nst[j] + stMask[ dir ][ j ] ;
- }
-
- // cells
- UCHAR* cs[2] ;
- for ( j = 0 ; j < 2 ; j ++ )
- {
- cs[ j ] = locateLeaf( cst[j] ) ;
- }
-
- // Middle sign
- int s = getSign( cs[0], 0 ) ;
-
- // Masks
- int fcCells[4] = {1,0,1,0};
- int fcEdges[3][4][3] = {
- {{9,2,11},{8,1,10},{5,1,7},{4,2,6}},
- {{10,6,11},{8,5,9},{1,5,3},{0,6,2}},
- {{6,10,7},{4,9,5},{2,9,3},{0,10,1}}
- };
-
- // Search for neighboring connected intersection edges
- for ( int find = 0 ; find < 4 ; find ++ )
- {
- int cind = fcCells[find] ;
- int eind, edge ;
- if ( s == 0 )
- {
- // Original order
- for ( eind = 0 ; eind < 3 ; eind ++ )
- {
- edge = fcEdges[dir][find][eind] ;
- if ( getEdgeParity( cs[cind], edge ) == 1 )
- {
- break ;
- }
- }
- }
- else
- {
- // Inverse order
- for ( eind = 2 ; eind >= 0 ; eind -- )
- {
- edge = fcEdges[dir][find][eind] ;
- if ( getEdgeParity( cs[cind], edge ) == 1 )
- {
- break ;
- }
- }
- }
-
- if ( eind == 3 || eind == -1 )
- {
- dc_printf("Wrong! this is not a consistent sign. %d\n", eind );
- }
- else
- {
- int est[3] ;
- est[0] = cst[cind][0] + vertmap[edgemap[edge][0]][0] * len ;
- est[1] = cst[cind][1] + vertmap[edgemap[edge][0]][1] * len ;
- est[2] = cst[cind][2] + vertmap[edgemap[edge][0]][2] * len ;
- int edir = edge / 4 ;
-
- if ( isInProcess( cs[cind], edge ) == 0 )
- {
- setInProcessAll( est, edir ) ;
- queue->pushQueue( est, edir ) ;
- // dc_printf("Pushed: est: %d %d %d, edir: %d\n", est[0]/len, est[1]/len, est[2]/len, edir) ;
- total ++ ;
- }
- else
- {
- // dc_printf("Processed, not pushed: est: %d %d %d, edir: %d\n", est[0]/len, est[1]/len, est[2]/len, edir) ;
- }
- }
-
- }
-
+ int maxtotal = 0;
+
+ // Leaf cell,
+ int par, inp;
+
+ // Test if the leaf has intersection edges
+ for(i = 0; i < 12; i ++) {
+ par = getEdgeParity(leaf, i);
+ inp = isInProcess(leaf, i);
+
+ if(par == 1 && inp == 0) {
+ // Intersection edge, hasn't been processed
+ // Let's start filling
+ GridQueue* queue = new GridQueue();
+ int total = 1;
+
+ // Set to in process
+ int mst[3];
+ mst[0] = st[0] + vertmap[edgemap[i][0]][0] * len;
+ mst[1] = st[1] + vertmap[edgemap[i][0]][1] * len;
+ mst[2] = st[2] + vertmap[edgemap[i][0]][2] * len;
+ int mdir = i / 4;
+ setInProcessAll(mst, mdir);
+
+ // Put this edge into queue
+ queue->pushQueue(mst, mdir);
+
+ // Queue processing
+ int nst[3], dir;
+ while(queue->popQueue(nst, dir) == 1) {
+ // dc_printf("nst: %d %d %d, dir: %d\n", nst[0]/mindimen, nst[1]/mindimen, nst[2]/mindimen, dir);
+ // locations
+ int stMask[3][3] = {
+ {0, 0 - len, 0 - len},
+ {0 - len, 0, 0 - len},
+ {0 - len, 0 - len, 0}
+ };
+ int cst[2][3];
+ for(j = 0; j < 3; j ++) {
+ cst[0][j] = nst[j];
+ cst[1][j] = nst[j] + stMask[dir][j];
}
- dc_printf("Size of component: %d ", total) ;
-
- if ( total > threshold )
- {
- dc_printf("Maintained.\n") ;
- continue ;
+ // cells
+ LeafNode* cs[2];
+ for(j = 0; j < 2; j ++) {
+ cs[j] = locateLeaf(cst[j]);
}
- dc_printf("Less then %d, removing...\n", threshold) ;
-
- // We have to remove this noise
-
- // Flip parity
- // setOutProcessAll( mst, mdir ) ;
- flipParityAll( mst, mdir ) ;
-
- // Put this edge into queue
- queue->pushQueue( mst, mdir ) ;
-
- // Queue processing
- while ( queue->popQueue( nst, dir ) == 1 )
- {
- // dc_printf("nst: %d %d %d, dir: %d\n", nst[0]/mindimen, nst[1]/mindimen, nst[2]/mindimen, dir) ;
- // locations
- int stMask[3][3] = {
- { 0, 0 - len, 0 - len },
- { 0 - len, 0, 0 - len },
- { 0 - len, 0 - len, 0 }
- };
- int cst[2][3] ;
- for ( j = 0 ; j < 3 ; j ++ )
- {
- cst[0][j] = nst[j] ;
- cst[1][j] = nst[j] + stMask[ dir ][ j ] ;
- }
- // cells
- UCHAR* cs[2] ;
- for ( j = 0 ; j < 2 ; j ++ )
- {
- cs[ j ] = locateLeaf( cst[j] ) ;
- }
-
- // Middle sign
- int s = getSign( cs[0], 0 ) ;
-
- // Masks
- int fcCells[4] = {1,0,1,0};
- int fcEdges[3][4][3] = {
- {{9,2,11},{8,1,10},{5,1,7},{4,2,6}},
- {{10,6,11},{8,5,9},{1,5,3},{0,6,2}},
- {{6,10,7},{4,9,5},{2,9,3},{0,10,1}}
- };
-
- // Search for neighboring connected intersection edges
- for ( int find = 0 ; find < 4 ; find ++ )
- {
- int cind = fcCells[find] ;
- int eind, edge ;
- if ( s == 0 )
- {
- // Original order
- for ( eind = 0 ; eind < 3 ; eind ++ )
- {
- edge = fcEdges[dir][find][eind] ;
- if ( isInProcess( cs[cind], edge ) == 1 )
- {
- break ;
- }
- }
- }
- else
- {
- // Inverse order
- for ( eind = 2 ; eind >= 0 ; eind -- )
- {
- edge = fcEdges[dir][find][eind] ;
- if ( isInProcess( cs[cind], edge ) == 1 )
- {
- break ;
- }
- }
- }
-
- if ( eind == 3 || eind == -1 )
- {
- dc_printf("Wrong! this is not a consistent sign. %d\n", eind );
- }
- else
- {
- int est[3] ;
- est[0] = cst[cind][0] + vertmap[edgemap[edge][0]][0] * len ;
- est[1] = cst[cind][1] + vertmap[edgemap[edge][0]][1] * len ;
- est[2] = cst[cind][2] + vertmap[edgemap[edge][0]][2] * len ;
- int edir = edge / 4 ;
-
- if ( getEdgeParity( cs[cind], edge ) == 1 )
- {
- flipParityAll( est, edir ) ;
- queue->pushQueue( est, edir ) ;
- // dc_printf("Pushed: est: %d %d %d, edir: %d\n", est[0]/len, est[1]/len, est[2]/len, edir) ;
- total ++ ;
- }
- else
- {
- // dc_printf("Processed, not pushed: est: %d %d %d, edir: %d\n", est[0]/len, est[1]/len, est[2]/len, edir) ;
+ // Middle sign
+ int s = getSign(cs[0], 0);
+
+ // Masks
+ int fcCells[4] = {1,0,1,0};
+ int fcEdges[3][4][3] = {
+ {{9,2,11},{8,1,10},{5,1,7},{4,2,6}},
+ {{10,6,11},{8,5,9},{1,5,3},{0,6,2}},
+ {{6,10,7},{4,9,5},{2,9,3},{0,10,1}}
+ };
+
+ // Search for neighboring connected intersection edges
+ for(int find = 0; find < 4; find ++) {
+ int cind = fcCells[find];
+ int eind, edge;
+ if(s == 0) {
+ // Original order
+ for(eind = 0; eind < 3; eind ++) {
+ edge = fcEdges[dir][find][eind];
+ if(getEdgeParity(cs[cind], edge) == 1) {
+ break;
}
}
-
}
-
- }
-
- }
- }
- }
- else
- {
- // Internal cell, recur
- int count = 0 ;
- len >>= 1 ;
- for ( i = 0 ; i < 8 ; i ++ )
- {
- if ( hasChild( node, i ) )
- {
- int nst[3] ;
- nst[0] = st[0] + vertmap[i][0] * len ;
- nst[1] = st[1] + vertmap[i][1] * len ;
- nst[2] = st[2] + vertmap[i][2] * len ;
-
- floodFill( getChild( node, count ), nst, len, height - 1, threshold ) ;
- count ++ ;
- }
- }
- }
-}
-*/
-
-int Octree::floodFill( UCHAR* node, int st[3], int len, int height, int threshold )
-{
- int i, j;
- int maxtotal = 0 ;
-
- if ( height == 0 )
- {
- // Leaf cell,
- int par, inp ;
-
- // Test if the leaf has intersection edges
- for ( i = 0 ; i < 12 ; i ++ )
- {
- par = getEdgeParity( node, i ) ;
- inp = isInProcess( node, i ) ;
-
- if ( par == 1 && inp == 0 )
- {
- // Intersection edge, hasn't been processed
- // Let's start filling
- GridQueue* queue = new GridQueue() ;
- int total = 1 ;
-
- // Set to in process
- int mst[3] ;
- mst[0] = st[0] + vertmap[edgemap[i][0]][0] * len ;
- mst[1] = st[1] + vertmap[edgemap[i][0]][1] * len ;
- mst[2] = st[2] + vertmap[edgemap[i][0]][2] * len;
- int mdir = i / 4 ;
- setInProcessAll( mst, mdir ) ;
-
- // Put this edge into queue
- queue->pushQueue( mst, mdir ) ;
-
- // Queue processing
- int nst[3], dir ;
- while ( queue->popQueue( nst, dir ) == 1 )
- {
- // dc_printf("nst: %d %d %d, dir: %d\n", nst[0]/mindimen, nst[1]/mindimen, nst[2]/mindimen, dir) ;
- // locations
- int stMask[3][3] = {
- { 0, 0 - len, 0 - len },
- { 0 - len, 0, 0 - len },
- { 0 - len, 0 - len, 0 }
- };
- int cst[2][3] ;
- for ( j = 0 ; j < 3 ; j ++ )
- {
- cst[0][j] = nst[j] ;
- cst[1][j] = nst[j] + stMask[ dir ][ j ] ;
- }
-
- // cells
- UCHAR* cs[2] ;
- for ( j = 0 ; j < 2 ; j ++ )
- {
- cs[ j ] = locateLeaf( cst[j] ) ;
- }
-
- // Middle sign
- int s = getSign( cs[0], 0 ) ;
-
- // Masks
- int fcCells[4] = {1,0,1,0};
- int fcEdges[3][4][3] = {
- {{9,2,11},{8,1,10},{5,1,7},{4,2,6}},
- {{10,6,11},{8,5,9},{1,5,3},{0,6,2}},
- {{6,10,7},{4,9,5},{2,9,3},{0,10,1}}
- };
-
- // Search for neighboring connected intersection edges
- for ( int find = 0 ; find < 4 ; find ++ )
- {
- int cind = fcCells[find] ;
- int eind, edge ;
- if ( s == 0 )
- {
- // Original order
- for ( eind = 0 ; eind < 3 ; eind ++ )
- {
- edge = fcEdges[dir][find][eind] ;
- if ( getEdgeParity( cs[cind], edge ) == 1 )
- {
- break ;
- }
- }
- }
- else
- {
- // Inverse order
- for ( eind = 2 ; eind >= 0 ; eind -- )
- {
- edge = fcEdges[dir][find][eind] ;
- if ( getEdgeParity( cs[cind], edge ) == 1 )
- {
- break ;
- }
+ else {
+ // Inverse order
+ for(eind = 2; eind >= 0; eind --) {
+ edge = fcEdges[dir][find][eind];
+ if(getEdgeParity(cs[cind], edge) == 1) {
+ break;
}
}
+ }
- if ( eind == 3 || eind == -1 )
- {
- dc_printf("Wrong! this is not a consistent sign. %d\n", eind );
- }
- else
- {
- int est[3] ;
- est[0] = cst[cind][0] + vertmap[edgemap[edge][0]][0] * len ;
- est[1] = cst[cind][1] + vertmap[edgemap[edge][0]][1] * len ;
- est[2] = cst[cind][2] + vertmap[edgemap[edge][0]][2] * len ;
- int edir = edge / 4 ;
+ if(eind == 3 || eind == -1) {
+ dc_printf("Wrong! this is not a consistent sign. %d\n", eind);
+ }
+ else {
+ int est[3];
+ est[0] = cst[cind][0] + vertmap[edgemap[edge][0]][0] * len;
+ est[1] = cst[cind][1] + vertmap[edgemap[edge][0]][1] * len;
+ est[2] = cst[cind][2] + vertmap[edgemap[edge][0]][2] * len;
+ int edir = edge / 4;
- if ( isInProcess( cs[cind], edge ) == 0 )
- {
- setInProcessAll( est, edir ) ;
- queue->pushQueue( est, edir ) ;
- // dc_printf("Pushed: est: %d %d %d, edir: %d\n", est[0]/len, est[1]/len, est[2]/len, edir) ;
- total ++ ;
- }
- else
- {
- // dc_printf("Processed, not pushed: est: %d %d %d, edir: %d\n", est[0]/len, est[1]/len, est[2]/len, edir) ;
- }
+ if(isInProcess(cs[cind], edge) == 0) {
+ setInProcessAll(est, edir);
+ queue->pushQueue(est, edir);
+ // dc_printf("Pushed: est: %d %d %d, edir: %d\n", est[0]/len, est[1]/len, est[2]/len, edir);
+ total ++;
}
-
}
-
}
+ }
- dc_printf("Size of component: %d ", total) ;
+ dc_printf("Size of component: %d ", total);
- if ( threshold == 0 )
- {
- // Measuring stage
- if ( total > maxtotal )
- {
- maxtotal = total ;
- }
- dc_printf(".\n") ;
- continue ;
+ if(threshold == 0) {
+ // Measuring stage
+ if(total > maxtotal) {
+ maxtotal = total;
}
+ dc_printf(".\n");
+ continue;
+ }
- if ( total >= threshold )
- {
- dc_printf("Maintained.\n") ;
- continue ;
+ if(total >= threshold) {
+ dc_printf("Maintained.\n");
+ continue;
+ }
+ dc_printf("Less then %d, removing...\n", threshold);
+
+ // We have to remove this noise
+
+ // Flip parity
+ // setOutProcessAll(mst, mdir);
+ flipParityAll(mst, mdir);
+
+ // Put this edge into queue
+ queue->pushQueue(mst, mdir);
+
+ // Queue processing
+ while(queue->popQueue(nst, dir) == 1) {
+ // dc_printf("nst: %d %d %d, dir: %d\n", nst[0]/mindimen, nst[1]/mindimen, nst[2]/mindimen, dir);
+ // locations
+ int stMask[3][3] = {
+ {0, 0 - len, 0 - len},
+ {0 - len, 0, 0 - len},
+ {0 - len, 0 - len, 0}
+ };
+ int cst[2][3];
+ for(j = 0; j < 3; j ++) {
+ cst[0][j] = nst[j];
+ cst[1][j] = nst[j] + stMask[dir][j];
}
- dc_printf("Less then %d, removing...\n", threshold) ;
- // We have to remove this noise
-
- // Flip parity
- // setOutProcessAll( mst, mdir ) ;
- flipParityAll( mst, mdir ) ;
-
- // Put this edge into queue
- queue->pushQueue( mst, mdir ) ;
-
- // Queue processing
- while ( queue->popQueue( nst, dir ) == 1 )
- {
- // dc_printf("nst: %d %d %d, dir: %d\n", nst[0]/mindimen, nst[1]/mindimen, nst[2]/mindimen, dir) ;
- // locations
- int stMask[3][3] = {
- { 0, 0 - len, 0 - len },
- { 0 - len, 0, 0 - len },
- { 0 - len, 0 - len, 0 }
- };
- int cst[2][3] ;
- for ( j = 0 ; j < 3 ; j ++ )
- {
- cst[0][j] = nst[j] ;
- cst[1][j] = nst[j] + stMask[ dir ][ j ] ;
- }
-
- // cells
- UCHAR* cs[2] ;
- for ( j = 0 ; j < 2 ; j ++ )
- {
- cs[ j ] = locateLeaf( cst[j] ) ;
- }
-
- // Middle sign
- int s = getSign( cs[0], 0 ) ;
-
- // Masks
- int fcCells[4] = {1,0,1,0};
- int fcEdges[3][4][3] = {
- {{9,2,11},{8,1,10},{5,1,7},{4,2,6}},
- {{10,6,11},{8,5,9},{1,5,3},{0,6,2}},
- {{6,10,7},{4,9,5},{2,9,3},{0,10,1}}
- };
-
- // Search for neighboring connected intersection edges
- for ( int find = 0 ; find < 4 ; find ++ )
- {
- int cind = fcCells[find] ;
- int eind, edge ;
- if ( s == 0 )
- {
- // Original order
- for ( eind = 0 ; eind < 3 ; eind ++ )
- {
- edge = fcEdges[dir][find][eind] ;
- if ( isInProcess( cs[cind], edge ) == 1 )
- {
- break ;
- }
+ // cells
+ LeafNode* cs[2];
+ for(j = 0; j < 2; j ++)
+ cs[j] = locateLeaf(cst[j]);
+
+ // Middle sign
+ int s = getSign(cs[0], 0);
+
+ // Masks
+ int fcCells[4] = {1,0,1,0};
+ int fcEdges[3][4][3] = {
+ {{9,2,11},{8,1,10},{5,1,7},{4,2,6}},
+ {{10,6,11},{8,5,9},{1,5,3},{0,6,2}},
+ {{6,10,7},{4,9,5},{2,9,3},{0,10,1}}
+ };
+
+ // Search for neighboring connected intersection edges
+ for(int find = 0; find < 4; find ++) {
+ int cind = fcCells[find];
+ int eind, edge;
+ if(s == 0) {
+ // Original order
+ for(eind = 0; eind < 3; eind ++) {
+ edge = fcEdges[dir][find][eind];
+ if(isInProcess(cs[cind], edge) == 1) {
+ break;
}
}
- else
- {
- // Inverse order
- for ( eind = 2 ; eind >= 0 ; eind -- )
- {
- edge = fcEdges[dir][find][eind] ;
- if ( isInProcess( cs[cind], edge ) == 1 )
- {
- break ;
- }
+ }
+ else {
+ // Inverse order
+ for(eind = 2; eind >= 0; eind --) {
+ edge = fcEdges[dir][find][eind];
+ if(isInProcess(cs[cind], edge) == 1) {
+ break;
}
}
+ }
- if ( eind == 3 || eind == -1 )
- {
- dc_printf("Wrong! this is not a consistent sign. %d\n", eind );
- }
- else
- {
- int est[3] ;
- est[0] = cst[cind][0] + vertmap[edgemap[edge][0]][0] * len ;
- est[1] = cst[cind][1] + vertmap[edgemap[edge][0]][1] * len ;
- est[2] = cst[cind][2] + vertmap[edgemap[edge][0]][2] * len ;
- int edir = edge / 4 ;
+ if(eind == 3 || eind == -1) {
+ dc_printf("Wrong! this is not a consistent sign. %d\n", eind);
+ }
+ else {
+ int est[3];
+ est[0] = cst[cind][0] + vertmap[edgemap[edge][0]][0] * len;
+ est[1] = cst[cind][1] + vertmap[edgemap[edge][0]][1] * len;
+ est[2] = cst[cind][2] + vertmap[edgemap[edge][0]][2] * len;
+ int edir = edge / 4;
- if ( getEdgeParity( cs[cind], edge ) == 1 )
- {
- flipParityAll( est, edir ) ;
- queue->pushQueue( est, edir ) ;
- // dc_printf("Pushed: est: %d %d %d, edir: %d\n", est[0]/len, est[1]/len, est[2]/len, edir) ;
- total ++ ;
- }
- else
- {
- // dc_printf("Processed, not pushed: est: %d %d %d, edir: %d\n", est[0]/len, est[1]/len, est[2]/len, edir) ;
- }
+ if(getEdgeParity(cs[cind], edge) == 1) {
+ flipParityAll(est, edir);
+ queue->pushQueue(est, edir);
+ // dc_printf("Pushed: est: %d %d %d, edir: %d\n", est[0]/len, est[1]/len, est[2]/len, edir);
+ total ++;
}
-
}
-
}
-
}
}
-
}
- else
- {
- // Internal cell, recur
- int count = 0 ;
- len >>= 1 ;
- for ( i = 0 ; i < 8 ; i ++ )
- {
- if ( hasChild( node, i ) )
- {
- int nst[3] ;
- nst[0] = st[0] + vertmap[i][0] * len ;
- nst[1] = st[1] + vertmap[i][1] * len ;
- nst[2] = st[2] + vertmap[i][2] * len ;
-
- int d = floodFill( getChild( node, count ), nst, len, height - 1, threshold ) ;
- if ( d > maxtotal)
- {
- maxtotal = d ;
- }
- count ++ ;
- }
- }
- }
-
-
- return maxtotal ;
-
-}
-
-void Octree::writeOut()
-{
- int numQuads = 0 ;
- int numVertices = 0 ;
- int numEdges = 0 ;
-#ifdef USE_HERMIT
- countIntersection( root, maxDepth, numQuads, numVertices, numEdges ) ;
-#else
- countIntersection( root, maxDepth, numQuads, numVertices ) ;
- numEdges = numQuads * 3 / 2 ;
-#endif
- dc_printf("Vertices counted: %d Polys counted: %d \n", numVertices, numQuads ) ;
- output_mesh = alloc_output(numVertices, numQuads);
- int offset = 0 ;
- int st[3] = { 0, 0, 0 } ;
-
- // First, output vertices
- offset = 0 ;
- actualVerts = 0 ;
- actualQuads = 0 ;
-#ifdef USE_HERMIT
- generateMinimizer( root, st, dimen, maxDepth, offset ) ;
- cellProcContour( this->root, 0, maxDepth ) ;
- dc_printf("Vertices written: %d Quads written: %d \n", offset, actualQuads ) ;
-#else
- writeVertex( root, st, dimen, maxDepth, offset, out ) ;
- writeQuad( root, st, dimen, maxDepth, out ) ;
- dc_printf("Vertices written: %d Triangles written: %d \n", offset, actualQuads ) ;
-#endif
-}
-
-#if 0
-void Octree::writePLY( char* fname )
-{
- int numQuads = 0 ;
- int numVertices = 0 ;
- int numEdges = 0 ;
-#ifdef USE_HERMIT
- countIntersection( root, maxDepth, numQuads, numVertices, numEdges ) ;
-#else
- countIntersection( root, maxDepth, numQuads, numVertices ) ;
- numEdges = numQuads * 3 / 2 ;
-#endif
- // int euler = numVertices + numQuads - numEdges ;
- // int genus = ( 2 - euler ) / 2 ;
- // dc_printf("%d vertices %d quads %d edges\n", numVertices, numQuads, numEdges ) ;
- // dc_printf("Genus: %d Euler: %d\n", genus, euler ) ;
-
- FILE* fout = fopen ( fname, "wb" ) ;
- dc_printf("Vertices counted: %d Polys counted: %d \n", numVertices, numQuads ) ;
- PLYWriter::writeHeader( fout, numVertices, numQuads ) ;
- int offset = 0 ;
- int st[3] = { 0, 0, 0 } ;
-
- // First, output vertices
- offset = 0 ;
- actualVerts = 0 ;
- actualQuads = 0 ;
-#ifdef USE_HERMIT
- generateMinimizer( root, st, dimen, maxDepth, offset, fout ) ;
-#ifdef TESTMANIFOLD
- testfout = fopen("test.txt", "w");
- fprintf(testfout, "{");
-#endif
- cellProcContour( this->root, 0, maxDepth, fout ) ;
-#ifdef TESTMANIFOLD
- fprintf(testfout, "}");
- fclose( testfout ) ;
-#endif
- dc_printf("Vertices written: %d Quads written: %d \n", offset, actualQuads ) ;
-#else
- writeVertex( root, st, dimen, maxDepth, offset, fout ) ;
- writeQuad( root, st, dimen, maxDepth, fout ) ;
- dc_printf("Vertices written: %d Triangles written: %d \n", offset, actualQuads ) ;
-#endif
-
-
- fclose( fout ) ;
-}
-#endif
-
-void Octree::writeOctree( char* fname )
-{
- FILE* fout = fopen ( fname, "wb" ) ;
- int sized = ( 1 << maxDepth ) ;
- fwrite( &sized, sizeof( int ), 1, fout ) ;
- writeOctree( fout, root, maxDepth ) ;
- dc_printf("Grid dimension: %d\n", sized ) ;
-
-
- fclose( fout ) ;
-}
-void Octree::writeOctree( FILE* fout, UCHAR* node, int depth )
-{
- char type ;
- if ( depth > 0 )
- {
- type = 0 ;
- fwrite( &type, sizeof( char ), 1, fout ) ;
-
- // Get sign at the center
- char sg = (char) getSign( getChild( node, 0 ), depth - 1, 7 - getChildIndex( node, 0 ) ) ;
-
- int t = 0 ;
- for ( int i = 0 ; i < 8 ; i ++ )
- {
- if ( hasChild( node, i ) )
- {
- writeOctree( fout, getChild( node, t ), depth - 1 ) ;
- t ++ ;
- }
- else
- {
- type = 1 ;
- fwrite( &type, sizeof( char ), 1, fout ) ;
- fwrite( &sg, sizeof( char ), 1, fout ) ;
- }
- }
- }
- else
- {
- type = 2 ;
- fwrite( &type, sizeof( char ), 1, fout ) ;
- fwrite( &(node[2]), sizeof ( UCHAR ), 1, fout );
- }
+ return maxtotal;
}
-#ifdef USE_HERMIT
-#if 0
-void Octree::writeOctreeGeom( char* fname )
+int Octree::floodFill(Node* node, int st[3], int len, int height, int threshold)
{
- FILE* fout = fopen ( fname, "wb" ) ;
-
- // Write header
- char header[]="SOG.Format 1.0";
- int nlen = 128 - 4 * 4 - strlen(header) - 1 ;
- char* header2 = new char[ nlen ];
- for ( int i = 0 ; i < nlen ; i ++ )
- {
- header2[i] = '\0';
- }
- fwrite( header, sizeof( char ), strlen(header) + 1, fout ) ;
- fwrite( origin, sizeof( float ), 3, fout ) ;
- fwrite( &range, sizeof( float ), 1, fout ) ;
- fwrite( header2, sizeof( char ), nlen, fout ) ;
-
-
- int sized = ( 1 << maxDepth ) ;
- int st[3] = {0,0,0};
- fwrite( &sized, sizeof( int ), 1, fout ) ;
-
- writeOctreeGeom( fout, root, st, dimen, maxDepth ) ;
- dc_printf("Grid dimension: %d\n", sized ) ;
-
-
- fclose( fout ) ;
-}
-#endif
-void Octree::writeOctreeGeom( FILE* fout, UCHAR* node, int st[3], int len, int depth )
-{
- char type ;
- if ( depth > 0 )
- {
- type = 0 ;
- fwrite( &type, sizeof( char ), 1, fout ) ;
-
- // Get sign at the center
- char sg = (char) getSign( getChild( node, 0 ), depth - 1, 7 - getChildIndex( node, 0 ) ) ;
-
- int t = 0 ;
- len >>= 1 ;
- for ( int i = 0 ; i < 8 ; i ++ )
- {
- if ( hasChild( node, i ) )
- {
- int nst[3] ;
- nst[0] = st[0] + vertmap[i][0] * len ;
- nst[1] = st[1] + vertmap[i][1] * len ;
- nst[2] = st[2] + vertmap[i][2] * len ;
- writeOctreeGeom( fout, getChild( node, t ), nst, len, depth - 1 ) ;
- t ++ ;
- }
- else
- {
- type = 1 ;
- fwrite( &type, sizeof( char ), 1, fout ) ;
- fwrite( &sg, sizeof( char ), 1, fout ) ;
- }
- }
- }
- else
- {
- type = 2 ;
- fwrite( &type, sizeof( char ), 1, fout ) ;
- fwrite( &(node[2]), sizeof ( UCHAR ), 1, fout );
-
- // Compute minimizer
- // First, find minimizer
- float rvalue[3] ;
- rvalue[0] = (float) st[0] + len / 2 ;
- rvalue[1] = (float) st[1] + len / 2 ;
- rvalue[2] = (float) st[2] + len / 2 ;
- computeMinimizer( node, st, len, rvalue ) ;
-
- // Update
- // float flen = len * range / dimen ;
- for ( int j = 0 ; j < 3 ; j ++ )
- {
- rvalue[ j ] = rvalue[ j ] * range / dimen + origin[ j ] ;
- }
-
- fwrite( rvalue, sizeof ( float ), 3, fout );
- }
-}
-#endif
-
-#ifdef USE_HERMIT
-void Octree::writeDCF( char* fname )
-{
- FILE* fout = fopen ( fname, "wb" ) ;
-
- // Writing out version
- char version[10] = "multisign";
- fwrite ( &version, sizeof ( char ), 10, fout );
-
- // Writing out size
- int sized = ( 1 << maxDepth ) ;
- fwrite( &sized, sizeof( int ), 1, fout ) ;
- fwrite( &sized, sizeof( int ), 1, fout ) ;
- fwrite( &sized, sizeof( int ), 1, fout ) ;
-
- int st[3] = {0, 0, 0} ;
- writeDCF( fout, root, maxDepth, st, dimen ) ;
-
- dc_printf("Grid dimension: %d\n", sized ) ;
- fclose( fout ) ;
-}
+ int i;
+ int maxtotal = 0;
-void Octree::writeDCF( FILE* fout, UCHAR* node, int height, int st[3], int len )
-{
- nodetype type ;
- if ( height > 0 )
+ if(height == 0)
{
- type = 0 ;
- len >>= 1 ;
- fwrite( &type, sizeof( nodetype ), 1, fout ) ;
-
- // Get sign at the center
- signtype sg = 1 - (signtype) getSign( getChild( node, 0 ), height - 1, 7 - getChildIndex( node, 0 ) ) ;
-
- int t = 0 ;
- for ( int i = 0 ; i < 8 ; i ++ )
- {
- if ( hasChild( node, i ) )
- {
- int nst[3] ;
- nst[0] = st[0] + vertmap[i][0] * len ;
- nst[1] = st[1] + vertmap[i][1] * len ;
- nst[2] = st[2] + vertmap[i][2] * len ;
-
-
- writeDCF( fout, getChild( node, t ), height - 1, nst, len ) ;
- t ++ ;
- }
- else
- {
- type = 1 ;
- fwrite( &type, sizeof( nodetype ), 1, fout ) ;
- fwrite ( &(sg), sizeof ( signtype ), 1, fout );
- }
- }
+ maxtotal = floodFill(&node->leaf, st, len, height, threshold);
}
else
{
- type = 2 ;
- fwrite( &type, sizeof( nodetype ), 1, fout ) ;
-
- // Write signs
- signtype sgn[8] ;
- for ( int i = 0 ; i < 8 ; i ++ )
- {
- sgn[ i ] = 1 - (signtype) getSign( node, i ) ;
- }
- fwrite (sgn, sizeof (signtype), 8, fout );
-
- // Write edge data
- float pts[12], norms[12][3] ;
- int parity[12] ;
- fillEdgeOffsetsNormals( node, st, len, pts, norms, parity ) ;
-
- numtype zero = 0, one = 1 ;
- for ( int i = 0 ; i < 12 ; i ++ )
+ // Internal cell, recur
+ int count = 0;
+ len >>= 1;
+ for(i = 0; i < 8; i ++)
{
- int par = getEdgeParity( node, i ) ;
- // Let's check first
- if ( par )
- {
- if ( sgn[ edgemap[i][0] ] == sgn[ edgemap[i][1] ] )
- {
- dc_printf("Wrong! Parity: %d Sign: %d %d\n", parity[i], sgn[ edgemap[i][0] ], sgn[ edgemap[i][1] ]);
- exit(0) ;
- }
- if ( parity[ i ] == 0 )
- {
- dc_printf("Wrong! No intersection found.\n");
- exit(0) ;
- }
- fwrite( &one, sizeof ( numtype ) , 1, fout ) ;
- fwrite( &(pts[i]), sizeof( float ), 1, fout ) ;
- fwrite( norms[i], sizeof( float ), 3, fout ) ;
-
- }
- else
+ if(hasChild((InternalNode*)node, i))
{
- if ( sgn[ edgemap[i][0] ] != sgn[ edgemap[i][1] ] )
+ int nst[3];
+ nst[0] = st[0] + vertmap[i][0] * len;
+ nst[1] = st[1] + vertmap[i][1] * len;
+ nst[2] = st[2] + vertmap[i][2] * len;
+
+ int d = floodFill(getChild((InternalNode*)node, count), nst, len, height - 1, threshold);
+ if(d > maxtotal)
{
- dc_printf("Wrong! Parity: %d Sign: %d %d\n", parity[i], sgn[ edgemap[i][0] ], sgn[ edgemap[i][1] ]);
- exit(0) ;
+ maxtotal = d;
}
- fwrite ( &zero, sizeof ( numtype ) , 1, fout );
+ count ++;
}
}
}
-}
-#endif
-
-void Octree::writeOpenEdges( FILE* fout )
-{
- // Total number of rings
- fprintf( fout, "%d\n", numRings ) ;
- dc_printf("Number of rings to write: %d\n", numRings) ;
-
- // Write each ring
- PathList* tlist = ringList ;
- for ( int i = 0 ; i < numRings ; i ++ )
- {
- fprintf(fout, "%d\n", tlist->length) ;
- // dc_printf("Ring length: %d\n", tlist->length ) ;
- PathElement* cur = tlist->head ;
- for ( int j = 0 ; j < tlist->length ; j ++ )
- {
- float cent[3] ;
- float flen = mindimen * range / dimen ;
- for ( int k = 0 ; k < 3 ; k ++ )
- {
- cent[ k ] = cur->pos[ k ] * range / dimen + origin[ k ] + flen / 2 ;
- }
- fprintf(fout, "%f %f %f\n", cent[0], cent[1], cent[2]) ;
- cur = cur->next ;
- }
-
- tlist = tlist->next ;
- }
-}
-#ifndef USE_HERMIT
-void Octree::countIntersection( UCHAR* node, int height, int& nquad, int& nvert )
-{
- if ( height > 0 )
- {
- int total = getNumChildren( node ) ;
- for ( int i = 0 ; i < total ; i ++ )
- {
- countIntersection( getChild( node, i ), height - 1, nquad, nvert ) ;
- }
- }
- else
- {
- int mask = getSignMask( node ) ;
- nvert += getNumEdges2( node ) ;
- nquad += cubes->getNumTriangle( mask ) ;
+ return maxtotal;
- }
}
-void Octree::writeVertex( UCHAR* node, int st[3], int len, int height, int& offset, FILE* fout )
+void Octree::writeOut()
{
- int i ;
-
- if ( height == 0 )
- {
- // Leaf cell, generate
- int emap[] = { 0, 4, 8 } ;
- for ( int i = 0 ; i < 3 ; i ++ )
- {
- if ( getEdgeParity( node, emap[i] ) )
- {
- // Get intersection location
- int count = getEdgeCount( node, i ) ;
- float off = getEdgeOffset( node, count ) ;
-
- float rvalue[3] ;
- rvalue[0] = (float) st[0] ;
- rvalue[1] = (float) st[1] ;
- rvalue[2] = (float) st[2] ;
- rvalue[i] += off * mindimen ;
-
- // Update
- float fnst[3] ;
- float flen = len * range / dimen ;
- for ( int j = 0 ; j < 3 ; j ++ )
- {
- rvalue[ j ] = rvalue[ j ] * range / dimen + origin[ j ] ;
- fnst[ j ] = st[ j ] * range / dimen + origin[ j ] ;
- }
-
- if ( this->outType == 0 )
- {
- fprintf( fout, "%f %f %f\n", rvalue[0], rvalue[1], rvalue[2] ) ;
- }
- else if ( this->outType == 1 )
- {
- PLYWriter::writeVertex( fout, rvalue ) ;
- }
-
- // Store the index
- setEdgeIntersectionIndex( node, count, offset ) ;
- offset ++ ;
- }
- }
+ int numQuads = 0;
+ int numVertices = 0;
+ int numEdges = 0;
- }
- else
- {
- // Internal cell, recur
- int count = 0 ;
- len >>= 1 ;
- for ( i = 0 ; i < 8 ; i ++ )
- {
- if ( hasChild( node, i ) )
- {
- int nst[3] ;
- nst[0] = st[0] + vertmap[i][0] * len ;
- nst[1] = st[1] + vertmap[i][1] * len ;
- nst[2] = st[2] + vertmap[i][2] * len ;
-
- writeVertex( getChild( node, count ), nst, len, height - 1, offset, fout ) ;
- count ++ ;
- }
- }
- }
-}
+ countIntersection(root, maxDepth, numQuads, numVertices, numEdges);
-void Octree::writeQuad( UCHAR* node, int st[3], int len, int height, FILE* fout )
-{
- int i ;
- if ( height == 0 )
- {
- int mask = getSignMask( node ) ;
- int num = cubes->getNumTriangle( mask ) ;
- int indices[12] ;
- fillEdgeIntersectionIndices( node, st, len, indices ) ;
- int einds[3], ind[3] ;
-
- //int flag1 = 0 ;
- //int flag2 = 0 ;
- for ( i = 0 ; i < num ; i ++ )
- {
- int color = 0 ;
- cubes->getTriangle( mask, i, einds ) ;
- // dc_printf("(%d %d %d) ", einds[0], einds[1], einds[2] ) ;
-
- for ( int j = 0 ; j < 3 ; j ++ )
- {
- ind[j] = indices[ einds[j] ] ;
- /*
- if ( ind[j] == 78381 )
- {
- flag1 = 1 ;
- }
- if ( ind[j] == 78384 )
- {
- flag2 = 1 ;
- }
- */
- }
+ dc_printf("Vertices counted: %d Polys counted: %d \n", numVertices, numQuads);
+ output_mesh = alloc_output(numVertices, numQuads);
+ int offset = 0;
+ int st[3] = {0, 0, 0};
- if ( this->outType == 0 )
- {
- // OFF
- int numpoly = ( color ? -3 : 3 ) ;
- fprintf(fout, "%d %d %d %d\n", numpoly, ind[0], ind[1], ind[2] ) ;
- actualQuads ++ ;
- }
- else if ( this->outType == 1 )
- {
- // PLY
- PLYWriter::writeFace( fout, 3, ind ) ;
- actualQuads ++ ;
- }
- }
+ // First, output vertices
+ offset = 0;
+ actualVerts = 0;
+ actualQuads = 0;
- /*
- if (flag1 && flag2)
- {
- dc_printf("%d\n", mask);
- cubes->printTriangles( mask ) ;
- }
- */
- }
- else
- {
- // Internal cell, recur
- int count = 0 ;
- len >>= 1 ;
- for ( i = 0 ; i < 8 ; i ++ )
- {
- if ( hasChild( node, i ) )
- {
- int nst[3] ;
- nst[0] = st[0] + vertmap[i][0] * len ;
- nst[1] = st[1] + vertmap[i][1] * len ;
- nst[2] = st[2] + vertmap[i][2] * len ;
-
- writeQuad( getChild( node, count ), nst, len, height - 1, fout ) ;
- count ++ ;
- }
- }
- }
+ generateMinimizer(root, st, dimen, maxDepth, offset);
+ cellProcContour(root, 0, maxDepth);
+ dc_printf("Vertices written: %d Quads written: %d \n", offset, actualQuads);
}
-#endif
-
-
-#ifdef USE_HERMIT
-void Octree::countIntersection( UCHAR* node, int height, int& nedge, int& ncell, int& nface )
+void Octree::countIntersection(Node* node, int height, int& nedge, int& ncell, int& nface)
{
- if ( height > 0 )
+ if(height > 0)
{
- int total = getNumChildren( node ) ;
- for ( int i = 0 ; i < total ; i ++ )
+ int total = getNumChildren(&node->internal);
+ for(int i = 0; i < total; i ++)
{
- countIntersection( getChild( node, i ), height - 1, nedge, ncell, nface ) ;
+ countIntersection(getChild(&node->internal, i), height - 1, nedge, ncell, nface);
}
}
else
{
- nedge += getNumEdges2( node ) ;
+ nedge += getNumEdges2(&node->leaf);
- int smask = getSignMask( node ) ;
+ int smask = getSignMask(&node->leaf);
if(use_manifold)
{
- int comps = manifold_table[ smask ].comps ;
- ncell += comps ;
+ int comps = manifold_table[smask].comps;
+ ncell += comps;
}
else {
- if ( smask > 0 && smask < 255 )
+ if(smask > 0 && smask < 255)
{
- ncell ++ ;
+ ncell ++;
}
}
- for ( int i = 0 ; i < 3 ; i ++ )
+ for(int i = 0; i < 3; i ++)
{
- if ( getFaceEdgeNum( node, i * 2 ) )
+ if(getFaceEdgeNum(&node->leaf, i * 2))
{
- nface ++ ;
+ nface ++;
}
}
}
@@ -3497,213 +2313,203 @@ void solve_least_squares(const float halfA[], const float b[],
void minimize(float rvalue[3], float mp[3], const float pts[12][3],
const float norms[12][3], const int parity[12])
{
- float ata[6] = { 0, 0, 0, 0, 0, 0 };
- float atb[3] = { 0, 0, 0 } ;
- int ec = 0 ;
+ float ata[6] = {0, 0, 0, 0, 0, 0};
+ float atb[3] = {0, 0, 0};
+ int ec = 0;
- for ( int i = 0 ; i < 12 ; i ++ )
+ for(int i = 0; i < 12; i ++)
{
- // if ( getEdgeParity( leaf, i) )
- if ( parity[ i ] )
+ // if(getEdgeParity(leaf, i))
+ if(parity[i])
{
- const float* norm = norms[i] ;
- const float* p = pts[i] ;
+ const float* norm = norms[i];
+ const float* p = pts[i];
// QEF
- ata[ 0 ] += (float) ( norm[ 0 ] * norm[ 0 ] );
- ata[ 1 ] += (float) ( norm[ 0 ] * norm[ 1 ] );
- ata[ 2 ] += (float) ( norm[ 0 ] * norm[ 2 ] );
- ata[ 3 ] += (float) ( norm[ 1 ] * norm[ 1 ] );
- ata[ 4 ] += (float) ( norm[ 1 ] * norm[ 2 ] );
- ata[ 5 ] += (float) ( norm[ 2 ] * norm[ 2 ] );
+ ata[0] +=(float)(norm[0] * norm[0]);
+ ata[1] +=(float)(norm[0] * norm[1]);
+ ata[2] +=(float)(norm[0] * norm[2]);
+ ata[3] +=(float)(norm[1] * norm[1]);
+ ata[4] +=(float)(norm[1] * norm[2]);
+ ata[5] +=(float)(norm[2] * norm[2]);
- double pn = p[0] * norm[0] + p[1] * norm[1] + p[2] * norm[2] ;
+ double pn = p[0] * norm[0] + p[1] * norm[1] + p[2] * norm[2];
- atb[ 0 ] += (float) ( norm[ 0 ] * pn ) ;
- atb[ 1 ] += (float) ( norm[ 1 ] * pn ) ;
- atb[ 2 ] += (float) ( norm[ 2 ] * pn ) ;
+ atb[0] +=(float)(norm[0] * pn);
+ atb[1] +=(float)(norm[1] * pn);
+ atb[2] +=(float)(norm[2] * pn);
// Minimizer
- mp[0] += p[0] ;
- mp[1] += p[1] ;
- mp[2] += p[2] ;
+ mp[0] += p[0];
+ mp[1] += p[1];
+ mp[2] += p[2];
- ec ++ ;
+ ec ++;
}
}
- if ( ec == 0 )
+ if(ec == 0)
{
- return ;
+ return;
}
- mp[0] /= ec ;
- mp[1] /= ec ;
- mp[2] /= ec ;
+ mp[0] /= ec;
+ mp[1] /= ec;
+ mp[2] /= ec;
// Solve least squares
solve_least_squares(ata, atb, mp, rvalue);
}
-void Octree::computeMinimizer( UCHAR* leaf, int st[3], int len, float rvalue[3] )
+void Octree::computeMinimizer(LeafNode* leaf, int st[3], int len, float rvalue[3])
{
// First, gather all edge intersections
- float pts[12][3], norms[12][3] ;
- // fillEdgeIntersections( leaf, st, len, pts, norms ) ;
- int parity[12] ;
- fillEdgeIntersections( leaf, st, len, pts, norms, parity ) ;
+ float pts[12][3], norms[12][3];
+ int parity[12];
+ fillEdgeIntersections(leaf, st, len, pts, norms, parity);
// Next, construct QEF and minimizer
float mp[3] = {0, 0, 0};
minimize(rvalue, mp, pts, norms, parity);
/* Restraining the location of the minimizer */
- float nh1 = hermite_num * len ;
- float nh2 = ( 1 + hermite_num ) * len ;
+ float nh1 = hermite_num * len;
+ float nh2 =(1 + hermite_num) * len;
if((mode == DUALCON_MASS_POINT || mode == DUALCON_CENTROID) ||
- ( rvalue[0] < st[0] - nh1 || rvalue[1] < st[1] - nh1 || rvalue[2] < st[2] - nh1 ||
- rvalue[0] > st[0] + nh2 || rvalue[1] > st[1] + nh2 || rvalue[2] > st[2] + nh2 ))
+ (rvalue[0] < st[0] - nh1 || rvalue[1] < st[1] - nh1 || rvalue[2] < st[2] - nh1 ||
+ rvalue[0] > st[0] + nh2 || rvalue[1] > st[1] + nh2 || rvalue[2] > st[2] + nh2))
{
if(mode == DUALCON_CENTROID) {
// Use centroids
- rvalue[0] = (float) st[0] + len / 2 ;
- rvalue[1] = (float) st[1] + len / 2 ;
- rvalue[2] = (float) st[2] + len / 2 ;
+ rvalue[0] =(float) st[0] + len / 2;
+ rvalue[1] =(float) st[1] + len / 2;
+ rvalue[2] =(float) st[2] + len / 2;
}
else {
// Use mass point instead
- rvalue[0] = mp[0] ;
- rvalue[1] = mp[1] ;
- rvalue[2] = mp[2] ;
+ rvalue[0] = mp[0];
+ rvalue[1] = mp[1];
+ rvalue[2] = mp[2];
}
}
}
-void Octree::generateMinimizer( UCHAR* node, int st[3], int len, int height, int& offset )
+void Octree::generateMinimizer(Node* node, int st[3], int len, int height, int& offset)
{
- int i, j ;
+ int i, j;
- if ( height == 0 )
+ if(height == 0)
{
// Leaf cell, generate
// First, find minimizer
- float rvalue[3] ;
- rvalue[0] = (float) st[0] + len / 2 ;
- rvalue[1] = (float) st[1] + len / 2 ;
- rvalue[2] = (float) st[2] + len / 2 ;
- computeMinimizer( node, st, len, rvalue ) ;
+ float rvalue[3];
+ rvalue[0] =(float) st[0] + len / 2;
+ rvalue[1] =(float) st[1] + len / 2;
+ rvalue[2] =(float) st[2] + len / 2;
+ computeMinimizer(&node->leaf, st, len, rvalue);
// Update
- //float fnst[3] ;
- for ( j = 0 ; j < 3 ; j ++ )
+ //float fnst[3];
+ for(j = 0; j < 3; j ++)
{
- rvalue[ j ] = rvalue[ j ] * range / dimen + origin[ j ] ;
- //fnst[ j ] = st[ j ] * range / dimen + origin[ j ] ;
+ rvalue[j] = rvalue[j] * range / dimen + origin[j];
+ //fnst[j] = st[j] * range / dimen + origin[j];
}
- int mult = 0, smask = getSignMask( node ) ;
+ int mult = 0, smask = getSignMask(&node->leaf);
if(use_manifold)
{
- mult = manifold_table[ smask ].comps ;
+ mult = manifold_table[smask].comps;
}
else
{
- if ( smask > 0 && smask < 255 )
+ if(smask > 0 && smask < 255)
{
- mult = 1 ;
+ mult = 1;
}
}
- for ( j = 0 ; j < mult ; j ++ )
+ for(j = 0; j < mult; j ++)
{
add_vert(output_mesh, rvalue);
}
// Store the index
- setMinimizerIndex( node, offset ) ;
+ setMinimizerIndex(&node->leaf, offset);
- offset += mult ;
+ offset += mult;
}
else
{
// Internal cell, recur
- int count = 0 ;
- len >>= 1 ;
- for ( i = 0 ; i < 8 ; i ++ )
+ int count = 0;
+ len >>= 1;
+ for(i = 0; i < 8; i ++)
{
- if ( hasChild( node, i ) )
+ if(hasChild(&node->internal, i))
{
- int nst[3] ;
- nst[0] = st[0] + vertmap[i][0] * len ;
- nst[1] = st[1] + vertmap[i][1] * len ;
- nst[2] = st[2] + vertmap[i][2] * len ;
+ int nst[3];
+ nst[0] = st[0] + vertmap[i][0] * len;
+ nst[1] = st[1] + vertmap[i][1] * len;
+ nst[2] = st[2] + vertmap[i][2] * len;
- generateMinimizer( getChild( node, count ), nst, len, height - 1, offset ) ;
- count ++ ;
+ generateMinimizer(getChild(&node->internal, count),
+ nst, len, height - 1, offset);
+ count ++;
}
}
}
}
-void Octree::processEdgeWrite( UCHAR* node[4], int depth[4], int maxdep, int dir )
+void Octree::processEdgeWrite(Node* node[4], int depth[4], int maxdep, int dir)
{
- //int color = 0 ;
+ //int color = 0;
- int i = 3 ;
+ int i = 3;
{
- if ( getEdgeParity( node[i], processEdgeMask[dir][i] ) )
+ if(getEdgeParity((LeafNode*)(node[i]), processEdgeMask[dir][i]))
{
- int flip = 0 ;
- int edgeind = processEdgeMask[dir][i] ;
- if ( getSign( node[i], edgemap[ edgeind ][ 1 ] ) > 0 )
+ int flip = 0;
+ int edgeind = processEdgeMask[dir][i];
+ if(getSign((LeafNode*)node[i], edgemap[edgeind][1]) > 0)
{
- flip = 1 ;
+ flip = 1;
}
- int num = 0 ;
+ int num = 0;
{
int ind[8];
if(use_manifold)
{
/* Deprecated
int ind[4] = {
- getMinimizerIndex( node[0], processEdgeMask[dir][0] ),
- getMinimizerIndex( node[1], processEdgeMask[dir][1] ),
- getMinimizerIndex( node[3], processEdgeMask[dir][3] ),
- getMinimizerIndex( node[2], processEdgeMask[dir][2] )
- } ;
- num = 4 ;
+ getMinimizerIndex(node[0], processEdgeMask[dir][0]),
+ getMinimizerIndex(node[1], processEdgeMask[dir][1]),
+ getMinimizerIndex(node[3], processEdgeMask[dir][3]),
+ getMinimizerIndex(node[2], processEdgeMask[dir][2])
+ };
+ num = 4;
*/
- int vind[2] ;
+ int vind[2];
int seq[4] = {0,1,3,2};
- for ( int k = 0 ; k < 4 ; k ++ )
+ for(int k = 0; k < 4; k ++)
{
- getMinimizerIndices( node[seq[k]], processEdgeMask[dir][seq[k]], vind ) ;
- ind[num] = vind[0] ;
- num ++ ;
+ getMinimizerIndices((LeafNode*)(node[seq[k]]), processEdgeMask[dir][seq[k]], vind);
+ ind[num] = vind[0];
+ num ++;
- if ( vind[1] != -1 )
+ if(vind[1] != -1)
{
- ind[num] = vind[1] ;
- num ++ ;
- if ( flip == 0 )
+ ind[num] = vind[1];
+ num ++;
+ if(flip == 0)
{
- ind[num-1] = vind[0] ;
- ind[num-2] = vind[1] ;
+ ind[num-1] = vind[0];
+ ind[num-2] = vind[1];
}
}
}
-#ifdef TESTMANIFOLD
- if ( num != 4 )
- {
- dc_printf("Polygon: %d\n", num);
- }
- for ( k = 0 ; k < num ; k ++ )
- {
- fprintf(testfout, "{%d,%d},", ind[k], ind[(k+1)%num] );
- }
-#endif
/* we don't use the manifold option, but if it is
ever enabled again note that it can output
@@ -3711,498 +2517,505 @@ void Octree::processEdgeWrite( UCHAR* node[4], int depth[4], int maxdep, int dir
}
else {
if(flip) {
- ind[0] = getMinimizerIndex( node[2] );
- ind[1] = getMinimizerIndex( node[3] );
- ind[2] = getMinimizerIndex( node[1] );
- ind[3] = getMinimizerIndex( node[0] );
+ ind[0] = getMinimizerIndex((LeafNode*)(node[2]));
+ ind[1] = getMinimizerIndex((LeafNode*)(node[3]));
+ ind[2] = getMinimizerIndex((LeafNode*)(node[1]));
+ ind[3] = getMinimizerIndex((LeafNode*)(node[0]));
}
else {
- ind[0] = getMinimizerIndex( node[0] );
- ind[1] = getMinimizerIndex( node[1] );
- ind[2] = getMinimizerIndex( node[3] );
- ind[3] = getMinimizerIndex( node[2] );
+ ind[0] = getMinimizerIndex((LeafNode*)(node[0]));
+ ind[1] = getMinimizerIndex((LeafNode*)(node[1]));
+ ind[2] = getMinimizerIndex((LeafNode*)(node[3]));
+ ind[3] = getMinimizerIndex((LeafNode*)(node[2]));
}
add_quad(output_mesh, ind);
}
/*
- if ( this->outType == 0 )
+ if(outType == 0)
{
// OFF
- num = ( color ? -num : num ) ;
+ num =(color ? -num : num);
fprintf(fout, "%d ", num);
- if ( flip )
+ if(flip)
{
- for ( int k = num - 1 ; k >= 0 ; k -- )
+ for(int k = num - 1; k >= 0; k --)
{
- fprintf(fout, "%d ", ind[k] ) ;
+ fprintf(fout, "%d ", ind[k]);
}
}
else
{
- for ( int k = 0 ; k < num ; k ++ )
+ for(int k = 0; k < num; k ++)
{
- fprintf(fout, "%d ", ind[k] ) ;
+ fprintf(fout, "%d ", ind[k]);
}
}
- fprintf( fout, "\n") ;
+ fprintf(fout, "\n");
- actualQuads ++ ;
+ actualQuads ++;
}
- else if ( this->outType == 1 )
+ else if(outType == 1)
{
// PLY
- if ( flip )
+ if(flip)
{
int tind[8];
- for ( int k = num - 1 ; k >= 0 ; k -- )
+ for(int k = num - 1; k >= 0; k --)
{
- tind[k] = ind[num-1-k] ;
+ tind[k] = ind[num-1-k];
}
- // PLYWriter::writeFace( fout, num, tind ) ;
+ // PLYWriter::writeFace(fout, num, tind);
}
else
{
- // PLYWriter::writeFace( fout, num, ind ) ;
+ // PLYWriter::writeFace(fout, num, ind);
}
- actualQuads ++ ;
+ actualQuads ++;
}*/
}
- return ;
+ return;
}
else
{
- return ;
+ return;
}
}
}
-void Octree::edgeProcContour( UCHAR* node[4], int leaf[4], int depth[4], int maxdep, int dir )
+void Octree::edgeProcContour(Node* node[4], int leaf[4], int depth[4], int maxdep, int dir)
{
- if ( ! ( node[0] && node[1] && node[2] && node[3] ) )
+ if(!(node[0] && node[1] && node[2] && node[3]))
{
- return ;
+ return;
}
- if ( leaf[0] && leaf[1] && leaf[2] && leaf[3] )
+ if(leaf[0] && leaf[1] && leaf[2] && leaf[3])
{
- processEdgeWrite( node, depth, maxdep, dir ) ;
+ processEdgeWrite(node, depth, maxdep, dir);
}
else
{
- int i, j ;
- UCHAR* chd[ 4 ][ 8 ] ;
- for ( j = 0 ; j < 4 ; j ++ )
+ int i, j;
+ Node* chd[4][8];
+ for(j = 0; j < 4; j ++)
{
- for ( i = 0 ; i < 8 ; i ++ )
+ for(i = 0; i < 8; i ++)
{
- chd[ j ][ i ] = ((!leaf[j]) && hasChild( node[j], i ) )? getChild( node[j], getChildCount( node[j], i ) ) : NULL ;
+ chd[j][i] = ((!leaf[j]) && hasChild(&node[j]->internal, i)) ?
+ getChild(&node[j]->internal,
+ getChildCount(&node[j]->internal, i)) : NULL;
}
}
// 2 edge calls
- UCHAR* ne[4] ;
- int le[4] ;
- int de[4] ;
- for ( i = 0 ; i < 2 ; i ++ )
+ Node* ne[4];
+ int le[4];
+ int de[4];
+ for(i = 0; i < 2; i ++)
{
- int c[ 4 ] = { edgeProcEdgeMask[ dir ][ i ][ 0 ],
- edgeProcEdgeMask[ dir ][ i ][ 1 ],
- edgeProcEdgeMask[ dir ][ i ][ 2 ],
- edgeProcEdgeMask[ dir ][ i ][ 3 ] } ;
+ int c[4] = {edgeProcEdgeMask[dir][i][0],
+ edgeProcEdgeMask[dir][i][1],
+ edgeProcEdgeMask[dir][i][2],
+ edgeProcEdgeMask[dir][i][3]};
- for ( int j = 0 ; j < 4 ; j ++ )
+ for(int j = 0; j < 4; j ++)
{
- if ( leaf[j] )
+ if(leaf[j])
{
- le[j] = leaf[j] ;
- ne[j] = node[j] ;
- de[j] = depth[j] ;
+ le[j] = leaf[j];
+ ne[j] = node[j];
+ de[j] = depth[j];
}
else
{
- le[j] = isLeaf( node[j], c[j] ) ;
- ne[j] = chd[ j ][ c[j] ] ;
- de[j] = depth[j] - 1 ;
+ le[j] = isLeaf(&node[j]->internal, c[j]);
+ ne[j] = chd[j][c[j]];
+ de[j] = depth[j] - 1;
}
}
- edgeProcContour( ne, le, de, maxdep - 1, edgeProcEdgeMask[ dir ][ i ][ 4 ] ) ;
+ edgeProcContour(ne, le, de, maxdep - 1, edgeProcEdgeMask[dir][i][4]);
}
}
}
-void Octree::faceProcContour( UCHAR* node[2], int leaf[2], int depth[2], int maxdep, int dir )
+void Octree::faceProcContour(Node* node[2], int leaf[2], int depth[2], int maxdep, int dir)
{
- if ( ! ( node[0] && node[1] ) )
+ if(!(node[0] && node[1]))
{
- return ;
+ return;
}
- if ( ! ( leaf[0] && leaf[1] ) )
+ if(!(leaf[0] && leaf[1]))
{
- int i, j ;
+ int i, j;
// Fill children nodes
- UCHAR* chd[ 2 ][ 8 ] ;
- for ( j = 0 ; j < 2 ; j ++ )
+ Node* chd[2][8];
+ for(j = 0; j < 2; j ++)
{
- for ( i = 0 ; i < 8 ; i ++ )
+ for(i = 0; i < 8; i ++)
{
- chd[ j ][ i ] = ((!leaf[j]) && hasChild( node[j], i )) ? getChild( node[j], getChildCount( node[j], i ) ) : NULL ;
+ chd[j][i] =((!leaf[j]) && hasChild(&node[j]->internal, i)) ?
+ getChild(&node[j]->internal,
+ getChildCount(&node[j]->internal, i)) : NULL;
}
}
// 4 face calls
- UCHAR* nf[2] ;
- int df[2] ;
- int lf[2] ;
- for ( i = 0 ; i < 4 ; i ++ )
+ Node* nf[2];
+ int df[2];
+ int lf[2];
+ for(i = 0; i < 4; i ++)
{
- int c[2] = { faceProcFaceMask[ dir ][ i ][ 0 ], faceProcFaceMask[ dir ][ i ][ 1 ] };
- for ( int j = 0 ; j < 2 ; j ++ )
+ int c[2] = {faceProcFaceMask[dir][i][0], faceProcFaceMask[dir][i][1]};
+ for(int j = 0; j < 2; j ++)
{
- if ( leaf[j] )
+ if(leaf[j])
{
- lf[j] = leaf[j] ;
- nf[j] = node[j] ;
- df[j] = depth[j] ;
+ lf[j] = leaf[j];
+ nf[j] = node[j];
+ df[j] = depth[j];
}
else
{
- lf[j] = isLeaf( node[j], c[j] ) ;
- nf[j] = chd[ j ][ c[j] ] ;
- df[j] = depth[j] - 1 ;
+ lf[j] = isLeaf(&node[j]->internal, c[j]);
+ nf[j] = chd[j][c[j]];
+ df[j] = depth[j] - 1;
}
}
- faceProcContour( nf, lf, df, maxdep - 1, faceProcFaceMask[ dir ][ i ][ 2 ] ) ;
+ faceProcContour(nf, lf, df, maxdep - 1, faceProcFaceMask[dir][i][2]);
}
// 4 edge calls
- int orders[2][4] = {{ 0, 0, 1, 1 }, { 0, 1, 0, 1 }} ;
- UCHAR* ne[4] ;
- int le[4] ;
- int de[4] ;
+ int orders[2][4] = {{0, 0, 1, 1}, {0, 1, 0, 1}};
+ Node* ne[4];
+ int le[4];
+ int de[4];
- for ( i = 0 ; i < 4 ; i ++ )
+ for(i = 0; i < 4; i ++)
{
- int c[4] = { faceProcEdgeMask[ dir ][ i ][ 1 ], faceProcEdgeMask[ dir ][ i ][ 2 ],
- faceProcEdgeMask[ dir ][ i ][ 3 ], faceProcEdgeMask[ dir ][ i ][ 4 ] };
- int* order = orders[ faceProcEdgeMask[ dir ][ i ][ 0 ] ] ;
+ int c[4] = {faceProcEdgeMask[dir][i][1], faceProcEdgeMask[dir][i][2],
+ faceProcEdgeMask[dir][i][3], faceProcEdgeMask[dir][i][4]};
+ int* order = orders[faceProcEdgeMask[dir][i][0]];
- for ( int j = 0 ; j < 4 ; j ++ )
+ for(int j = 0; j < 4; j ++)
{
- if ( leaf[order[j]] )
+ if(leaf[order[j]])
{
- le[j] = leaf[order[j]] ;
- ne[j] = node[order[j]] ;
- de[j] = depth[order[j]] ;
+ le[j] = leaf[order[j]];
+ ne[j] = node[order[j]];
+ de[j] = depth[order[j]];
}
else
{
- le[j] = isLeaf( node[order[j]], c[j] ) ;
- ne[j] = chd[ order[ j ] ][ c[j] ] ;
- de[j] = depth[order[j]] - 1 ;
+ le[j] = isLeaf(&node[order[j]]->internal, c[j]);
+ ne[j] = chd[order[j]][c[j]];
+ de[j] = depth[order[j]] - 1;
}
}
- edgeProcContour( ne, le, de, maxdep - 1, faceProcEdgeMask[ dir ][ i ][ 5 ] ) ;
+ edgeProcContour(ne, le, de, maxdep - 1, faceProcEdgeMask[dir][i][5]);
}
}
}
-void Octree::cellProcContour( UCHAR* node, int leaf, int depth )
+void Octree::cellProcContour(Node* node, int leaf, int depth)
{
- if ( node == NULL )
+ if(node == NULL)
{
- return ;
+ return;
}
- if ( ! leaf )
+ if(! leaf)
{
- int i ;
+ int i;
// Fill children nodes
- UCHAR* chd[ 8 ] ;
- for ( i = 0 ; i < 8 ; i ++ )
+ Node* chd[8];
+ for(i = 0; i < 8; i ++)
{
- chd[ i ] = ((!leaf) && hasChild( node, i )) ? getChild( node, getChildCount( node, i ) ) : NULL ;
+ chd[i] =((!leaf) && hasChild(&node->internal, i)) ?
+ getChild(&node->internal,
+ getChildCount(&node->internal, i)) : NULL;
}
// 8 Cell calls
- for ( i = 0 ; i < 8 ; i ++ )
+ for(i = 0; i < 8; i ++)
{
- cellProcContour( chd[ i ], isLeaf( node, i ), depth - 1 ) ;
+ cellProcContour(chd[i], isLeaf(&node->internal, i), depth - 1);
}
// 12 face calls
- UCHAR* nf[2] ;
- int lf[2] ;
- int df[2] = { depth - 1, depth - 1 } ;
- for ( i = 0 ; i < 12 ; i ++ )
+ Node* nf[2];
+ int lf[2];
+ int df[2] = {depth - 1, depth - 1};
+ for(i = 0; i < 12; i ++)
{
- int c[ 2 ] = { cellProcFaceMask[ i ][ 0 ], cellProcFaceMask[ i ][ 1 ] };
+ int c[2] = {cellProcFaceMask[i][0], cellProcFaceMask[i][1]};
- lf[0] = isLeaf( node, c[0] ) ;
- lf[1] = isLeaf( node, c[1] ) ;
+ lf[0] = isLeaf(&node->internal, c[0]);
+ lf[1] = isLeaf(&node->internal, c[1]);
- nf[0] = chd[ c[0] ] ;
- nf[1] = chd[ c[1] ] ;
+ nf[0] = chd[c[0]];
+ nf[1] = chd[c[1]];
- faceProcContour( nf, lf, df, depth - 1, cellProcFaceMask[ i ][ 2 ] ) ;
+ faceProcContour(nf, lf, df, depth - 1, cellProcFaceMask[i][2]);
}
// 6 edge calls
- UCHAR* ne[4] ;
- int le[4] ;
- int de[4] = { depth - 1, depth - 1, depth - 1, depth - 1 } ;
- for ( i = 0 ; i < 6 ; i ++ )
+ Node* ne[4];
+ int le[4];
+ int de[4] = {depth - 1, depth - 1, depth - 1, depth - 1};
+ for(i = 0; i < 6; i ++)
{
- int c[ 4 ] = { cellProcEdgeMask[ i ][ 0 ], cellProcEdgeMask[ i ][ 1 ], cellProcEdgeMask[ i ][ 2 ], cellProcEdgeMask[ i ][ 3 ] };
+ int c[4] = {cellProcEdgeMask[i][0], cellProcEdgeMask[i][1], cellProcEdgeMask[i][2], cellProcEdgeMask[i][3]};
- for ( int j = 0 ; j < 4 ; j ++ )
+ for(int j = 0; j < 4; j ++)
{
- le[j] = isLeaf( node, c[j] ) ;
- ne[j] = chd[ c[j] ] ;
+ le[j] = isLeaf(&node->internal, c[j]);
+ ne[j] = chd[c[j]];
}
- edgeProcContour( ne, le, de, depth - 1, cellProcEdgeMask[ i ][ 4 ] ) ;
+ edgeProcContour(ne, le, de, depth - 1, cellProcEdgeMask[i][4]);
}
}
}
-#endif
-
-
-
-void Octree::processEdgeParity( UCHAR* node[4], int depth[4], int maxdep, int dir )
+void Octree::processEdgeParity(LeafNode* node[4], int depth[4], int maxdep, int dir)
{
- int con = 0 ;
- for ( int i = 0 ; i < 4 ; i ++ )
+ int con = 0;
+ for(int i = 0; i < 4; i ++)
{
// Minimal cell
- // if ( op == 0 )
+ // if(op == 0)
{
- if ( getEdgeParity( node[i], processEdgeMask[dir][i] ) )
+ if(getEdgeParity(node[i], processEdgeMask[dir][i]))
{
- con = 1 ;
- break ;
+ con = 1;
+ break;
}
}
}
- if ( con == 1 )
+ if(con == 1)
{
- for ( int i = 0 ; i < 4 ; i ++ )
+ for(int i = 0; i < 4; i ++)
{
- setEdge( node[ i ], processEdgeMask[dir][i] ) ;
+ setEdge(node[i], processEdgeMask[dir][i]);
}
}
}
-void Octree::edgeProcParity( UCHAR* node[4], int leaf[4], int depth[4], int maxdep, int dir )
+void Octree::edgeProcParity(Node* node[4], int leaf[4], int depth[4], int maxdep, int dir)
{
- if ( ! ( node[0] && node[1] && node[2] && node[3] ) )
+ if(!(node[0] && node[1] && node[2] && node[3]))
{
- return ;
+ return;
}
- if ( leaf[0] && leaf[1] && leaf[2] && leaf[3] )
+ if(leaf[0] && leaf[1] && leaf[2] && leaf[3])
{
- processEdgeParity( node, depth, maxdep, dir ) ;
+ processEdgeParity((LeafNode**)node, depth, maxdep, dir);
}
else
{
- int i, j ;
- UCHAR* chd[ 4 ][ 8 ] ;
- for ( j = 0 ; j < 4 ; j ++ )
+ int i, j;
+ Node* chd[4][8];
+ for(j = 0; j < 4; j ++)
{
- for ( i = 0 ; i < 8 ; i ++ )
+ for(i = 0; i < 8; i ++)
{
- chd[ j ][ i ] = ((!leaf[j]) && hasChild( node[j], i ) )? getChild( node[j], getChildCount( node[j], i ) ) : NULL ;
+ chd[j][i] =((!leaf[j]) && hasChild(&node[j]->internal, i)) ?
+ getChild(&node[j]->internal, getChildCount(&node[j]->internal, i)) : NULL;
}
}
// 2 edge calls
- UCHAR* ne[4] ;
- int le[4] ;
- int de[4] ;
- for ( i = 0 ; i < 2 ; i ++ )
+ Node* ne[4];
+ int le[4];
+ int de[4];
+ for(i = 0; i < 2; i ++)
{
- int c[ 4 ] = { edgeProcEdgeMask[ dir ][ i ][ 0 ],
- edgeProcEdgeMask[ dir ][ i ][ 1 ],
- edgeProcEdgeMask[ dir ][ i ][ 2 ],
- edgeProcEdgeMask[ dir ][ i ][ 3 ] } ;
+ int c[4] = {edgeProcEdgeMask[dir][i][0],
+ edgeProcEdgeMask[dir][i][1],
+ edgeProcEdgeMask[dir][i][2],
+ edgeProcEdgeMask[dir][i][3]};
- // int allleaf = 1 ;
- for ( int j = 0 ; j < 4 ; j ++ )
+ // int allleaf = 1;
+ for(int j = 0; j < 4; j ++)
{
- if ( leaf[j] )
+ if(leaf[j])
{
- le[j] = leaf[j] ;
- ne[j] = node[j] ;
- de[j] = depth[j] ;
+ le[j] = leaf[j];
+ ne[j] = node[j];
+ de[j] = depth[j];
}
else
{
- le[j] = isLeaf( node[j], c[j] ) ;
- ne[j] = chd[ j ][ c[j] ] ;
- de[j] = depth[j] - 1 ;
+ le[j] = isLeaf(&node[j]->internal, c[j]);
+ ne[j] = chd[j][c[j]];
+ de[j] = depth[j] - 1;
}
}
- edgeProcParity( ne, le, de, maxdep - 1, edgeProcEdgeMask[ dir ][ i ][ 4 ] ) ;
+ edgeProcParity(ne, le, de, maxdep - 1, edgeProcEdgeMask[dir][i][4]);
}
}
}
-void Octree::faceProcParity( UCHAR* node[2], int leaf[2], int depth[2], int maxdep, int dir )
+void Octree::faceProcParity(Node* node[2], int leaf[2], int depth[2], int maxdep, int dir)
{
- if ( ! ( node[0] && node[1] ) )
+ if(!(node[0] && node[1]))
{
- return ;
+ return;
}
- if ( ! ( leaf[0] && leaf[1] ) )
+ if(!(leaf[0] && leaf[1]))
{
- int i, j ;
+ int i, j;
// Fill children nodes
- UCHAR* chd[ 2 ][ 8 ] ;
- for ( j = 0 ; j < 2 ; j ++ )
+ Node* chd[2][8];
+ for(j = 0; j < 2; j ++)
{
- for ( i = 0 ; i < 8 ; i ++ )
+ for(i = 0; i < 8; i ++)
{
- chd[ j ][ i ] = ((!leaf[j]) && hasChild( node[j], i )) ? getChild( node[j], getChildCount( node[j], i ) ) : NULL ;
+ chd[j][i] =((!leaf[j]) && hasChild(&node[j]->internal, i)) ?
+ getChild(&node[j]->internal,
+ getChildCount(&node[j]->internal, i)) : NULL;
}
}
// 4 face calls
- UCHAR* nf[2] ;
- int df[2] ;
- int lf[2] ;
- for ( i = 0 ; i < 4 ; i ++ )
+ Node* nf[2];
+ int df[2];
+ int lf[2];
+ for(i = 0; i < 4; i ++)
{
- int c[2] = { faceProcFaceMask[ dir ][ i ][ 0 ], faceProcFaceMask[ dir ][ i ][ 1 ] };
- for ( int j = 0 ; j < 2 ; j ++ )
+ int c[2] = {faceProcFaceMask[dir][i][0], faceProcFaceMask[dir][i][1]};
+ for(int j = 0; j < 2; j ++)
{
- if ( leaf[j] )
+ if(leaf[j])
{
- lf[j] = leaf[j] ;
- nf[j] = node[j] ;
- df[j] = depth[j] ;
+ lf[j] = leaf[j];
+ nf[j] = node[j];
+ df[j] = depth[j];
}
else
{
- lf[j] = isLeaf( node[j], c[j] ) ;
- nf[j] = chd[ j ][ c[j] ] ;
- df[j] = depth[j] - 1 ;
+ lf[j] = isLeaf(&node[j]->internal, c[j]);
+ nf[j] = chd[j][c[j]];
+ df[j] = depth[j] - 1;
}
}
- faceProcParity( nf, lf, df, maxdep - 1, faceProcFaceMask[ dir ][ i ][ 2 ] ) ;
+ faceProcParity(nf, lf, df, maxdep - 1, faceProcFaceMask[dir][i][2]);
}
// 4 edge calls
- int orders[2][4] = {{ 0, 0, 1, 1 }, { 0, 1, 0, 1 }} ;
- UCHAR* ne[4] ;
- int le[4] ;
- int de[4] ;
+ int orders[2][4] = {{0, 0, 1, 1}, {0, 1, 0, 1}};
+ Node* ne[4];
+ int le[4];
+ int de[4];
- for ( i = 0 ; i < 4 ; i ++ )
+ for(i = 0; i < 4; i ++)
{
- int c[4] = { faceProcEdgeMask[ dir ][ i ][ 1 ], faceProcEdgeMask[ dir ][ i ][ 2 ],
- faceProcEdgeMask[ dir ][ i ][ 3 ], faceProcEdgeMask[ dir ][ i ][ 4 ] };
- int* order = orders[ faceProcEdgeMask[ dir ][ i ][ 0 ] ] ;
+ int c[4] = {faceProcEdgeMask[dir][i][1], faceProcEdgeMask[dir][i][2],
+ faceProcEdgeMask[dir][i][3], faceProcEdgeMask[dir][i][4]};
+ int* order = orders[faceProcEdgeMask[dir][i][0]];
- for ( int j = 0 ; j < 4 ; j ++ )
+ for(int j = 0; j < 4; j ++)
{
- if ( leaf[order[j]] )
+ if(leaf[order[j]])
{
- le[j] = leaf[order[j]] ;
- ne[j] = node[order[j]] ;
- de[j] = depth[order[j]] ;
+ le[j] = leaf[order[j]];
+ ne[j] = node[order[j]];
+ de[j] = depth[order[j]];
}
else
{
- le[j] = isLeaf( node[order[j]], c[j] ) ;
- ne[j] = chd[ order[ j ] ][ c[j] ] ;
- de[j] = depth[order[j]] - 1 ;
+ le[j] = isLeaf((InternalNode*)(node[order[j]]), c[j]);
+ ne[j] = chd[order[j]][c[j]];
+ de[j] = depth[order[j]] - 1;
}
}
- edgeProcParity( ne, le, de, maxdep - 1, faceProcEdgeMask[ dir ][ i ][ 5 ] ) ;
+ edgeProcParity(ne, le, de, maxdep - 1, faceProcEdgeMask[dir][i][5]);
}
}
}
-void Octree::cellProcParity( UCHAR* node, int leaf, int depth )
+void Octree::cellProcParity(Node* node, int leaf, int depth)
{
- if ( node == NULL )
+ if(node == NULL)
{
- return ;
+ return;
}
- if ( ! leaf )
+ if(! leaf)
{
- int i ;
+ int i;
// Fill children nodes
- UCHAR* chd[ 8 ] ;
- for ( i = 0 ; i < 8 ; i ++ )
+ Node* chd[8];
+ for(i = 0; i < 8; i ++)
{
- chd[ i ] = ((!leaf) && hasChild( node, i )) ? getChild( node, getChildCount( node, i ) ) : NULL ;
+ chd[i] =((!leaf) && hasChild((InternalNode*)node, i)) ?
+ getChild((InternalNode*)node,
+ getChildCount((InternalNode*)node, i)) : NULL;
}
// 8 Cell calls
- for ( i = 0 ; i < 8 ; i ++ )
+ for(i = 0; i < 8; i ++)
{
- cellProcParity( chd[ i ], isLeaf( node, i ), depth - 1 ) ;
+ cellProcParity(chd[i], isLeaf((InternalNode*)node, i), depth - 1);
}
// 12 face calls
- UCHAR* nf[2] ;
- int lf[2] ;
- int df[2] = { depth - 1, depth - 1 } ;
- for ( i = 0 ; i < 12 ; i ++ )
+ Node* nf[2];
+ int lf[2];
+ int df[2] = {depth - 1, depth - 1};
+ for(i = 0; i < 12; i ++)
{
- int c[ 2 ] = { cellProcFaceMask[ i ][ 0 ], cellProcFaceMask[ i ][ 1 ] };
+ int c[2] = {cellProcFaceMask[i][0], cellProcFaceMask[i][1]};
- lf[0] = isLeaf( node, c[0] ) ;
- lf[1] = isLeaf( node, c[1] ) ;
+ lf[0] = isLeaf((InternalNode*)node, c[0]);
+ lf[1] = isLeaf((InternalNode*)node, c[1]);
- nf[0] = chd[ c[0] ] ;
- nf[1] = chd[ c[1] ] ;
+ nf[0] = chd[c[0]];
+ nf[1] = chd[c[1]];
- faceProcParity( nf, lf, df, depth - 1, cellProcFaceMask[ i ][ 2 ] ) ;
+ faceProcParity(nf, lf, df, depth - 1, cellProcFaceMask[i][2]);
}
// 6 edge calls
- UCHAR* ne[4] ;
- int le[4] ;
- int de[4] = { depth - 1, depth - 1, depth - 1, depth - 1 } ;
- for ( i = 0 ; i < 6 ; i ++ )
+ Node* ne[4];
+ int le[4];
+ int de[4] = {depth - 1, depth - 1, depth - 1, depth - 1};
+ for(i = 0; i < 6; i ++)
{
- int c[ 4 ] = { cellProcEdgeMask[ i ][ 0 ], cellProcEdgeMask[ i ][ 1 ], cellProcEdgeMask[ i ][ 2 ], cellProcEdgeMask[ i ][ 3 ] };
+ int c[4] = {cellProcEdgeMask[i][0], cellProcEdgeMask[i][1], cellProcEdgeMask[i][2], cellProcEdgeMask[i][3]};
- for ( int j = 0 ; j < 4 ; j ++ )
+ for(int j = 0; j < 4; j ++)
{
- le[j] = isLeaf( node, c[j] ) ;
- ne[j] = chd[ c[j] ] ;
+ le[j] = isLeaf((InternalNode*)node, c[j]);
+ ne[j] = chd[c[j]];
}
- edgeProcParity( ne, le, de, depth - 1, cellProcEdgeMask[ i ][ 4 ] ) ;
+ edgeProcParity(ne, le, de, depth - 1, cellProcEdgeMask[i][4]);
}
}
diff --git a/intern/dualcon/intern/octree.h b/intern/dualcon/intern/octree.h
index 7b5a626bddc..aac09549ee6 100644
--- a/intern/dualcon/intern/octree.h
+++ b/intern/dualcon/intern/octree.h
@@ -15,7 +15,7 @@
* 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): Tao Ju
+ * Contributor(s): Tao Ju, Nicholas Bishop
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -23,6 +23,8 @@
#ifndef OCTREE_H
#define OCTREE_H
+#include <cassert>
+#include <cstring>
#include <stdio.h>
#include <math.h>
#include "GeoCommon.h"
@@ -50,52 +52,56 @@
// #define IN_VERBOSE_MODE
/* Set scan convert params */
-// Uncomment to use Dual Contouring on Hermit representation
-// for better sharp feature reproduction, but more mem is required
-// The number indicates how far do we allow the minimizer to shoot
-// outside the cell
-#define USE_HERMIT 1.0f
-
-#ifdef USE_HERMIT
-//#define CINDY
-#endif
-///#define QIANYI
+#define EDGE_FLOATS 4
-//#define TESTMANIFOLD
+union Node;
+struct InternalNode {
+ /* Treat as bitfield, bit N indicates whether child N exists or not */
+ unsigned char has_child;
+ /* Treat as bitfield, bit N indicates whether child N is a leaf or not */
+ unsigned char child_is_leaf;
-/* Set output options */
-// Comment out to prevent writing output files
-#define OUTPUT_REPAIRED
+ /* Can have up to eight children */
+ Node *children[0];
+};
-/* Set node bytes */
-#ifdef USE_HERMIT
-#define EDGE_BYTES 16
-#define EDGE_FLOATS 4
-#else
-#define EDGE_BYTES 4
-#define EDGE_FLOATS 1
-#endif
+/**
+ * Bits order
+ *
+ * Leaf node:
+ * Byte 0,1(0-11): edge parity
+ * Byte 1(4,5,6): mask of primary edges intersections stored
+ * Byte 1(7): in flood fill mode, whether the cell is in process
+ * Byte 2(0-8): signs
+ * Byte 3,4: in coloring mode, the mask for edges
+ * Byte 5: edge intersections(4 bytes per inter, or 12 bytes if USE_HERMIT)
+ */
+struct LeafNode /* TODO: remove this attribute once everything is fixed */ {
+ unsigned short edge_parity : 12;
+ unsigned short primary_edge_intersections : 3;
-#define CINDY_BYTES 0
+ /* XXX: maybe actually unused? */
+ unsigned short in_process : 1;
-/*#define LEAF_EXTRA_BYTES FLOOD_BYTES + CINDY_BYTES
+ /* bitfield */
+ char signs;
-#ifdef USE_HERMIT
-#define LEAF_NODE_BYTES 7 + LEAF_EXTRA_BYTES
-#else
-#define LEAF_NODE_BYTES 3 + LEAF_EXTRA_BYTES
-#endif*/
+ int minimizer_index;
+
+ unsigned short flood_fill;
-#define INTERNAL_NODE_BYTES 2
-#define POINTER_BYTES 8
-#define FLOOD_FILL_BYTES 2
+ float edge_intersections[0];
+};
-#define signtype short
-#define nodetype int
-#define numtype int
+/* Doesn't get directly allocated anywhere, just used for passing
+ pointers to nodes that could be internal or leaf. */
+union Node {
+ InternalNode internal;
+ LeafNode leaf;
+};
/* Global variables */
extern const int edgemask[3];
@@ -116,23 +122,23 @@ extern const int dirEdge[3][4];
struct PathElement
{
// Origin
- int pos[3] ;
+ int pos[3];
// link
- PathElement* next ;
+ PathElement* next;
};
struct PathList
{
// Head
- PathElement* head ;
- PathElement* tail ;
+ PathElement* head;
+ PathElement* tail;
// Length of the list
- int length ;
+ int length;
// Next list
- PathList* next ;
+ PathList* next;
};
@@ -145,78 +151,71 @@ public:
/* Public members */
/// Memory allocators
- VirtualMemoryAllocator * alloc[ 9 ] ;
- VirtualMemoryAllocator * leafalloc[ 4 ] ;
+ VirtualMemoryAllocator * alloc[9];
+ VirtualMemoryAllocator * leafalloc[4];
/// Root node
- UCHAR* root ;
+ Node* root;
/// Model reader
- ModelReader* reader ;
+ ModelReader* reader;
/// Marching cubes table
- Cubes* cubes ;
+ Cubes* cubes;
/// Length of grid
- int dimen ;
- int mindimen, minshift ;
+ int dimen;
+ int mindimen, minshift;
/// Maximum depth
- int maxDepth ;
+ int maxDepth;
/// The lower corner of the bounding box and the size
float origin[3];
float range;
/// Counting information
- int nodeCount ;
- int nodeSpace ;
- int nodeCounts[ 9 ] ;
+ int nodeCount;
+ int nodeSpace;
+ int nodeCounts[9];
- int actualQuads, actualVerts ;
+ int actualQuads, actualVerts;
- PathList* ringList ;
+ PathList* ringList;
- int maxTrianglePerCell ;
- int outType ; // 0 for OFF, 1 for PLY, 2 for VOL
+ int maxTrianglePerCell;
+ int outType; // 0 for OFF, 1 for PLY, 2 for VOL
// For flood filling
int use_flood_fill;
- float thresh ;
+ float thresh;
int use_manifold;
- // testing
- FILE* testfout ;
-
float hermite_num;
DualConMode mode;
- int leaf_node_bytes;
- int leaf_extra_bytes;
- int flood_bytes;
-
public:
/**
* Construtor
*/
- Octree ( ModelReader* mr,
+ Octree(ModelReader* mr,
DualConAllocOutput alloc_output_func,
DualConAddVert add_vert_func,
DualConAddQuad add_quad_func,
DualConFlags flags, DualConMode mode, int depth,
- float threshold, float hermite_num ) ;
+ float threshold, float hermite_num);
/**
* Destructor
*/
- ~Octree ( ) ;
+ ~Octree();
/**
* Scan convert
*/
- void scanConvert() ;
+ void scanConvert();
void *getOutputMesh() { return output_mesh; }
@@ -226,164 +225,129 @@ private:
/**
* Initialize memory allocators
*/
- void initMemory ( ) ;
+ void initMemory();
/**
* Release memory
*/
- void freeMemory ( ) ;
+ void freeMemory();
/**
* Print memory usage
*/
- void printMemUsage( ) ;
+ void printMemUsage();
/**
* Methods to set / restore minimum edges
*/
- void resetMinimalEdges( ) ;
+ void resetMinimalEdges();
- void cellProcParity ( UCHAR* node, int leaf, int depth ) ;
- void faceProcParity ( UCHAR* node[2], int leaf[2], int depth[2], int maxdep, int dir ) ;
- void edgeProcParity ( UCHAR* node[4], int leaf[4], int depth[4], int maxdep, int dir ) ;
+ void cellProcParity(Node* node, int leaf, int depth);
+ void faceProcParity(Node* node[2], int leaf[2], int depth[2], int maxdep, int dir);
+ void edgeProcParity(Node* node[4], int leaf[4], int depth[4], int maxdep, int dir);
- void processEdgeParity ( UCHAR* node[4], int depths[4], int maxdep, int dir ) ;
+ void processEdgeParity(LeafNode* node[4], int depths[4], int maxdep, int dir);
/**
* Add triangles to the tree
*/
- void addTrian ( );
- void addTrian ( Triangle* trian, int triind );
- UCHAR* addTrian ( UCHAR* node, Projections* p, int height );
+ void addTrian();
+ void addTrian(Triangle* trian, int triind);
+ InternalNode* addTrian(InternalNode* node, Projections* p, int height);
/**
* Method to update minimizer in a cell: update edge intersections instead
*/
- UCHAR* updateCell( UCHAR* node, Projections* p ) ;
+ LeafNode* updateCell(LeafNode* node, Projections* p);
/* Routines to detect and patch holes */
- int numRings ;
- int totRingLengths ;
- int maxRingLength ;
+ int numRings;
+ int totRingLengths;
+ int maxRingLength;
/**
* Entry routine.
*/
- void trace ( ) ;
+ void trace();
/**
* Trace the given node, find patches and fill them in
*/
- UCHAR* trace ( UCHAR* node, int* st, int len, int depth, PathList*& paths ) ;
+ Node* trace(Node* node, int* st, int len, int depth, PathList*& paths);
/**
* Look for path on the face and add to paths
*/
- void findPaths ( UCHAR* node[2], int leaf[2], int depth[2], int* st[2], int maxdep, int dir, PathList*& paths ) ;
+ void findPaths(Node* node[2], int leaf[2], int depth[2], int* st[2], int maxdep, int dir, PathList*& paths);
/**
* Combine two list1 and list2 into list1 using connecting paths list3,
* while closed paths are appended to rings
*/
- void combinePaths ( PathList*& list1, PathList* list2, PathList* paths, PathList*& rings ) ;
+ void combinePaths(PathList*& list1, PathList* list2, PathList* paths, PathList*& rings);
/**
* Helper function: combine current paths in list1 and list2 to a single path and append to list3
*/
- PathList* combineSinglePath ( PathList*& head1, PathList* pre1, PathList*& list1, PathList*& head2, PathList* pre2, PathList*& list2 ) ;
+ PathList* combineSinglePath(PathList*& head1, PathList* pre1, PathList*& list1, PathList*& head2, PathList* pre2, PathList*& list2);
/**
* Functions to patch rings in a node
*/
- UCHAR* patch ( UCHAR* node, int st[3], int len, PathList* rings ) ;
- UCHAR* patchSplit ( UCHAR* node, int st[3], int len, PathList* rings, int dir, PathList*& nrings1, PathList*& nrings2 ) ;
- UCHAR* patchSplitSingle ( UCHAR* node, int st[3], int len, PathElement* head, int dir, PathList*& nrings1, PathList*& nrings2 ) ;
- UCHAR* connectFace ( UCHAR* node, int st[3], int len, int dir, PathElement* f1, PathElement* f2 ) ;
- UCHAR* locateCell( UCHAR* node, int st[3], int len, int ori[3], int dir, int side, UCHAR*& rleaf, int rst[3], int& rlen ) ;
- void compressRing ( PathElement*& ring ) ;
- void getFacePoint( PathElement* leaf, int dir, int& x, int& y, float& p, float& q ) ;
- UCHAR* patchAdjacent( UCHAR* node, int len, int st1[3], UCHAR* leaf1, int st2[3], UCHAR* leaf2, int walkdir, int inc, int dir, int side, float alpha ) ;
- int findPair ( PathElement* head, int pos, int dir, PathElement*& pre1, PathElement*& pre2 ) ;
- int getSide( PathElement* e, int pos, int dir ) ;
- int isEqual( PathElement* e1, PathElement* e2 ) ;
- void preparePrimalEdgesMask( UCHAR* node ) ;
- void testFacePoint( PathElement* e1, PathElement* e2 ) ;
+ Node* patch(Node* node, int st[3], int len, PathList* rings);
+ Node* patchSplit(Node* node, int st[3], int len, PathList* rings, int dir, PathList*& nrings1, PathList*& nrings2);
+ Node* patchSplitSingle(Node* node, int st[3], int len, PathElement* head, int dir, PathList*& nrings1, PathList*& nrings2);
+ Node* connectFace(Node* node, int st[3], int len, int dir, PathElement* f1, PathElement* f2);
+ Node* locateCell(InternalNode* node, int st[3], int len, int ori[3], int dir, int side, Node*& rleaf, int rst[3], int& rlen);
+ void compressRing(PathElement*& ring);
+ void getFacePoint(PathElement* leaf, int dir, int& x, int& y, float& p, float& q);
+ LeafNode* patchAdjacent(InternalNode* node, int len, int st1[3], LeafNode* leaf1, int st2[3], LeafNode* leaf2, int walkdir, int inc, int dir, int side, float alpha);
+ int findPair(PathElement* head, int pos, int dir, PathElement*& pre1, PathElement*& pre2);
+ int getSide(PathElement* e, int pos, int dir);
+ int isEqual(PathElement* e1, PathElement* e2) ;
+ void preparePrimalEdgesMask(InternalNode* node);
+ void testFacePoint(PathElement* e1, PathElement* e2);
/**
* Path-related functions
*/
- void deletePath ( PathList*& head, PathList* pre, PathList*& curr ) ;
- void printPath( PathList* path ) ;
- void printPath( PathElement* path ) ;
- void printElement( PathElement* ele ) ;
- void printPaths( PathList* path ) ;
- void checkElement ( PathElement* ele ) ;
- void checkPath( PathElement* path ) ;
+ void deletePath(PathList*& head, PathList* pre, PathList*& curr);
+ void printPath(PathList* path);
+ void printPath(PathElement* path);
+ void printElement(PathElement* ele);
+ void printPaths(PathList* path);
+ void checkElement(PathElement* ele);
+ void checkPath(PathElement* path);
/**
* Routines to build signs to create a partitioned volume
- * (after patching rings)
+ *(after patching rings)
*/
- void buildSigns( ) ;
- void buildSigns( unsigned char table[], UCHAR* node, int isLeaf, int sg, int rvalue[8] ) ;
+ void buildSigns();
+ void buildSigns(unsigned char table[], Node* node, int isLeaf, int sg, int rvalue[8]);
/************************************************************************/
/* To remove disconnected components */
/************************************************************************/
- void floodFill( ) ;
- void clearProcessBits( UCHAR* node, int height ) ;
- int floodFill( UCHAR* node, int st[3], int len, int height, int threshold ) ;
+ void floodFill();
+ void clearProcessBits(Node* node, int height);
+ int floodFill(LeafNode* leaf, int st[3], int len, int height, int threshold);
+ int floodFill(Node* node, int st[3], int len, int height, int threshold);
/**
* Write out polygon file
*/
void writeOut();
- void writeOFF ( char* fname ) ;
- void writePLY ( char* fname ) ;
- void writeOpenEdges( FILE* fout ) ;
- void writeAllEdges( FILE* fout, int mode ) ;
- void writeAllEdges( FILE* fout, UCHAR* node, int height, int st[3], int len, int mode ) ;
- void writeOctree( char* fname ) ;
- void writeOctree( FILE* fout, UCHAR* node, int depth ) ;
-#ifdef USE_HERMIT
- void writeOctreeGeom( char* fname ) ;
- void writeOctreeGeom( FILE* fout, UCHAR* node, int st[3], int len, int depth ) ;
-#endif
-#ifdef USE_HERMIT
- void writeDCF ( char* fname ) ;
- void writeDCF ( FILE* fout, UCHAR* node, int height, int st[3], int len ) ;
- void countEdges ( UCHAR* node, int height, int& nedge, int mode ) ;
- void countIntersection( UCHAR* node, int height, int& nedge, int& ncell, int& nface ) ;
- void generateMinimizer( UCHAR* node, int st[3], int len, int height, int& offset ) ;
- void computeMinimizer( UCHAR* leaf, int st[3], int len, float rvalue[3] ) ;
+ void countIntersection(Node* node, int height, int& nedge, int& ncell, int& nface);
+ void generateMinimizer(Node* node, int st[3], int len, int height, int& offset);
+ void computeMinimizer(LeafNode* leaf, int st[3], int len, float rvalue[3]);
/**
* Traversal functions to generate polygon model
* op: 0 for counting, 1 for writing OBJ, 2 for writing OFF, 3 for writing PLY
*/
- void cellProcContour ( UCHAR* node, int leaf, int depth ) ;
- void faceProcContour ( UCHAR* node[2], int leaf[2], int depth[2], int maxdep, int dir ) ;
- void edgeProcContour ( UCHAR* node[4], int leaf[4], int depth[4], int maxdep, int dir ) ;
- void processEdgeWrite ( UCHAR* node[4], int depths[4], int maxdep, int dir ) ;
-#else
- void countIntersection( UCHAR* node, int height, int& nquad, int& nvert ) ;
- void writeVertex( UCHAR* node, int st[3], int len, int height, int& offset, FILE* fout ) ;
- void writeQuad( UCHAR* node, int st[3], int len, int height, FILE* fout ) ;
-#endif
-
- /**
- * Write out original model
- */
- void writeModel( char* fname ) ;
-
- /************************************************************************/
- /* Write out original vertex tags */
- /************************************************************************/
-#ifdef CINDY
- void writeTags( char* fname ) ;
- void readVertices( ) ;
- void readVertex( UCHAR* node, int st[3], int len, int height, float v[3], int index ) ;
- void outputTags( UCHAR* node, int height, FILE* fout ) ;
- void clearCindyBits( UCHAR* node, int height ) ;
-#endif
+ void cellProcContour(Node* node, int leaf, int depth);
+ void faceProcContour(Node* node[2], int leaf[2], int depth[2], int maxdep, int dir);
+ void edgeProcContour(Node* node[4], int leaf[4], int depth[4], int maxdep, int dir);
+ void processEdgeWrite(Node* node[4], int depths[4], int maxdep, int dir);
/* output callbacks/data */
DualConAllocOutput alloc_output;
@@ -394,858 +358,753 @@ private:
private:
/************ Operators for all nodes ************/
- /**
- * Bits order
- *
- * Leaf node:
- * Byte 0,1 (0-11): edge parity
- * Byte 1 (4,5,6): mask of primary edges intersections stored
- * Byte 1 (7): in flood fill mode, whether the cell is in process
- * Byte 2 (0-8): signs
- * Byte 3 (or 5) -- : edge intersections ( 4 bytes per inter, or 12 bytes if USE_HERMIT )
- * Byte 3,4: in coloring mode, the mask for edges
- *
- * Internal node:
- * Byte 0: child mask
- * Byte 1: leaf child mask
- */
-
/// Lookup table
- int numChildrenTable[ 256 ] ;
- int childrenCountTable[ 256 ][ 8 ] ;
- int childrenIndexTable[ 256 ][ 8 ] ;
- int numEdgeTable[ 8 ] ;
- int edgeCountTable[ 8 ][ 3 ] ;
+ int numChildrenTable[256];
+ int childrenCountTable[256][8];
+ int childrenIndexTable[256][8];
+ int numEdgeTable[8];
+ int edgeCountTable[8][3];
/// Build up lookup table
- void buildTable ( )
+ void buildTable()
{
- for ( int i = 0 ; i < 256 ; i ++ )
+ for(int i = 0; i < 256; i ++)
{
- numChildrenTable[ i ] = 0 ;
- int count = 0 ;
- for ( int j = 0 ; j < 8 ; j ++ )
+ numChildrenTable[i] = 0;
+ int count = 0;
+ for(int j = 0; j < 8; j ++)
{
- numChildrenTable[ i ] += ( ( i >> j ) & 1 ) ;
- childrenCountTable[ i ][ j ] = count ;
- childrenIndexTable[ i ][ count ] = j ;
- count += ( ( i >> j ) & 1 ) ;
+ numChildrenTable[i] +=((i >> j) & 1);
+ childrenCountTable[i][j] = count;
+ childrenIndexTable[i][count] = j;
+ count +=((i >> j) & 1);
}
}
- for ( int i = 0 ; i < 8 ; i ++ )
+ for(int i = 0; i < 8; i ++)
{
- numEdgeTable[ i ] = 0 ;
- int count = 0 ;
- for ( int j = 0 ; j < 3 ; j ++ )
+ numEdgeTable[i] = 0;
+ int count = 0;
+ for(int j = 0; j < 3; j ++)
{
- numEdgeTable[ i ] += ( ( i >> j ) & 1 ) ;
- edgeCountTable[ i ][ j ] = count ;
- count += ( ( i >> j ) & 1 ) ;
+ numEdgeTable[i] +=((i >> j) & 1);
+ edgeCountTable[i][j] = count;
+ count +=((i >> j) & 1);
}
}
- };
+ }
- int getSign( UCHAR* node, int height, int index )
+ int getSign(Node* node, int height, int index)
{
- if ( height == 0 )
+ if(height == 0)
{
- return getSign( node, index ) ;
+ return getSign(&node->leaf, index);
}
else
{
- if ( hasChild( node, index ) )
+ if(hasChild(&node->internal, index))
{
- return getSign( getChild( node, getChildCount( node, index ) ), height - 1, index ) ;
+ return getSign(getChild(&node->internal, getChildCount(&node->internal, index)),
+ height - 1,
+ index);
}
else
{
- return getSign( getChild( node, 0 ), height - 1, 7 - getChildIndex( node, 0 ) ) ;
+ return getSign(getChild(&node->internal, 0),
+ height - 1,
+ 7 - getChildIndex(&node->internal, 0));
}
}
}
/************ Operators for leaf nodes ************/
- void printInfo( int st[3] )
+ void printInfo(int st[3])
{
- printf("INFO AT: %d %d %d\n", st[0] >> minshift, st[1] >>minshift, st[2] >> minshift ) ;
- UCHAR* leaf = locateLeafCheck( st ) ;
- if ( leaf == NULL )
- {
- printf("Leaf not exists!\n") ;
- }
+ printf("INFO AT: %d %d %d\n", st[0] >> minshift, st[1] >>minshift, st[2] >> minshift);
+ LeafNode* leaf = (LeafNode*)locateLeafCheck(st);
+ if(leaf)
+ printInfo(leaf);
else
- {
- printInfo( leaf ) ;
- }
+ printf("Leaf not exists!\n");
}
- void printInfo( UCHAR* leaf )
+ void printInfo(const LeafNode* leaf)
{
/*
- printf("Edge mask: ") ;
- for ( int i = 0 ; i < 12 ; i ++ )
+ printf("Edge mask: ");
+ for(int i = 0; i < 12; i ++)
{
- printf("%d ", getEdgeParity( leaf, i ) ) ;
+ printf("%d ", getEdgeParity(leaf, i));
}
- printf("\n") ;
- printf("Stored edge mask: ") ;
- for ( i = 0 ; i < 3 ; i ++ )
+ printf("\n");
+ printf("Stored edge mask: ");
+ for(i = 0; i < 3; i ++)
{
- printf("%d ", getStoredEdgesParity( leaf, i ) ) ;
+ printf("%d ", getStoredEdgesParity(leaf, i));
}
- printf("\n") ;
+ printf("\n");
*/
- printf("Sign mask: ") ;
- for ( int i = 0 ; i < 8 ; i ++ )
+ printf("Sign mask: ");
+ for(int i = 0; i < 8; i ++)
{
- printf("%d ", getSign( leaf, i ) ) ;
+ printf("%d ", getSign(leaf, i));
}
- printf("\n") ;
+ printf("\n");
}
/// Retrieve signs
- int getSign ( UCHAR* leaf, int index )
+ int getSign(const LeafNode* leaf, int index)
{
- return (( leaf[2] >> index ) & 1 );
- };
+ return ((leaf->signs >> index) & 1);
+ }
/// Set sign
- void setSign ( UCHAR* leaf, int index )
+ void setSign(LeafNode* leaf, int index)
{
- leaf[2] |= ( 1 << index ) ;
- };
+ leaf->signs |= (1 << index);
+ }
- void setSign ( UCHAR* leaf, int index, int sign )
+ void setSign(LeafNode* leaf, int index, int sign)
{
- leaf[2] &= ( ~ ( 1 << index ) ) ;
- leaf[2] |= ( ( sign & 1 ) << index ) ;
- };
+ leaf->signs &= (~(1 << index));
+ leaf->signs |= ((sign & 1) << index);
+ }
- int getSignMask( UCHAR* leaf )
+ int getSignMask(const LeafNode* leaf)
{
- return leaf[2] ;
+ return leaf->signs;
}
- void setInProcessAll( int st[3], int dir )
+ void setInProcessAll(int st[3], int dir)
{
- int nst[3], eind ;
- for ( int i = 0 ; i < 4 ; i ++ )
+ int nst[3], eind;
+ for(int i = 0; i < 4; i ++)
{
- nst[0] = st[0] + dirCell[dir][i][0] * mindimen ;
- nst[1] = st[1] + dirCell[dir][i][1] * mindimen ;
- nst[2] = st[2] + dirCell[dir][i][2] * mindimen ;
- eind = dirEdge[dir][i] ;
+ nst[0] = st[0] + dirCell[dir][i][0] * mindimen;
+ nst[1] = st[1] + dirCell[dir][i][1] * mindimen;
+ nst[2] = st[2] + dirCell[dir][i][2] * mindimen;
+ eind = dirEdge[dir][i];
- UCHAR* cell = locateLeafCheck( nst ) ;
- if ( cell == NULL )
- {
- printf("Wrong!\n") ;
- }
- setInProcess( cell, eind ) ;
+ LeafNode* cell = locateLeafCheck(nst);
+ assert(cell);
+
+ setInProcess(cell, eind);
}
}
- void flipParityAll( int st[3], int dir )
+ void flipParityAll(int st[3], int dir)
{
- int nst[3], eind ;
- for ( int i = 0 ; i < 4 ; i ++ )
+ int nst[3], eind;
+ for(int i = 0; i < 4; i ++)
{
- nst[0] = st[0] + dirCell[dir][i][0] * mindimen ;
- nst[1] = st[1] + dirCell[dir][i][1] * mindimen ;
- nst[2] = st[2] + dirCell[dir][i][2] * mindimen ;
- eind = dirEdge[dir][i] ;
+ nst[0] = st[0] + dirCell[dir][i][0] * mindimen;
+ nst[1] = st[1] + dirCell[dir][i][1] * mindimen;
+ nst[2] = st[2] + dirCell[dir][i][2] * mindimen;
+ eind = dirEdge[dir][i];
- UCHAR* cell = locateLeaf( nst ) ;
- flipEdge( cell, eind ) ;
+ LeafNode* cell = locateLeaf(nst);
+ flipEdge(cell, eind);
}
}
- void setInProcess( UCHAR* leaf, int eind )
- {
- // leaf[1] |= ( 1 << 7 ) ;
- ( (USHORT*) (leaf + leaf_node_bytes - (flood_bytes + CINDY_BYTES)))[0] |= ( 1 << eind ) ;
- }
- void setOutProcess( UCHAR* leaf, int eind )
- {
- // leaf[1] &= ( ~ ( 1 << 7 ) ) ;
- ( (USHORT*) (leaf + leaf_node_bytes - (flood_bytes + CINDY_BYTES)))[0] &= ( ~ ( 1 << eind ) ) ;
- }
-
- int isInProcess( UCHAR* leaf, int eind )
+ void setInProcess(LeafNode* leaf, int eind)
{
- //int a = ( ( leaf[1] >> 7 ) & 1 ) ;
- int a = ( ( ( (USHORT*) (leaf + leaf_node_bytes - (flood_bytes + CINDY_BYTES)))[0] >> eind ) & 1 ) ;
- return a ;
- }
+ assert(eind >= 0 && eind <= 11);
-#ifndef USE_HERMIT
- /// Set minimizer index
- void setEdgeIntersectionIndex( UCHAR* leaf, int count, int index )
- {
- ((int *)( leaf + leaf_node_bytes ))[ count ] = index ;
+ leaf->flood_fill |= (1 << eind);
}
-
- /// Get minimizer index
- int getEdgeIntersectionIndex( UCHAR* leaf, int count )
+
+ void setOutProcess(LeafNode* leaf, int eind)
{
- return ((int *)( leaf + leaf_node_bytes ))[ count ] ;
+ assert(eind >= 0 && eind <= 11);
+
+ leaf->flood_fill &= ~(1 << eind);
}
- /// Get all intersection indices associated with a cell
- void fillEdgeIntersectionIndices( UCHAR* leaf, int st[3], int len, int inds[12] )
+ int isInProcess(LeafNode* leaf, int eind)
{
- int i ;
-
- // The three primal edges are easy
- int pmask[3] = { 0, 4, 8 } ;
- for ( i = 0 ; i < 3 ; i ++ )
- {
- if ( getEdgeParity( leaf, pmask[i] ) )
- {
- inds[pmask[i]] = getEdgeIntersectionIndex( leaf, getEdgeCount( leaf, i ) ) ;
- }
- }
+ assert(eind >= 0 && eind <= 11);
- // 3 face adjacent cubes
- int fmask[3][2] = {{6,10},{2,9},{1,5}} ;
- int femask[3][2] = {{1,2},{0,2},{0,1}} ;
- for ( i = 0 ; i < 3 ; i ++ )
- {
- int e1 = getEdgeParity( leaf, fmask[i][0] ) ;
- int e2 = getEdgeParity( leaf, fmask[i][1] ) ;
- if ( e1 || e2 )
- {
- int nst[3] = {st[0], st[1], st[2]} ;
- nst[ i ] += len ;
- // int nstt[3] = {0, 0, 0} ;
- // nstt[ i ] += 1 ;
- UCHAR* node = locateLeaf( nst ) ;
-
- if ( e1 )
- {
- inds[ fmask[i][0] ] = getEdgeIntersectionIndex( node, getEdgeCount( node, femask[i][0] ) ) ;
- }
- if ( e2 )
- {
- inds[ fmask[i][1] ] = getEdgeIntersectionIndex( node, getEdgeCount( node, femask[i][1] ) ) ;
- }
- }
- }
-
- // 3 edge adjacent cubes
- int emask[3] = {3, 7, 11} ;
- int eemask[3] = {0, 1, 2} ;
- for ( i = 0 ; i < 3 ; i ++ )
- {
- if ( getEdgeParity( leaf, emask[i] ) )
- {
- int nst[3] = {st[0] + len, st[1] + len, st[2] + len} ;
- nst[ i ] -= len ;
- // int nstt[3] = {1, 1, 1} ;
- // nstt[ i ] -= 1 ;
- UCHAR* node = locateLeaf( nst ) ;
-
- inds[ emask[i] ] = getEdgeIntersectionIndex( node, getEdgeCount( node, eemask[i] ) ) ;
- }
- }
+ return (leaf->flood_fill >> eind) & 1;
}
-
-#endif
-
/// Generate signs at the corners from the edge parity
- void generateSigns ( UCHAR* leaf, UCHAR table[], int start )
+ void generateSigns(LeafNode* leaf, unsigned char table[], int start)
{
- leaf[2] = table[ ( ((USHORT *) leaf)[ 0 ] ) & ( ( 1 << 12 ) - 1 ) ] ;
+ leaf->signs = table[leaf->edge_parity];
- if ( ( start ^ leaf[2] ) & 1 )
+ if((start ^ leaf->signs) & 1)
{
- leaf[2] = ~ ( leaf[2] ) ;
+ leaf->signs = ~(leaf->signs);
}
}
/// Get edge parity
- int getEdgeParity( UCHAR* leaf, int index )
+ int getEdgeParity(LeafNode* leaf, int index)
{
- int a = ( ( ((USHORT *) leaf)[ 0 ] >> index ) & 1 ) ;
- return a ;
- };
+ assert(index >= 0 && index <= 11);
+
+ return (leaf->edge_parity >> index) & 1;
+ }
/// Get edge parity on a face
- int getFaceParity ( UCHAR* leaf, int index )
+ int getFaceParity(LeafNode* leaf, int index)
{
- int a = getEdgeParity( leaf, faceMap[ index ][ 0 ] ) +
- getEdgeParity( leaf, faceMap[ index ][ 1 ] ) +
- getEdgeParity( leaf, faceMap[ index ][ 2 ] ) +
- getEdgeParity( leaf, faceMap[ index ][ 3 ] ) ;
- return ( a & 1 ) ;
+ int a = getEdgeParity(leaf, faceMap[index][0]) +
+ getEdgeParity(leaf, faceMap[index][1]) +
+ getEdgeParity(leaf, faceMap[index][2]) +
+ getEdgeParity(leaf, faceMap[index][3]);
+ return (a & 1);
}
- int getFaceEdgeNum ( UCHAR* leaf, int index )
+ int getFaceEdgeNum(LeafNode* leaf, int index)
{
- int a = getEdgeParity( leaf, faceMap[ index ][ 0 ] ) +
- getEdgeParity( leaf, faceMap[ index ][ 1 ] ) +
- getEdgeParity( leaf, faceMap[ index ][ 2 ] ) +
- getEdgeParity( leaf, faceMap[ index ][ 3 ] ) ;
- return a ;
+ int a = getEdgeParity(leaf, faceMap[index][0]) +
+ getEdgeParity(leaf, faceMap[index][1]) +
+ getEdgeParity(leaf, faceMap[index][2]) +
+ getEdgeParity(leaf, faceMap[index][3]);
+ return a;
}
/// Set edge parity
- void flipEdge( UCHAR* leaf, int index )
+ void flipEdge(LeafNode* leaf, int index)
{
- ((USHORT *) leaf)[ 0 ] ^= ( 1 << index ) ;
- };
+ assert(index >= 0 && index <= 11);
+
+ leaf->edge_parity ^= (1 << index);
+ }
+
/// Set 1
- void setEdge( UCHAR* leaf, int index )
+ void setEdge(LeafNode* leaf, int index)
{
- ((USHORT *) leaf)[ 0 ] |= ( 1 << index ) ;
- };
+ assert(index >= 0 && index <= 11);
+
+ leaf->edge_parity |= (1 << index);
+ }
+
/// Set 0
- void resetEdge( UCHAR* leaf, int index )
+ void resetEdge(LeafNode* leaf, int index)
{
- ((USHORT *) leaf)[ 0 ] &= ( ~ ( 1 << index ) ) ;
- };
+ assert(index >= 0 && index <= 11);
+
+ leaf->edge_parity &= ~(1 << index);
+ }
/// Flipping with a new intersection offset
- void createPrimalEdgesMask( UCHAR* leaf )
+ void createPrimalEdgesMask(LeafNode* leaf)
{
- int mask = (( leaf[0] & 1 ) | ( (leaf[0] >> 3) & 2 ) | ( (leaf[1] & 1) << 2 ) ) ;
- leaf[1] |= ( mask << 4 ) ;
-
+ leaf->primary_edge_intersections = getPrimalEdgesMask2(leaf);
}
- void setStoredEdgesParity( UCHAR* leaf, int pindex )
+ void setStoredEdgesParity(LeafNode* leaf, int pindex)
{
- leaf[1] |= ( 1 << ( 4 + pindex ) ) ;
+ assert(pindex <= 2 && pindex >= 0);
+
+ leaf->primary_edge_intersections |= (1 << pindex);
}
- int getStoredEdgesParity( UCHAR* leaf, int pindex )
+ int getStoredEdgesParity(LeafNode* leaf, int pindex)
{
- return ( ( leaf[1] >> ( 4 + pindex ) ) & 1 ) ;
+ assert(pindex <= 2 && pindex >= 0);
+
+ return (leaf->primary_edge_intersections >> pindex) & 1;
}
- UCHAR* flipEdge( UCHAR* leaf, int index, float alpha )
+ LeafNode* flipEdge(LeafNode* leaf, int index, float alpha)
{
- flipEdge( leaf, index ) ;
+ flipEdge(leaf, index);
- if ( ( index & 3 ) == 0 )
+ if((index & 3) == 0)
{
- int ind = index / 4 ;
- if ( getEdgeParity( leaf, index ) && ! getStoredEdgesParity( leaf, ind ) )
+ int ind = index / 4;
+ if(getEdgeParity(leaf, index) && ! getStoredEdgesParity(leaf, ind))
{
// Create a new node
- int num = getNumEdges( leaf ) + 1 ;
- setStoredEdgesParity( leaf, ind ) ;
- int count = getEdgeCount( leaf, ind ) ;
- UCHAR* nleaf = createLeaf( num ) ;
- for ( int i = 0 ; i < leaf_node_bytes ; i ++ )
- {
- nleaf[i] = leaf[i] ;
- }
+ int num = getNumEdges(leaf) + 1;
+ setStoredEdgesParity(leaf, ind);
+ int count = getEdgeCount(leaf, ind);
+ LeafNode* nleaf = createLeaf(num);
+ *nleaf = *leaf;
- setEdgeOffset( nleaf, alpha, count ) ;
+ setEdgeOffset(nleaf, alpha, count);
- if ( num > 1 )
+ if(num > 1)
{
- float * pts = ( float * ) ( leaf + leaf_node_bytes ) ;
- float * npts = ( float * ) ( nleaf + leaf_node_bytes ) ;
- for ( int i = 0 ; i < count ; i ++ )
+ float *pts = leaf->edge_intersections;
+ float *npts = nleaf->edge_intersections;
+ for(int i = 0; i < count; i ++)
{
- for ( int j = 0 ; j < EDGE_FLOATS ; j ++ )
+ for(int j = 0; j < EDGE_FLOATS; j ++)
{
- npts[i * EDGE_FLOATS + j] = pts[i * EDGE_FLOATS + j] ;
+ npts[i * EDGE_FLOATS + j] = pts[i * EDGE_FLOATS + j];
}
}
- for ( int i = count + 1 ; i < num ; i ++ )
+ for(int i = count + 1; i < num; i ++)
{
- for ( int j = 0 ; j < EDGE_FLOATS ; j ++ )
+ for(int j = 0; j < EDGE_FLOATS; j ++)
{
- npts[i * EDGE_FLOATS + j] = pts[ (i - 1) * EDGE_FLOATS + j] ;
+ npts[i * EDGE_FLOATS + j] = pts[(i - 1) * EDGE_FLOATS + j];
}
}
}
- removeLeaf( num-1, leaf ) ;
- leaf = nleaf ;
+ removeLeaf(num-1, (LeafNode*)leaf);
+ leaf = nleaf;
}
}
- return leaf ;
- };
+ return leaf;
+ }
/// Update parent link
- void updateParent( UCHAR* node, int len, int st[3], UCHAR* leaf )
+ void updateParent(InternalNode* node, int len, int st[3], LeafNode* leaf)
{
// First, locate the parent
- int count ;
- UCHAR* parent = locateParent( node, len, st, count ) ;
+ int count;
+ InternalNode* parent = locateParent(node, len, st, count);
- // UPdate
- setChild( parent, count, leaf ) ;
+ // Update
+ setChild(parent, count, (Node*)leaf);
}
- void updateParent( UCHAR* node, int len, int st[3] )
+ void updateParent(InternalNode* node, int len, int st[3])
{
- if ( len == dimen )
+ if(len == dimen)
{
- root = node ;
- return ;
+ root = (Node*)node;
+ return;
}
// First, locate the parent
- int count ;
- UCHAR* parent = locateParent( len, st, count ) ;
+ int count;
+ InternalNode* parent = locateParent(len, st, count);
// UPdate
- setChild( parent, count, node ) ;
+ setChild(parent, count, (Node*)node);
}
/// Find edge intersection on a given edge
- int getEdgeIntersectionByIndex( int st[3], int index, float pt[3], int check )
+ int getEdgeIntersectionByIndex(int st[3], int index, float pt[3], int check)
{
// First, locat the leaf
- UCHAR* leaf ;
- if ( check )
+ LeafNode* leaf;
+ if(check)
{
- leaf = locateLeafCheck( st ) ;
+ leaf = locateLeafCheck(st);
}
else
{
- leaf = locateLeaf( st ) ;
+ leaf = locateLeaf(st);
}
- if ( leaf && getStoredEdgesParity( leaf, index ) )
+ if(leaf && getStoredEdgesParity(leaf, index))
{
- float off = getEdgeOffset( leaf, getEdgeCount( leaf, index ) ) ;
- pt[0] = (float) st[0] ;
- pt[1] = (float) st[1] ;
- pt[2] = (float) st[2] ;
- pt[index] += off * mindimen ;
+ float off = getEdgeOffset(leaf, getEdgeCount(leaf, index));
+ pt[0] =(float) st[0];
+ pt[1] =(float) st[1];
+ pt[2] =(float) st[2];
+ pt[index] += off * mindimen;
- return 1 ;
+ return 1;
}
else
{
- return 0 ;
+ return 0;
}
}
/// Retrieve number of edges intersected
- int getPrimalEdgesMask( UCHAR* leaf )
+ int getPrimalEdgesMask(LeafNode* leaf)
{
- // return (( leaf[0] & 1 ) | ( (leaf[0] >> 3) & 2 ) | ( (leaf[1] & 1) << 2 ) ) ;
- return ( ( leaf[1] >> 4 ) & 7 ) ;
+ return leaf->primary_edge_intersections;
}
- int getPrimalEdgesMask2( UCHAR* leaf )
+ int getPrimalEdgesMask2(LeafNode* leaf)
{
- return (( leaf[0] & 1 ) | ( (leaf[0] >> 3) & 2 ) | ( (leaf[1] & 1) << 2 ) ) ;
+ return (((leaf->edge_parity & 0x1) >> 0) |
+ ((leaf->edge_parity & 0x10) >> 3) |
+ ((leaf->edge_parity & 0x100) >> 6));
}
/// Get the count for a primary edge
- int getEdgeCount( UCHAR* leaf, int index )
+ int getEdgeCount(LeafNode* leaf, int index)
{
- return edgeCountTable[ getPrimalEdgesMask( leaf ) ][ index ] ;
+ return edgeCountTable[getPrimalEdgesMask(leaf)][index];
}
- int getNumEdges( UCHAR* leaf )
+ int getNumEdges(LeafNode* leaf)
{
- return numEdgeTable[ getPrimalEdgesMask( leaf ) ] ;
+ return numEdgeTable[getPrimalEdgesMask(leaf)];
}
- int getNumEdges2( UCHAR* leaf )
+ int getNumEdges2(LeafNode* leaf)
{
- return numEdgeTable[ getPrimalEdgesMask2( leaf ) ] ;
+ return numEdgeTable[getPrimalEdgesMask2(leaf)];
}
/// Set edge intersection
- void setEdgeOffset( UCHAR* leaf, float pt, int count )
- {
- float * pts = ( float * ) ( leaf + leaf_node_bytes ) ;
-#ifdef USE_HERMIT
- pts[ EDGE_FLOATS * count ] = pt ;
- pts[ EDGE_FLOATS * count + 1 ] = 0 ;
- pts[ EDGE_FLOATS * count + 2 ] = 0 ;
- pts[ EDGE_FLOATS * count + 3 ] = 0 ;
-#else
- pts[ count ] = pt ;
-#endif
+ void setEdgeOffset(LeafNode* leaf, float pt, int count)
+ {
+ float *pts = leaf->edge_intersections;
+ pts[EDGE_FLOATS * count] = pt;
+ pts[EDGE_FLOATS * count + 1] = 0;
+ pts[EDGE_FLOATS * count + 2] = 0;
+ pts[EDGE_FLOATS * count + 3] = 0;
}
/// Set multiple edge intersections
- void setEdgeOffsets( UCHAR* leaf, float pt[3], int len )
+ void setEdgeOffsets(LeafNode* leaf, float pt[3], int len)
{
- float * pts = ( float * ) ( leaf + leaf_node_bytes ) ;
- for ( int i = 0 ; i < len ; i ++ )
+ float * pts = leaf->edge_intersections;
+ for(int i = 0; i < len; i ++)
{
- pts[i] = pt[i] ;
+ pts[i] = pt[i];
}
}
/// Retrieve edge intersection
- float getEdgeOffset( UCHAR* leaf, int count )
+ float getEdgeOffset(LeafNode* leaf, int count)
{
-#ifdef USE_HERMIT
- return (( float * ) ( leaf + leaf_node_bytes ))[ 4 * count ] ;
-#else
- return (( float * ) ( leaf + leaf_node_bytes ))[ count ] ;
-#endif
+ return leaf->edge_intersections[4 * count];
}
/// Update method
- UCHAR* updateEdgeOffsets( UCHAR* leaf, int oldlen, int newlen, float offs[3] )
+ LeafNode* updateEdgeOffsets(LeafNode* leaf, int oldlen, int newlen, float offs[3])
{
// First, create a new leaf node
- UCHAR* nleaf = createLeaf( newlen ) ;
- for ( int i = 0 ; i < leaf_node_bytes ; i ++ )
- {
- nleaf[i] = leaf[i] ;
- }
+ LeafNode* nleaf = createLeaf(newlen);
+ *nleaf = *leaf;
// Next, fill in the offsets
- setEdgeOffsets( nleaf, offs, newlen ) ;
+ setEdgeOffsets(nleaf, offs, newlen);
// Finally, delete the old leaf
- removeLeaf( oldlen, leaf ) ;
+ removeLeaf(oldlen, leaf);
- return nleaf ;
+ return nleaf;
}
- /// Set original vertex index
- void setOriginalIndex( UCHAR* leaf, int index )
- {
- ((int *)( leaf + leaf_node_bytes ))[ 0 ] = index ;
- }
- int getOriginalIndex( UCHAR* leaf )
- {
- return ((int *)( leaf + leaf_node_bytes ))[ 0 ] ;
- }
-#ifdef USE_HERMIT
/// Set minimizer index
- void setMinimizerIndex( UCHAR* leaf, int index )
+ void setMinimizerIndex(LeafNode* leaf, int index)
{
- ((int *)( leaf + leaf_node_bytes - leaf_extra_bytes - 4 ))[ 0 ] = index ;
+ leaf->minimizer_index = index;
}
/// Get minimizer index
- int getMinimizerIndex( UCHAR* leaf )
+ int getMinimizerIndex(LeafNode* leaf)
{
- return ((int *)( leaf + leaf_node_bytes - leaf_extra_bytes - 4 ))[ 0 ] ;
+ return leaf->minimizer_index;
}
- int getMinimizerIndex( UCHAR* leaf, int eind )
+ int getMinimizerIndex(LeafNode* leaf, int eind)
{
- int add = manifold_table[ getSignMask( leaf ) ].pairs[ eind ][ 0 ] - 1 ;
- if ( add < 0 )
- {
- printf("Manifold components wrong!\n") ;
- }
- return ((int *)( leaf + leaf_node_bytes - leaf_extra_bytes - 4 ))[ 0 ] + add ;
+ int add = manifold_table[getSignMask(leaf)].pairs[eind][0] - 1;
+ assert(add >= 0);
+ return leaf->minimizer_index + add;
}
- void getMinimizerIndices( UCHAR* leaf, int eind, int inds[2] )
+ void getMinimizerIndices(LeafNode* leaf, int eind, int inds[2])
{
- const int* add = manifold_table[ getSignMask( leaf ) ].pairs[ eind ] ;
- inds[0] = ((int *)( leaf + leaf_node_bytes - leaf_extra_bytes - 4 ))[ 0 ] + add[0] - 1 ;
- if ( add[0] == add[1] )
+ const int* add = manifold_table[getSignMask(leaf)].pairs[eind];
+ inds[0] = leaf->minimizer_index + add[0] - 1;
+ if(add[0] == add[1])
{
- inds[1] = -1 ;
+ inds[1] = -1;
}
else
{
- inds[1] = ((int *)( leaf + leaf_node_bytes - leaf_extra_bytes - 4 ))[ 0 ] + add[1] - 1 ;
+ inds[1] = leaf->minimizer_index + add[1] - 1;
}
}
/// Set edge intersection
- void setEdgeOffsetNormal( UCHAR* leaf, float pt, float a, float b, float c, int count )
+ void setEdgeOffsetNormal(LeafNode* leaf, float pt, float a, float b, float c, int count)
{
- float * pts = ( float * ) ( leaf + leaf_node_bytes ) ;
- pts[ 4 * count ] = pt ;
- pts[ 4 * count + 1 ] = a ;
- pts[ 4 * count + 2 ] = b ;
- pts[ 4 * count + 3 ] = c ;
+ float * pts = leaf->edge_intersections;
+ pts[4 * count] = pt;
+ pts[4 * count + 1] = a;
+ pts[4 * count + 2] = b;
+ pts[4 * count + 3] = c;
}
- float getEdgeOffsetNormal( UCHAR* leaf, int count, float& a, float& b, float& c )
+ float getEdgeOffsetNormal(LeafNode* leaf, int count, float& a, float& b, float& c)
{
- float * pts = ( float * ) ( leaf + leaf_node_bytes ) ;
- a = pts[ 4 * count + 1 ] ;
- b = pts[ 4 * count + 2 ] ;
- c = pts[ 4 * count + 3 ] ;
- return pts[ 4 * count ] ;
+ float * pts = leaf->edge_intersections;
+ a = pts[4 * count + 1];
+ b = pts[4 * count + 2];
+ c = pts[4 * count + 3];
+ return pts[4 * count];
}
/// Set multiple edge intersections
- void setEdgeOffsetsNormals( UCHAR* leaf, float pt[], float a[], float b[], float c[], int len )
+ void setEdgeOffsetsNormals(LeafNode* leaf, float pt[], float a[], float b[], float c[], int len)
{
- float * pts = ( float * ) ( leaf + leaf_node_bytes ) ;
- for ( int i = 0 ; i < len ; i ++ )
+ float *pts = leaf->edge_intersections;
+ for(int i = 0; i < len; i ++)
{
- if ( pt[i] > 1 || pt[i] < 0 )
+ if(pt[i] > 1 || pt[i] < 0)
{
- printf("\noffset: %f\n", pt[i]) ;
+ printf("\noffset: %f\n", pt[i]);
}
- pts[ i * 4 ] = pt[i] ;
- pts[ i * 4 + 1 ] = a[i] ;
- pts[ i * 4 + 2 ] = b[i] ;
- pts[ i * 4 + 3 ] = c[i] ;
+ pts[i * 4] = pt[i];
+ pts[i * 4 + 1] = a[i];
+ pts[i * 4 + 2] = b[i];
+ pts[i * 4 + 3] = c[i];
}
}
/// Retrieve complete edge intersection
- void getEdgeIntersectionByIndex( UCHAR* leaf, int index, int st[3], int len, float pt[3], float nm[3] )
+ void getEdgeIntersectionByIndex(LeafNode* leaf, int index, int st[3], int len, float pt[3], float nm[3])
{
- int count = getEdgeCount( leaf, index ) ;
- float * pts = ( float * ) ( leaf + leaf_node_bytes ) ;
+ int count = getEdgeCount(leaf, index);
+ float *pts = leaf->edge_intersections;
- float off = pts[ 4 * count ] ;
+ float off = pts[4 * count];
- pt[0] = (float) st[0] ;
- pt[1] = (float) st[1] ;
- pt[2] = (float) st[2] ;
- pt[ index ] += ( off * len ) ;
-
- nm[0] = pts[ 4 * count + 1 ] ;
- nm[1] = pts[ 4 * count + 2 ] ;
- nm[2] = pts[ 4 * count + 3 ] ;
+ pt[0] = (float) st[0];
+ pt[1] = (float) st[1];
+ pt[2] = (float) st[2];
+ pt[index] +=(off * len);
+
+ nm[0] = pts[4 * count + 1];
+ nm[1] = pts[4 * count + 2];
+ nm[2] = pts[4 * count + 3];
}
- float getEdgeOffsetNormalByIndex( UCHAR* leaf, int index, float nm[3] )
+ float getEdgeOffsetNormalByIndex(LeafNode* leaf, int index, float nm[3])
{
- int count = getEdgeCount( leaf, index ) ;
- float * pts = ( float * ) ( leaf + leaf_node_bytes ) ;
+ int count = getEdgeCount(leaf, index);
+ float *pts = leaf->edge_intersections;
- float off = pts[ 4 * count ] ;
+ float off = pts[4 * count];
- nm[0] = pts[ 4 * count + 1 ] ;
- nm[1] = pts[ 4 * count + 2 ] ;
- nm[2] = pts[ 4 * count + 3 ] ;
+ nm[0] = pts[4 * count + 1];
+ nm[1] = pts[4 * count + 2];
+ nm[2] = pts[4 * count + 3];
- return off ;
+ return off;
}
- void fillEdgeIntersections( UCHAR* leaf, int st[3], int len, float pts[12][3], float norms[12][3] )
+ void fillEdgeIntersections(LeafNode* leaf, int st[3], int len, float pts[12][3], float norms[12][3])
{
- int i ;
- // int stt[3] = { 0, 0, 0 } ;
+ int i;
+ // int stt[3] = {0, 0, 0};
// The three primal edges are easy
- int pmask[3] = { 0, 4, 8 } ;
- for ( i = 0 ; i < 3 ; i ++ )
+ int pmask[3] = {0, 4, 8};
+ for(i = 0; i < 3; i ++)
{
- if ( getEdgeParity( leaf, pmask[i] ) )
+ if(getEdgeParity(leaf, pmask[i]))
{
- // getEdgeIntersectionByIndex( leaf, i, stt, 1, pts[ pmask[i] ], norms[ pmask[i] ] ) ;
- getEdgeIntersectionByIndex( leaf, i, st, len, pts[ pmask[i] ], norms[ pmask[i] ] ) ;
+ // getEdgeIntersectionByIndex(leaf, i, stt, 1, pts[pmask[i]], norms[pmask[i]]);
+ getEdgeIntersectionByIndex(leaf, i, st, len, pts[pmask[i]], norms[pmask[i]]);
}
}
// 3 face adjacent cubes
- int fmask[3][2] = {{6,10},{2,9},{1,5}} ;
- int femask[3][2] = {{1,2},{0,2},{0,1}} ;
- for ( i = 0 ; i < 3 ; i ++ )
+ int fmask[3][2] = {{6,10},{2,9},{1,5}};
+ int femask[3][2] = {{1,2},{0,2},{0,1}};
+ for(i = 0; i < 3; i ++)
{
- int e1 = getEdgeParity( leaf, fmask[i][0] ) ;
- int e2 = getEdgeParity( leaf, fmask[i][1] ) ;
- if ( e1 || e2 )
+ int e1 = getEdgeParity(leaf, fmask[i][0]);
+ int e2 = getEdgeParity(leaf, fmask[i][1]);
+ if(e1 || e2)
{
- int nst[3] = {st[0], st[1], st[2]} ;
- nst[ i ] += len ;
- // int nstt[3] = {0, 0, 0} ;
- // nstt[ i ] += 1 ;
- UCHAR* node = locateLeaf( nst ) ;
+ int nst[3] = {st[0], st[1], st[2]};
+ nst[i] += len;
+ // int nstt[3] = {0, 0, 0};
+ // nstt[i] += 1;
+ LeafNode* node = locateLeaf(nst);
- if ( e1 )
+ if(e1)
{
- // getEdgeIntersectionByIndex( node, femask[i][0], nstt, 1, pts[ fmask[i][0] ], norms[ fmask[i][0] ] ) ;
- getEdgeIntersectionByIndex( node, femask[i][0], nst, len, pts[ fmask[i][0] ], norms[ fmask[i][0] ] ) ;
+ // getEdgeIntersectionByIndex(node, femask[i][0], nstt, 1, pts[fmask[i][0]], norms[fmask[i][0]]);
+ getEdgeIntersectionByIndex(node, femask[i][0], nst, len, pts[fmask[i][0]], norms[fmask[i][0]]);
}
- if ( e2 )
+ if(e2)
{
- // getEdgeIntersectionByIndex( node, femask[i][1], nstt, 1, pts[ fmask[i][1] ], norms[ fmask[i][1] ] ) ;
- getEdgeIntersectionByIndex( node, femask[i][1], nst, len, pts[ fmask[i][1] ], norms[ fmask[i][1] ] ) ;
+ // getEdgeIntersectionByIndex(node, femask[i][1], nstt, 1, pts[fmask[i][1]], norms[fmask[i][1]]);
+ getEdgeIntersectionByIndex(node, femask[i][1], nst, len, pts[fmask[i][1]], norms[fmask[i][1]]);
}
}
}
// 3 edge adjacent cubes
- int emask[3] = {3, 7, 11} ;
- int eemask[3] = {0, 1, 2} ;
- for ( i = 0 ; i < 3 ; i ++ )
+ int emask[3] = {3, 7, 11};
+ int eemask[3] = {0, 1, 2};
+ for(i = 0; i < 3; i ++)
{
- if ( getEdgeParity( leaf, emask[i] ) )
+ if(getEdgeParity(leaf, emask[i]))
{
- int nst[3] = {st[0] + len, st[1] + len, st[2] + len} ;
- nst[ i ] -= len ;
- // int nstt[3] = {1, 1, 1} ;
- // nstt[ i ] -= 1 ;
- UCHAR* node = locateLeaf( nst ) ;
+ int nst[3] = {st[0] + len, st[1] + len, st[2] + len};
+ nst[i] -= len;
+ // int nstt[3] = {1, 1, 1};
+ // nstt[i] -= 1;
+ LeafNode* node = locateLeaf(nst);
- // getEdgeIntersectionByIndex( node, eemask[i], nstt, 1, pts[ emask[i] ], norms[ emask[i] ] ) ;
- getEdgeIntersectionByIndex( node, eemask[i], nst, len, pts[ emask[i] ], norms[ emask[i] ] ) ;
+ // getEdgeIntersectionByIndex(node, eemask[i], nstt, 1, pts[emask[i]], norms[emask[i]]);
+ getEdgeIntersectionByIndex(node, eemask[i], nst, len, pts[emask[i]], norms[emask[i]]);
}
}
}
- void fillEdgeIntersections( UCHAR* leaf, int st[3], int len, float pts[12][3], float norms[12][3], int parity[12] )
+ void fillEdgeIntersections(LeafNode* leaf, int st[3], int len, float pts[12][3], float norms[12][3], int parity[12])
{
- int i ;
- for ( i = 0 ; i < 12 ; i ++ )
+ int i;
+ for(i = 0; i < 12; i ++)
{
- parity[ i ] = 0 ;
+ parity[i] = 0;
}
- // int stt[3] = { 0, 0, 0 } ;
+ // int stt[3] = {0, 0, 0};
// The three primal edges are easy
- int pmask[3] = { 0, 4, 8 } ;
- for ( i = 0 ; i < 3 ; i ++ )
+ int pmask[3] = {0, 4, 8};
+ for(i = 0; i < 3; i ++)
{
- if ( getStoredEdgesParity( leaf, i ) )
+ if(getStoredEdgesParity(leaf, i))
{
- // getEdgeIntersectionByIndex( leaf, i, stt, 1, pts[ pmask[i] ], norms[ pmask[i] ] ) ;
- getEdgeIntersectionByIndex( leaf, i, st, len, pts[ pmask[i] ], norms[ pmask[i] ] ) ;
- parity[ pmask[i] ] = 1 ;
+ // getEdgeIntersectionByIndex(leaf, i, stt, 1, pts[pmask[i]], norms[pmask[i]]);
+ getEdgeIntersectionByIndex(leaf, i, st, len, pts[pmask[i]], norms[pmask[i]]);
+ parity[pmask[i]] = 1;
}
}
// 3 face adjacent cubes
- int fmask[3][2] = {{6,10},{2,9},{1,5}} ;
- int femask[3][2] = {{1,2},{0,2},{0,1}} ;
- for ( i = 0 ; i < 3 ; i ++ )
+ int fmask[3][2] = {{6,10},{2,9},{1,5}};
+ int femask[3][2] = {{1,2},{0,2},{0,1}};
+ for(i = 0; i < 3; i ++)
{
{
- int nst[3] = {st[0], st[1], st[2]} ;
- nst[ i ] += len ;
- // int nstt[3] = {0, 0, 0} ;
- // nstt[ i ] += 1 ;
- UCHAR* node = locateLeafCheck( nst ) ;
- if ( node == NULL )
+ int nst[3] = {st[0], st[1], st[2]};
+ nst[i] += len;
+ // int nstt[3] = {0, 0, 0};
+ // nstt[i] += 1;
+ LeafNode* node = locateLeafCheck(nst);
+ if(node == NULL)
{
- continue ;
+ continue;
}
- int e1 = getStoredEdgesParity( node, femask[i][0] ) ;
- int e2 = getStoredEdgesParity( node, femask[i][1] ) ;
+ int e1 = getStoredEdgesParity(node, femask[i][0]);
+ int e2 = getStoredEdgesParity(node, femask[i][1]);
- if ( e1 )
+ if(e1)
{
- // getEdgeIntersectionByIndex( node, femask[i][0], nstt, 1, pts[ fmask[i][0] ], norms[ fmask[i][0] ] ) ;
- getEdgeIntersectionByIndex( node, femask[i][0], nst, len, pts[ fmask[i][0] ], norms[ fmask[i][0] ] ) ;
- parity[ fmask[i][0] ] = 1 ;
+ // getEdgeIntersectionByIndex(node, femask[i][0], nstt, 1, pts[fmask[i][0]], norms[fmask[i][0]]);
+ getEdgeIntersectionByIndex(node, femask[i][0], nst, len, pts[fmask[i][0]], norms[fmask[i][0]]);
+ parity[fmask[i][0]] = 1;
}
- if ( e2 )
+ if(e2)
{
- // getEdgeIntersectionByIndex( node, femask[i][1], nstt, 1, pts[ fmask[i][1] ], norms[ fmask[i][1] ] ) ;
- getEdgeIntersectionByIndex( node, femask[i][1], nst, len, pts[ fmask[i][1] ], norms[ fmask[i][1] ] ) ;
- parity[ fmask[i][1] ] = 1 ;
+ // getEdgeIntersectionByIndex(node, femask[i][1], nstt, 1, pts[fmask[i][1]], norms[fmask[i][1]]);
+ getEdgeIntersectionByIndex(node, femask[i][1], nst, len, pts[fmask[i][1]], norms[fmask[i][1]]);
+ parity[fmask[i][1]] = 1;
}
}
}
// 3 edge adjacent cubes
- int emask[3] = {3, 7, 11} ;
- int eemask[3] = {0, 1, 2} ;
- for ( i = 0 ; i < 3 ; i ++ )
+ int emask[3] = {3, 7, 11};
+ int eemask[3] = {0, 1, 2};
+ for(i = 0; i < 3; i ++)
{
-// if ( getEdgeParity( leaf, emask[i] ) )
+// if(getEdgeParity(leaf, emask[i]))
{
- int nst[3] = {st[0] + len, st[1] + len, st[2] + len} ;
- nst[ i ] -= len ;
- // int nstt[3] = {1, 1, 1} ;
- // nstt[ i ] -= 1 ;
- UCHAR* node = locateLeafCheck( nst ) ;
- if ( node == NULL )
+ int nst[3] = {st[0] + len, st[1] + len, st[2] + len};
+ nst[i] -= len;
+ // int nstt[3] = {1, 1, 1};
+ // nstt[i] -= 1;
+ LeafNode* node = locateLeafCheck(nst);
+ if(node == NULL)
{
- continue ;
+ continue;
}
- if ( getStoredEdgesParity( node, eemask[i] ) )
+ if(getStoredEdgesParity(node, eemask[i]))
{
- // getEdgeIntersectionByIndex( node, eemask[i], nstt, 1, pts[ emask[i] ], norms[ emask[i] ] ) ;
- getEdgeIntersectionByIndex( node, eemask[i], nst, len, pts[ emask[i] ], norms[ emask[i] ] ) ;
- parity[ emask[ i ] ] = 1 ;
+ // getEdgeIntersectionByIndex(node, eemask[i], nstt, 1, pts[emask[i]], norms[emask[i]]);
+ getEdgeIntersectionByIndex(node, eemask[i], nst, len, pts[emask[i]], norms[emask[i]]);
+ parity[emask[i]] = 1;
}
}
}
}
- void fillEdgeOffsetsNormals( UCHAR* leaf, int st[3], int len, float pts[12], float norms[12][3], int parity[12] )
+ void fillEdgeOffsetsNormals(LeafNode* leaf, int st[3], int len, float pts[12], float norms[12][3], int parity[12])
{
- int i ;
- for ( i = 0 ; i < 12 ; i ++ )
+ int i;
+ for(i = 0; i < 12; i ++)
{
- parity[ i ] = 0 ;
+ parity[i] = 0;
}
- // int stt[3] = { 0, 0, 0 } ;
+ // int stt[3] = {0, 0, 0};
// The three primal edges are easy
- int pmask[3] = { 0, 4, 8 } ;
- for ( i = 0 ; i < 3 ; i ++ )
+ int pmask[3] = {0, 4, 8};
+ for(i = 0; i < 3; i ++)
{
- if ( getStoredEdgesParity( leaf, i ) )
+ if(getStoredEdgesParity(leaf, i))
{
- pts[ pmask[i] ] = getEdgeOffsetNormalByIndex( leaf, i, norms[ pmask[i] ] ) ;
- parity[ pmask[i] ] = 1 ;
+ pts[pmask[i]] = getEdgeOffsetNormalByIndex(leaf, i, norms[pmask[i]]);
+ parity[pmask[i]] = 1;
}
}
// 3 face adjacent cubes
- int fmask[3][2] = {{6,10},{2,9},{1,5}} ;
- int femask[3][2] = {{1,2},{0,2},{0,1}} ;
- for ( i = 0 ; i < 3 ; i ++ )
+ int fmask[3][2] = {{6,10},{2,9},{1,5}};
+ int femask[3][2] = {{1,2},{0,2},{0,1}};
+ for(i = 0; i < 3; i ++)
{
{
- int nst[3] = {st[0], st[1], st[2]} ;
- nst[ i ] += len ;
- // int nstt[3] = {0, 0, 0} ;
- // nstt[ i ] += 1 ;
- UCHAR* node = locateLeafCheck( nst ) ;
- if ( node == NULL )
+ int nst[3] = {st[0], st[1], st[2]};
+ nst[i] += len;
+ // int nstt[3] = {0, 0, 0};
+ // nstt[i] += 1;
+ LeafNode* node = locateLeafCheck(nst);
+ if(node == NULL)
{
- continue ;
+ continue;
}
- int e1 = getStoredEdgesParity( node, femask[i][0] ) ;
- int e2 = getStoredEdgesParity( node, femask[i][1] ) ;
+ int e1 = getStoredEdgesParity(node, femask[i][0]);
+ int e2 = getStoredEdgesParity(node, femask[i][1]);
- if ( e1 )
+ if(e1)
{
- pts[ fmask[i][0] ] = getEdgeOffsetNormalByIndex( node, femask[i][0], norms[ fmask[i][0] ] ) ;
- parity[ fmask[i][0] ] = 1 ;
+ pts[fmask[i][0]] = getEdgeOffsetNormalByIndex(node, femask[i][0], norms[fmask[i][0]]);
+ parity[fmask[i][0]] = 1;
}
- if ( e2 )
+ if(e2)
{
- pts[ fmask[i][1] ] = getEdgeOffsetNormalByIndex( node, femask[i][1], norms[ fmask[i][1] ] ) ;
- parity[ fmask[i][1] ] = 1 ;
+ pts[fmask[i][1]] = getEdgeOffsetNormalByIndex(node, femask[i][1], norms[fmask[i][1]]);
+ parity[fmask[i][1]] = 1;
}
}
}
// 3 edge adjacent cubes
- int emask[3] = {3, 7, 11} ;
- int eemask[3] = {0, 1, 2} ;
- for ( i = 0 ; i < 3 ; i ++ )
+ int emask[3] = {3, 7, 11};
+ int eemask[3] = {0, 1, 2};
+ for(i = 0; i < 3; i ++)
{
-// if ( getEdgeParity( leaf, emask[i] ) )
+// if(getEdgeParity(leaf, emask[i]))
{
- int nst[3] = {st[0] + len, st[1] + len, st[2] + len} ;
- nst[ i ] -= len ;
- // int nstt[3] = {1, 1, 1} ;
- // nstt[ i ] -= 1 ;
- UCHAR* node = locateLeafCheck( nst ) ;
- if ( node == NULL )
+ int nst[3] = {st[0] + len, st[1] + len, st[2] + len};
+ nst[i] -= len;
+ // int nstt[3] = {1, 1, 1};
+ // nstt[i] -= 1;
+ LeafNode* node = locateLeafCheck(nst);
+ if(node == NULL)
{
- continue ;
+ continue;
}
- if ( getStoredEdgesParity( node, eemask[i] ) )
+ if(getStoredEdgesParity(node, eemask[i]))
{
- pts[ emask[i] ] = getEdgeOffsetNormalByIndex( node, eemask[i], norms[ emask[i] ] ) ;
- parity[ emask[ i ] ] = 1 ;
+ pts[emask[i]] = getEdgeOffsetNormalByIndex(node, eemask[i], norms[emask[i]]);
+ parity[emask[i]] = 1;
}
}
}
@@ -1253,344 +1112,320 @@ private:
/// Update method
- UCHAR* updateEdgeOffsetsNormals( UCHAR* leaf, int oldlen, int newlen, float offs[3], float a[3], float b[3], float c[3] )
+ LeafNode* updateEdgeOffsetsNormals(LeafNode* leaf, int oldlen, int newlen, float offs[3], float a[3], float b[3], float c[3])
{
// First, create a new leaf node
- UCHAR* nleaf = createLeaf( newlen ) ;
- for ( int i = 0 ; i < leaf_node_bytes ; i ++ )
- {
- nleaf[i] = leaf[i] ;
- }
+ LeafNode* nleaf = createLeaf(newlen);
+ *nleaf = *leaf;
// Next, fill in the offsets
- setEdgeOffsetsNormals( nleaf, offs, a, b, c, newlen ) ;
+ setEdgeOffsetsNormals(nleaf, offs, a, b, c, newlen);
// Finally, delete the old leaf
- removeLeaf( oldlen, leaf ) ;
+ removeLeaf(oldlen, leaf);
- return nleaf ;
+ return nleaf;
}
-#endif
/// Locate a leaf
/// WARNING: assuming this leaf already exists!
- UCHAR* locateLeaf( int st[3] )
+ LeafNode* locateLeaf(int st[3])
{
- UCHAR* node = root ;
- for ( int i = GRID_DIMENSION - 1 ; i > GRID_DIMENSION - maxDepth - 1 ; i -- )
+ Node* node = (Node*)root;
+ for(int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i --)
{
- int index = ( ( ( st[0] >> i ) & 1 ) << 2 ) |
- ( ( ( st[1] >> i ) & 1 ) << 1 ) |
- ( ( ( st[2] >> i ) & 1 ) ) ;
- node = getChild( node, getChildCount( node, index ) ) ;
+ int index =(((st[0] >> i) & 1) << 2) |
+ (((st[1] >> i) & 1) << 1) |
+ (((st[2] >> i) & 1));
+ node = getChild(&node->internal, getChildCount(&node->internal, index));
}
- return node ;
+ return &node->leaf;
}
- UCHAR* locateLeaf( UCHAR* node, int len, int st[3] )
+ LeafNode* locateLeaf(InternalNode* parent, int len, int st[3])
{
- int index ;
- for ( int i = len / 2 ; i >= mindimen ; i >>= 1 )
+ Node *node = (Node*)parent;
+ int index;
+ for(int i = len / 2; i >= mindimen; i >>= 1)
{
- index = ( ( ( st[0] & i ) ? 4 : 0 ) |
- ( ( st[1] & i ) ? 2 : 0 ) |
- ( ( st[2] & i ) ? 1 : 0 ) ) ;
- node = getChild( node, getChildCount( node, index ) ) ;
+ index =(((st[0] & i) ? 4 : 0) |
+ ((st[1] & i) ? 2 : 0) |
+ ((st[2] & i) ? 1 : 0));
+ node = getChild(&node->internal,
+ getChildCount(&node->internal, index));
}
- return node ;
+ return &node->leaf;
}
- UCHAR* locateLeafCheck( int st[3] )
+
+ LeafNode* locateLeafCheck(int st[3])
{
- UCHAR* node = root ;
- for ( int i = GRID_DIMENSION - 1 ; i > GRID_DIMENSION - maxDepth - 1 ; i -- )
+ Node* node = (Node*)root;
+ for(int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i --)
{
- int index = ( ( ( st[0] >> i ) & 1 ) << 2 ) |
- ( ( ( st[1] >> i ) & 1 ) << 1 ) |
- ( ( ( st[2] >> i ) & 1 ) ) ;
- if ( ! hasChild( node, index ) )
+ int index =(((st[0] >> i) & 1) << 2) |
+ (((st[1] >> i) & 1) << 1) |
+ (((st[2] >> i) & 1));
+ if(!hasChild(&node->internal, index))
{
- return NULL ;
+ return NULL;
}
- node = getChild( node, getChildCount( node, index ) ) ;
+ node = getChild(&node->internal, getChildCount(&node->internal, index));
}
- return node ;
+ return &node->leaf;
}
- UCHAR* locateParent( int len, int st[3], int& count )
+
+ InternalNode* locateParent(int len, int st[3], int& count)
{
- UCHAR* node = root ;
- UCHAR* pre = NULL ;
- int index = 0 ;
- for ( int i = dimen / 2 ; i >= len ; i >>= 1 )
+ InternalNode* node = (InternalNode*)root;
+ InternalNode* pre = NULL;
+ int index = 0;
+ for(int i = dimen / 2; i >= len; i >>= 1)
{
- index = ( ( ( st[0] & i ) ? 4 : 0 ) |
- ( ( st[1] & i ) ? 2 : 0 ) |
- ( ( st[2] & i ) ? 1 : 0 ) ) ;
- pre = node ;
- node = getChild( node, getChildCount( node, index ) ) ;
+ index =(((st[0] & i) ? 4 : 0) |
+ ((st[1] & i) ? 2 : 0) |
+ ((st[2] & i) ? 1 : 0));
+ pre = node;
+ node = &getChild(node, getChildCount(node, index))->internal;
}
- count = getChildCount( pre, index ) ;
- return pre ;
+ count = getChildCount(pre, index);
+ return pre;
}
- UCHAR* locateParent( UCHAR* papa, int len, int st[3], int& count )
+
+ InternalNode* locateParent(InternalNode* parent, int len, int st[3], int& count)
{
- UCHAR* node = papa ;
- UCHAR* pre = NULL ;
+ InternalNode* node = parent;
+ InternalNode* pre = NULL;
int index = 0;
- for ( int i = len / 2 ; i >= mindimen ; i >>= 1 )
+ for(int i = len / 2; i >= mindimen; i >>= 1)
{
- index = ( ( ( st[0] & i ) ? 4 : 0 ) |
- ( ( st[1] & i ) ? 2 : 0 ) |
- ( ( st[2] & i ) ? 1 : 0 ) ) ;
- pre = node ;
- node = getChild( node, getChildCount( node, index ) ) ;
+ index =(((st[0] & i) ? 4 : 0) |
+ ((st[1] & i) ? 2 : 0) |
+ ((st[2] & i) ? 1 : 0));
+ pre = node;
+ node = (InternalNode*)getChild(node, getChildCount(node, index));
}
- count = getChildCount( pre, index ) ;
- return pre ;
+ count = getChildCount(pre, index);
+ return pre;
}
+
/************ Operators for internal nodes ************/
- /// Print the node information
- void printNode( UCHAR* node )
- {
- printf("Address: %p ", node ) ;
- printf("Leaf Mask: ") ;
- for ( int i = 0 ; i < 8 ; i ++ )
- {
- printf( "%d ", isLeaf( node, i ) ) ;
- }
- printf("Child Mask: ") ;
- for ( int i = 0 ; i < 8 ; i ++ )
- {
- printf( "%d ", hasChild( node, i ) ) ;
- }
- printf("\n") ;
- }
-
- /// Get size of an internal node
- int getSize ( int length )
- {
- return INTERNAL_NODE_BYTES + length * 4 ;
- };
-
/// If child index exists
- int hasChild( UCHAR* node, int index )
+ int hasChild(InternalNode* node, int index)
{
- return ( node[0] >> index ) & 1 ;
- };
+ return (node->has_child >> index) & 1;
+ }
/// Test if child is leaf
- int isLeaf ( UCHAR* node, int index )
+ int isLeaf(InternalNode* node, int index)
{
- return ( node[1] >> index ) & 1 ;
- };
+ return (node->child_is_leaf >> index) & 1;
+ }
/// Get the pointer to child index
- UCHAR* getChild ( UCHAR* node, int count )
+ Node* getChild(InternalNode* node, int count)
{
- return (( UCHAR ** ) ( node + INTERNAL_NODE_BYTES )) [ count ] ;
+ return node->children[count];
};
/// Get total number of children
- int getNumChildren( UCHAR* node )
+ int getNumChildren(InternalNode* node)
{
- return numChildrenTable[ node[0] ] ;
- };
+ return numChildrenTable[node->has_child];
+ }
/// Get the count of children
- int getChildCount( UCHAR* node, int index )
+ int getChildCount(InternalNode* node, int index)
{
- return childrenCountTable[ node[0] ][ index ] ;
+ return childrenCountTable[node->has_child][index];
}
- int getChildIndex( UCHAR* node, int count )
+ int getChildIndex(InternalNode* node, int count)
{
- return childrenIndexTable[ node[0] ][ count ] ;
+ return childrenIndexTable[node->has_child][count];
}
- int* getChildCounts( UCHAR* node )
+ int* getChildCounts(InternalNode* node)
{
- return childrenCountTable[ node[0] ] ;
+ return childrenCountTable[node->has_child];
}
/// Get all children
- void fillChildren( UCHAR* node, UCHAR* chd[ 8 ], int leaf[ 8 ] )
+ void fillChildren(InternalNode* node, Node* children[8], int leaf[8])
{
- int count = 0 ;
- for ( int i = 0 ; i < 8 ; i ++ )
+ int count = 0;
+ for(int i = 0; i < 8; i ++)
{
- leaf[ i ] = isLeaf( node, i ) ;
- if ( hasChild( node, i ) )
+ leaf[i] = isLeaf(node, i);
+ if(hasChild(node, i))
{
- chd[ i ] = getChild( node, count ) ;
- count ++ ;
+ children[i] = getChild(node, count);
+ count ++;
}
else
{
- chd[ i ] = NULL ;
- leaf[ i ] = 0 ;
+ children[i] = NULL;
+ leaf[i] = 0;
}
}
}
/// Sets the child pointer
- void setChild ( UCHAR* node, int count, UCHAR* chd )
+ void setChild(InternalNode* node, int count, Node* chd)
{
- (( UCHAR ** ) ( node + INTERNAL_NODE_BYTES )) [ count ] = chd ;
+ node->children[count] = chd;
}
- void setInternalChild ( UCHAR* node, int index, int count, UCHAR* chd )
+ void setInternalChild(InternalNode* node, int index, int count, InternalNode* chd)
{
- setChild( node, count, chd ) ;
- node[0] |= ( 1 << index ) ;
- };
- void setLeafChild ( UCHAR* node, int index, int count, UCHAR* chd )
+ setChild(node, count, (Node*)chd);
+ node->has_child |= (1 << index);
+ }
+ void setLeafChild(InternalNode* node, int index, int count, LeafNode* chd)
{
- setChild( node, count, chd ) ;
- node[0] |= ( 1 << index ) ;
- node[1] |= ( 1 << index ) ;
- };
+ setChild(node, count, (Node*)chd);
+ node->has_child |=(1 << index);
+ node->child_is_leaf |= (1 << index);
+ }
/// Add a kid to an existing internal node
/// Fix me: can we do this without wasting memory ?
/// Fixed: using variable memory
- UCHAR* addChild( UCHAR* node, int index, UCHAR* chd, int aLeaf )
+ InternalNode* addChild(InternalNode* node, int index, Node* child, int aLeaf)
{
// Create new internal node
- int num = getNumChildren( node ) ;
- UCHAR* rnode = createInternal( num + 1 ) ;
+ int num = getNumChildren(node);
+ InternalNode* rnode = createInternal(num + 1);
// Establish children
- int i ;
- int count1 = 0, count2 = 0 ;
- for ( i = 0 ; i < 8 ; i ++ )
+ int i;
+ int count1 = 0, count2 = 0;
+ for(i = 0; i < 8; i ++)
{
- if ( i == index )
+ if(i == index)
{
- if ( aLeaf )
+ if(aLeaf)
{
- setLeafChild( rnode, i, count2, chd ) ;
+ setLeafChild(rnode, i, count2, &child->leaf);
}
else
{
- setInternalChild( rnode, i, count2, chd ) ;
+ setInternalChild(rnode, i, count2, &child->internal);
}
- count2 ++ ;
+ count2 ++;
}
- else if ( hasChild( node, i ) )
+ else if(hasChild(node, i))
{
- if ( isLeaf( node, i ) )
+ if(isLeaf(node, i))
{
- setLeafChild( rnode, i, count2, getChild( node, count1 ) ) ;
+ setLeafChild(rnode, i, count2, &getChild(node, count1)->leaf);
}
else
{
- setInternalChild( rnode, i, count2, getChild( node, count1 ) ) ;
+ setInternalChild(rnode, i, count2, &getChild(node, count1)->internal);
}
- count1 ++ ;
- count2 ++ ;
+ count1 ++;
+ count2 ++;
}
}
- removeInternal( num, node ) ;
- return rnode ;
+ removeInternal(num, node);
+ return rnode;
}
/// Allocate a node
- UCHAR* createInternal( int length )
+ InternalNode* createInternal(int length)
{
- UCHAR* inode = alloc[ length ]->allocate( ) ;
- inode[0] = inode[1] = 0 ;
- return inode ;
- };
- UCHAR* createLeaf( int length )
+ InternalNode* inode = (InternalNode*)alloc[length]->allocate();
+ inode->has_child = 0;
+ inode->child_is_leaf = 0;
+ return inode;
+ }
+
+ LeafNode* createLeaf(int length)
{
- if ( length > 3 )
- {
- printf("wierd");
- }
- UCHAR* lnode = leafalloc[ length ]->allocate( ) ;
- lnode[0] = lnode[1] = lnode[2] = 0 ;
+ assert(length <= 3);
- return lnode ;
- };
+ LeafNode* lnode = (LeafNode*)leafalloc[length]->allocate();
+ lnode->edge_parity = 0;
+ lnode->primary_edge_intersections = 0;
+ lnode->signs = 0;
- void removeInternal ( int num, UCHAR* node )
+ return lnode;
+ }
+
+ void removeInternal(int num, InternalNode* node)
{
- alloc[ num ]->deallocate( node ) ;
+ alloc[num]->deallocate(node);
}
- void removeLeaf ( int num, UCHAR* leaf )
+ void removeLeaf(int num, LeafNode* leaf)
{
- if ( num > 3 || num < 0 )
- {
- printf("wierd");
- }
- leafalloc[ num ]->deallocate( leaf ) ;
+ assert(num >= 0 && num <= 3);
+ leafalloc[num]->deallocate(leaf);
}
/// Add a leaf (by creating a new par node with the leaf added)
- UCHAR* addLeafChild ( UCHAR* par, int index, int count, UCHAR* leaf )
+ InternalNode* addLeafChild(InternalNode* par, int index, int count,
+ LeafNode* leaf)
{
- int num = getNumChildren( par ) + 1 ;
- UCHAR* npar = createInternal( num ) ;
- npar[0] = par[0] ;
- npar[1] = par[1] ;
+ int num = getNumChildren(par) + 1;
+ InternalNode* npar = createInternal(num);
+ *npar = *par;
- if ( num == 1 )
+ if(num == 1)
{
- setLeafChild( npar, index, 0, leaf ) ;
+ setLeafChild(npar, index, 0, leaf);
}
else
{
- int i ;
- for ( i = 0 ; i < count ; i ++ )
+ int i;
+ for(i = 0; i < count; i ++)
{
- setChild( npar, i, getChild( par, i ) ) ;
+ setChild(npar, i, getChild(par, i));
}
- setLeafChild( npar, index, count, leaf ) ;
- for ( i = count + 1 ; i < num ; i ++ )
+ setLeafChild(npar, index, count, leaf);
+ for(i = count + 1; i < num; i ++)
{
- setChild( npar, i, getChild( par, i - 1 ) ) ;
+ setChild(npar, i, getChild(par, i - 1));
}
}
- removeInternal( num-1, par ) ;
- return npar ;
- };
+ removeInternal(num-1, par);
+ return npar;
+ }
- UCHAR* addInternalChild ( UCHAR* par, int index, int count, UCHAR* node )
+ InternalNode* addInternalChild(InternalNode* par, int index, int count,
+ InternalNode* node)
{
- int num = getNumChildren( par ) + 1 ;
- UCHAR* npar = createInternal( num ) ;
- npar[0] = par[0] ;
- npar[1] = par[1] ;
+ int num = getNumChildren(par) + 1;
+ InternalNode* npar = createInternal(num);
+ *npar = *par;
- if ( num == 1 )
+ if(num == 1)
{
- setInternalChild( npar, index, 0, node ) ;
+ setInternalChild(npar, index, 0, node);
}
else
{
- int i ;
- for ( i = 0 ; i < count ; i ++ )
+ int i;
+ for(i = 0; i < count; i ++)
{
- setChild( npar, i, getChild( par, i ) ) ;
+ setChild(npar, i, getChild(par, i));
}
- setInternalChild( npar, index, count, node ) ;
- for ( i = count + 1 ; i < num ; i ++ )
+ setInternalChild(npar, index, count, node);
+ for(i = count + 1; i < num; i ++)
{
- setChild( npar, i, getChild( par, i - 1 ) ) ;
+ setChild(npar, i, getChild(par, i - 1));
}
}
- removeInternal( num-1, par ) ;
- return npar ;
- };
+ removeInternal(num-1, par);
+ return npar;
+ }
};
-
-
#endif
diff --git a/intern/smoke/intern/FLUID_3D.cpp b/intern/smoke/intern/FLUID_3D.cpp
index d688dbf1dfa..9f036cc6d2f 100644
--- a/intern/smoke/intern/FLUID_3D.cpp
+++ b/intern/smoke/intern/FLUID_3D.cpp
@@ -1106,7 +1106,7 @@ void FLUID_3D::addVorticity(int zBegin, int zEnd)
float dz = (out == index || in == index) ? 1.0f / _dx : gridSize;
int right = _obstacles[index + 1] ? index : index + 1;
int left = _obstacles[index - 1] ? index : index - 1;
- float dx = (right == index || right == index) ? 1.0f / _dx : gridSize;
+ float dx = (right == index || left == index) ? 1.0f / _dx : gridSize;
_xVorticity[vIndex] = (_zVelocity[up] - _zVelocity[down]) * dy + (-_yVelocity[out] + _yVelocity[in]) * dz;
_yVorticity[vIndex] = (_xVelocity[out] - _xVelocity[in]) * dz + (-_zVelocity[right] + _zVelocity[left]) * dx;
@@ -1152,7 +1152,7 @@ void FLUID_3D::addVorticity(int zBegin, int zEnd)
float dz = (out == vIndex || in == vIndex) ? 1.0f / _dx : gridSize;
int right = _obstacles[index + 1] ? vIndex : vIndex + 1;
int left = _obstacles[index - 1] ? vIndex : vIndex - 1;
- float dx = (right == vIndex || right == vIndex) ? 1.0f / _dx : gridSize;
+ float dx = (right == vIndex || left == vIndex) ? 1.0f / _dx : gridSize;
N[0] = (_vorticity[right] - _vorticity[left]) * dx;
N[1] = (_vorticity[up] - _vorticity[down]) * dy;
N[2] = (_vorticity[out] - _vorticity[in]) * dz;
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index 088e239e9a5..c5dc07e493a 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -373,7 +373,8 @@ class Mesh(bpy_types.ID):
"""
self.vertices.add(len(vertices))
self.edges.add(len(edges))
- self.faces.add(len(faces))
+ self.loops.add(sum((len(f) for f in faces)))
+ self.polygons.add(len(faces))
vertices_flat = [f for v in vertices for f in v]
self.vertices.foreach_set("co", vertices_flat)
@@ -383,19 +384,15 @@ class Mesh(bpy_types.ID):
self.edges.foreach_set("vertices", edges_flat)
del edges_flat
- def treat_face(f):
- if len(f) == 3:
- if f[2] == 0:
- return f[2], f[0], f[1], 0
- else:
- return f[0], f[1], f[2], 0
- elif f[2] == 0 or f[3] == 0:
- return f[2], f[3], f[0], f[1]
- return f
-
- faces_flat = [v for f in faces for v in treat_face(f)]
- self.faces.foreach_set("vertices_raw", faces_flat)
- del faces_flat
+ # this is different in bmesh
+ loop_index = 0
+ for i, p in enumerate(self.polygons):
+ f = faces[i]
+ loop_len = len(f)
+ p.loop_start = loop_index
+ p.loop_total = loop_len
+ p.vertices = f
+ loop_index += loop_len
@property
def edge_keys(self):
@@ -445,6 +442,20 @@ class MeshFace(StructRNA):
ord_ind(verts[3], verts[0]),
)
+class MeshPolygon(StructRNA):
+ __slots__ = ()
+
+ @property
+ def edge_keys(self):
+ verts = self.vertices[:]
+ vlen = len(self.vertices)
+ return [ord_ind(verts[i], verts[(i+1) % vlen]) for i in range(vlen)]
+
+ @property
+ def loops(self):
+ start = self.loop_start
+ end = start + self.loop_total
+ return range(start, end)
class Text(bpy_types.ID):
__slots__ = ()
diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py
index 3e206017238..1904ee5598e 100644
--- a/release/scripts/startup/bl_operators/mesh.py
+++ b/release/scripts/startup/bl_operators/mesh.py
@@ -24,50 +24,6 @@ from bpy.types import Operator
from bpy.props import EnumProperty
-class MeshSelectInteriorFaces(Operator):
- '''Select faces where all edges have more than 2 face users'''
-
- bl_idname = "mesh.faces_select_interior"
- bl_label = "Select Interior Faces"
- bl_options = {'REGISTER', 'UNDO'}
-
- @classmethod
- def poll(cls, context):
- ob = context.active_object
- return (ob and ob.type == 'MESH')
-
- def execute(self, context):
- from bpy_extras import mesh_utils
- ob = context.active_object
- context.tool_settings.mesh_select_mode = False, False, True
- is_editmode = (ob.mode == 'EDIT')
- if is_editmode:
- bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
-
- mesh = ob.data
-
- face_list = mesh.faces[:]
- face_edge_keys = [face.edge_keys for face in face_list]
-
- edge_face_count = mesh_utils.edge_face_count_dict(mesh)
-
- def test_interior(index):
- for key in face_edge_keys[index]:
- if edge_face_count[key] < 3:
- return False
- return True
-
- for index, face in enumerate(face_list):
- if(test_interior(index)):
- face.select = True
- else:
- face.select = False
-
- if is_editmode:
- bpy.ops.object.mode_set(mode='EDIT', toggle=False)
- return {'FINISHED'}
-
-
class MeshMirrorUV(Operator):
'''Copy mirror UV coordinates on the X axis based on a mirrored mesh'''
bl_idname = "mesh.faces_mirror_uv"
diff --git a/release/scripts/startup/bl_operators/uvcalc_follow_active.py b/release/scripts/startup/bl_operators/uvcalc_follow_active.py
index 748255671dd..0df86a3869e 100644
--- a/release/scripts/startup/bl_operators/uvcalc_follow_active.py
+++ b/release/scripts/startup/bl_operators/uvcalc_follow_active.py
@@ -30,6 +30,7 @@ def extend(obj, operator, EXTEND_MODE):
me = obj.data
me_verts = me.vertices
+
# script will fail without UVs
if not me.uv_textures:
me.uv_textures.new()
@@ -52,17 +53,15 @@ def extend(obj, operator, EXTEND_MODE):
'''
def face_edge_vs(vi):
- # assume a quad
- return [(vi[0], vi[1]), (vi[1], vi[2]), (vi[2], vi[3]), (vi[3], vi[0])]
+ vlen = len(vi)
+ return [(vi[i], vi[(i+1) % vlen]) for i in range(vlen)]
vidx_source = face_source.vertices
vidx_target = face_target.vertices
- faceUVsource = me.uv_textures.active.data[face_source.index]
- uvs_source = [faceUVsource.uv1, faceUVsource.uv2, faceUVsource.uv3, faceUVsource.uv4]
-
- faceUVtarget = me.uv_textures.active.data[face_target.index]
- uvs_target = [faceUVtarget.uv1, faceUVtarget.uv2, faceUVtarget.uv3, faceUVtarget.uv4]
+ uv_layer = me.uv_loop_layers.active.data
+ uvs_source = [uv_layer[i].uv for i in face_source.loops]
+ uvs_target = [uv_layer[i].uv for i in face_target.loops]
# vertex index is the key, uv is the value
@@ -135,15 +134,12 @@ def extend(obj, operator, EXTEND_MODE):
uvs_vhash_target[edgepair_outer_target[iB]][:] = uvs_vhash_source[edgepair_inner_source[0]] + (uvs_vhash_source[edgepair_inner_source[0]] - uvs_vhash_source[edgepair_outer_source[1]])
uvs_vhash_target[edgepair_outer_target[iA]][:] = uvs_vhash_source[edgepair_inner_source[1]] + (uvs_vhash_source[edgepair_inner_source[1]] - uvs_vhash_source[edgepair_outer_source[0]])
- if not me.uv_textures:
- me.uv_textures.new()
-
- face_act = me.faces.active
+ face_act = me.polygons.active
if face_act == -1:
operator.report({'ERROR'}, "No active face")
return
- face_sel = [f for f in me.faces if len(f.vertices) == 4 and f.select]
+ face_sel = [f for f in me.polygons if len(f.vertices) == 4 and f.select]
face_act_local_index = -1
for i, f in enumerate(face_sel):
diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
index 3159466c5ca..c7e35943e35 100644
--- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py
+++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
@@ -88,8 +88,8 @@ class prettyface(object):
self.children = []
else: # blender face
- # self.uv = data.uv
- self.uv = data.id_data.uv_textures.active.data[data.index].uv # XXX25
+ uv_layer = data.id_data.uv_loop_layers.active.data
+ self.uv = [uv_layer[i].uv for i in data.loops]
# cos = [v.co for v in data]
cos = [data.id_data.vertices[v].co for v in data.vertices] # XXX25
@@ -158,7 +158,8 @@ class prettyface(object):
I = [i for a, i in angles_co]
#~ fuv = f.uv
- fuv = f.id_data.uv_textures.active.data[f.index].uv # XXX25
+ uv_layer = f.id_data.uv_loop_layers.active.data
+ fuv = [uv_layer[i].uv for i in f.loops] # XXX25
if self.rot:
fuv[I[2]] = p1
@@ -219,15 +220,10 @@ def lightmap_uvpack(meshes,
face_groups = []
for me in meshes:
- # Add face UV if it does not exist.
- # All new faces are selected.
- if not me.uv_textures:
- me.uv_textures.new()
-
if PREF_SEL_ONLY:
- faces = [f for f in me.faces if f.select]
+ faces = [f for f in me.polygons if f.select]
else:
- faces = me.faces[:]
+ faces = me.polygons[:]
if PREF_PACK_IN_ONE:
face_groups[0].extend(faces)
@@ -237,6 +233,11 @@ def lightmap_uvpack(meshes,
if PREF_NEW_UVLAYER:
me.uv_textures.new()
+ # Add face UV if it does not exist.
+ # All new faces are selected.
+ if not me.uv_textures:
+ me.uv_textures.new()
+
for face_sel in face_groups:
print("\nStarting unwrap")
@@ -504,7 +505,7 @@ def lightmap_uvpack(meshes,
for f in face_sel:
# f.image = image
- f.id_data.uv_textures.active.data[f.index].image = image # XXX25
+ f.id_data.uv_loop_layers.active.data[f.index].image = image # XXX25
for me in meshes:
me.update()
@@ -528,7 +529,7 @@ def unwrap(operator, context, **kwargs):
if obj and obj.type == 'MESH':
meshes = [obj.data]
else:
- meshes = list({me for obj in context.selected_objects if obj.type == 'MESH' for me in (obj.data,) if me.faces and me.library is None})
+ meshes = list({me for obj in context.selected_objects if obj.type == 'MESH' for me in (obj.data,) if me.polygons and me.library is None})
if not meshes:
operator.report({'ERROR'}, "No mesh object")
diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py
index 622d19a0cfa..1464b83ab95 100644
--- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py
+++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py
@@ -757,12 +757,9 @@ def VectoQuat(vec):
class thickface(object):
__slost__= "v", "uv", "no", "area", "edge_keys"
- def __init__(self, face, uvface, mesh_verts):
+ def __init__(self, face, uv_layer, mesh_verts):
self.v = [mesh_verts[i] for i in face.vertices]
- if len(self.v)==4:
- self.uv = uvface.uv1, uvface.uv2, uvface.uv3, uvface.uv4
- else:
- self.uv = uvface.uv1, uvface.uv2, uvface.uv3
+ self.uv = [uv_layer[i].uv for i in face.loops]
self.no = face.normal
self.area = face.area
@@ -892,13 +889,13 @@ def main(context,
if not me.uv_textures: # Mesh has no UV Coords, don't bother.
me.uv_textures.new()
- uv_layer = me.uv_textures.active.data
+ uv_layer = me.uv_loop_layers.active.data
me_verts = list(me.vertices)
if USER_ONLY_SELECTED_FACES:
- meshFaces = [thickface(f, uv_layer[i], me_verts) for i, f in enumerate(me.faces) if f.select]
+ meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons) if f.select]
else:
- meshFaces = [thickface(f, uv_layer[i], me_verts) for i, f in enumerate(me.faces)]
+ meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons)]
if not meshFaces:
continue
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index 354b70c19c2..f4e5c27b90a 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -46,7 +46,11 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
# the mt.type enum is (ab)used for a lookup on function names
# ...to avoid lengthy if statements
# so each type must have a function here.
-
+
+ def NGONINTERP(self, layout, ob, md):
+ split = layout.split()
+ split.prop(md, "resolution")
+
def ARMATURE(self, layout, ob, md):
split = layout.split()
@@ -122,6 +126,12 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
split.prop(md, "width")
split.prop(md, "use_only_vertices")
+ # -- new modifier only, this may be reverted in favor of 2.62 mod.
+ split = layout.split()
+ split.prop(md, "use_even_offset")
+ split.prop(md, "use_distance_offset")
+ # -- end
+
layout.label(text="Limit Method:")
layout.row().prop(md, "limit_method", expand=True)
if md.limit_method == 'ANGLE':
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 0c9c4ff8fd2..1144cbf188d 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -522,16 +522,15 @@ class VIEW3D_MT_select_edit_mesh(Menu):
layout.operator("mesh.select_nth", text="Every N Number of Verts")
layout.operator("mesh.edges_select_sharp", text="Sharp Edges")
layout.operator("mesh.faces_select_linked_flat", text="Linked Flat Faces")
- layout.operator("mesh.faces_select_interior", text="Interior Faces")
+ layout.operator("mesh.select_interior_faces", text="Interior Faces")
layout.operator("mesh.select_axis", text="Side of Active")
layout.separator()
- layout.operator("mesh.select_by_number_vertices", text="Triangles").type = 'TRIANGLES'
- layout.operator("mesh.select_by_number_vertices", text="Quads").type = 'QUADS'
+ layout.operator("mesh.select_by_number_vertices", text = "By Number of Verts")
if context.scene.tool_settings.mesh_select_mode[2] == False:
layout.operator("mesh.select_non_manifold", text="Non Manifold")
- layout.operator("mesh.select_by_number_vertices", text="Loose Verts/Edges").type = 'OTHER'
+ layout.operator("mesh.select_loose_verts", text = "Loose Verts/Edges")
layout.operator("mesh.select_similar", text="Similar")
layout.separator()
@@ -1502,6 +1501,7 @@ class VIEW3D_MT_edit_mesh(Menu):
layout.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Region")
layout.operator("view3d.edit_mesh_extrude_individual_move", text="Extrude Individual")
+ layout.operator("mesh.dissolve_limited")
layout.operator("mesh.duplicate_move")
layout.operator("mesh.delete", text="Delete...")
@@ -1532,15 +1532,18 @@ class VIEW3D_MT_edit_mesh_specials(Menu):
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("mesh.subdivide", text="Subdivide").smoothness = 0.0
+ """
layout.operator("mesh.subdivide", text="Subdivide Smooth").smoothness = 1.0
+ """
layout.operator("mesh.merge", text="Merge...")
layout.operator("mesh.remove_doubles")
+ layout.operator("mesh.dissolve_limited")
layout.operator("mesh.hide", text="Hide")
layout.operator("mesh.reveal", text="Reveal")
layout.operator("mesh.select_all").action = 'INVERT'
layout.operator("mesh.flip_normals")
layout.operator("mesh.vertices_smooth", text="Smooth")
- # layout.operator("mesh.bevel", text="Bevel")
+ layout.operator("mesh.bevel", text="Bevel")
layout.operator("mesh.faces_shade_smooth")
layout.operator("mesh.faces_shade_flat")
layout.operator("mesh.blend_from_shape")
@@ -1614,6 +1617,7 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout.operator("mesh.rip_move")
layout.operator("mesh.split")
layout.operator("mesh.separate")
+ layout.operator("mesh.vert_connect")
layout.separator()
@@ -1657,7 +1661,7 @@ class VIEW3D_MT_edit_mesh_edges(Menu):
layout.separator()
- layout.operator("mesh.mark_freestyle_edge")
+ layout.operator("mesh.mark_freestyle_edge").clear = False
layout.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
layout.separator()
@@ -1667,6 +1671,10 @@ class VIEW3D_MT_edit_mesh_edges(Menu):
layout.separator()
+ layout.operator("mesh.bridge_edge_loops", text="Bridge Two Edge Loops")
+
+ layout.separator()
+
layout.operator("TRANSFORM_OT_edge_slide")
layout.operator("TRANSFORM_OT_edge_crease")
layout.operator("mesh.loop_multi_select", text="Edge Loop").ring = False
@@ -1699,12 +1707,7 @@ class VIEW3D_MT_edit_mesh_faces(Menu):
layout.separator()
- layout.operator("mesh.fgon_make")
- layout.operator("mesh.fgon_clear")
-
- layout.separator()
-
- layout.operator("mesh.mark_freestyle_face")
+ layout.operator("mesh.mark_freestyle_face").clear = False
layout.operator("mesh.mark_freestyle_face", text="Clear Freestyle Face").clear = True
layout.separator()
@@ -1728,9 +1731,9 @@ class VIEW3D_MT_edit_mesh_faces(Menu):
layout.separator()
layout.operator_menu_enum("mesh.uvs_rotate", "direction")
- layout.operator_menu_enum("mesh.uvs_mirror", "axis")
+ layout.operator("mesh.uvs_reverse")
layout.operator_menu_enum("mesh.colors_rotate", "direction")
- layout.operator_menu_enum("mesh.colors_mirror", "axis")
+ layout.operator("mesh.colors_reverse")
class VIEW3D_MT_edit_mesh_normals(Menu):
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 08ed019e26e..09e915abe4c 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -93,6 +93,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 1fe815849db..95c9d0925b6 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 40e2a4082f6..05b9519d2fe 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -28,21 +28,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"
@@ -53,20 +81,26 @@ 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.
+*/
typedef struct DMGridData {
float co[3];
@@ -80,15 +114,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, numTessFaceData, 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;
@@ -96,23 +130,29 @@ struct DerivedMesh {
DerivedMeshType type;
float auto_bump_scale;
+ /* calculate vert and face normals */
+ void (*calcNormals)(DerivedMesh *dm);
+
+ /* recalculates mesh tesselation */
+ void (*recalcTesselation)(DerivedMesh *dm);
+
/* Misc. Queries */
/* 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 (*getNumLoops)(DerivedMesh *dm);
+ int (*getNumPolys)(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,
@@ -121,21 +161,27 @@ struct DerivedMesh {
*/
struct MVert *(*getVertArray)(DerivedMesh *dm);
struct MEdge *(*getEdgeArray)(DerivedMesh *dm);
- struct MFace *(*getFaceArray)(DerivedMesh *dm);
+ struct MFace *(*getTessFaceArray)(DerivedMesh *dm);
+ struct MLoop *(*getLoopArray)(DerivedMesh *dm);
+ struct MPoly *(*getPolyArray)(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);
+ void (*copyLoopArray)(DerivedMesh *dm, struct MLoop *loop_r);
+ void (*copyPolyArray)(DerivedMesh *dm, struct MPoly *poly_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);
+ struct MLoop *(*dupLoopArray)(DerivedMesh *dm);
+ struct MPoly *(*dupPolyArray)(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
@@ -143,7 +189,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
@@ -151,8 +197,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 *(*getPolyDataLayout)(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);
@@ -210,6 +269,10 @@ struct DerivedMesh {
/* Get a map of vertices to faces
*/
+ struct ListBase *(*getPolyMap)(struct Object *ob, DerivedMesh *dm);
+
+ /* Get a map of vertices to faces
+ */
struct ListBase *(*getFaceMap)(struct Object *ob, DerivedMesh *dm);
/* Get the BVH used for paint modes
@@ -255,8 +318,8 @@ struct DerivedMesh {
* o Drawing options too complicated to enumerate, look at code.
*/
void (*drawFacesTex)(DerivedMesh *dm,
- int (*setDrawOptions)(struct MTFace *tface,
- int has_mcol, int matnr),
+ int (*setDrawOptions)(struct MTFace *tface,
+ int has_vcol, int matnr),
int (*compareDrawOptions)(void *userData,
int cur_index,
int next_index),
@@ -357,15 +420,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
@@ -374,7 +438,15 @@ int DM_release(DerivedMesh *dm);
/* utility function to convert a DerivedMesh to a Mesh
*/
-void DM_to_mesh(DerivedMesh *dm, struct Mesh *me);
+void DM_to_mesh(DerivedMesh *dm, struct Mesh *me, struct Object *ob);
+
+struct BMEditMesh *DM_to_editbmesh(struct Object *ob, struct DerivedMesh *dm,
+ struct BMEditMesh *existing, int do_tesselate);
+
+/* conversion to bmesh only */
+void DM_to_bmesh_ex(struct DerivedMesh *dm, struct BMesh *bm);
+struct BMesh *DM_to_bmesh(struct Object *ob, struct DerivedMesh *dm);
+
/* utility function to convert a DerivedMesh to a shape key block
*/
@@ -392,11 +464,15 @@ void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask);
* freed, see BKE_customdata.h for the different options
*/
void DM_add_vert_layer(struct DerivedMesh *dm, int type, int alloctype,
- void *layer);
+ void *layer);
void DM_add_edge_layer(struct DerivedMesh *dm, int type, int alloctype,
- void *layer);
-void DM_add_face_layer(struct DerivedMesh *dm, int type, int alloctype,
- void *layer);
+ void *layer);
+void DM_add_tessface_layer(struct DerivedMesh *dm, int type, int alloctype,
+ void *layer);
+void DM_add_loop_layer(DerivedMesh *dm, int type, int alloctype,
+ void *layer);
+void DM_add_poly_layer(struct DerivedMesh *dm, int type, int alloctype,
+ void *layer);
/* custom data access functions
* return pointer to data from first layer which matches type
@@ -405,7 +481,7 @@ void DM_add_face_layer(struct DerivedMesh *dm, int type, int alloctype,
*/
void *DM_get_vert_data(struct DerivedMesh *dm, int index, int type);
void *DM_get_edge_data(struct DerivedMesh *dm, int index, int type);
-void *DM_get_face_data(struct DerivedMesh *dm, int index, int type);
+void *DM_get_tessface_data(struct DerivedMesh *dm, int index, int type);
/* custom data layer access functions
* return pointer to first data layer which matches type (a flat array)
@@ -414,7 +490,9 @@ 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_face_data_layer(struct DerivedMesh *dm, int type);
+void *DM_get_tessface_data_layer(struct DerivedMesh *dm, int type);
+void *DM_get_poly_data_layer(struct DerivedMesh *dm, int type);
+void *DM_get_loop_data_layer(struct DerivedMesh *dm, int type);
/* custom data setting functions
* copy supplied data into first layer of type using layer's copy function
@@ -422,7 +500,7 @@ void *DM_get_face_data_layer(struct DerivedMesh *dm, int type);
*/
void DM_set_vert_data(struct DerivedMesh *dm, int index, int type, void *data);
void DM_set_edge_data(struct DerivedMesh *dm, int index, int type, void *data);
-void DM_set_face_data(struct DerivedMesh *dm, int index, int type, void *data);
+void DM_set_tessface_data(struct DerivedMesh *dm, int index, int type, void *data);
/* custom data copy functions
* copy count elements from source_index in source to dest_index in dest
@@ -432,7 +510,11 @@ 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_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+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_poly_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int source_index, int dest_index, int count);
/* custom data free functions
@@ -441,7 +523,14 @@ 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_face_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_poly_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);
+
+void DM_ensure_tessface(DerivedMesh *dm);
/* 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
@@ -472,12 +561,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_poly_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);
@@ -493,11 +590,15 @@ DerivedMesh *mesh_get_derived_final(struct Scene *scene, struct Object *ob,
DerivedMesh *mesh_get_derived_deform(struct Scene *scene, struct Object *ob,
CustomDataMask dataMask);
-DerivedMesh *mesh_create_derived_for_modifier(struct Scene *scene, struct Object *ob, struct ModifierData *md);
+DerivedMesh *mesh_create_derived_for_modifier(struct Scene *scene, struct Object *ob,
+ struct ModifierData *md, int build_shapekey_layers);
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 */
@@ -516,20 +617,21 @@ 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, int build_shapekey_layers);
/* 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,
@@ -574,16 +676,6 @@ typedef struct DMVertexAttribs {
int tottface, totmcol, tottang, totorco;
} DMVertexAttribs;
-/* should be local, bmesh replaces this */
-typedef struct {
- DerivedMesh dm;
-
- struct EditMesh *em;
- float (*vertexCos)[3];
- float (*vertexNos)[3];
- float (*faceNos)[3];
-} EditMeshDerivedMesh;
-
void DM_vertex_attributes_from_gpu(DerivedMesh *dm,
struct GPUVertexAttribs *gattribs, DMVertexAttribs *attribs);
@@ -593,6 +685,8 @@ void DM_calc_auto_bump_scale(DerivedMesh *dm);
/* Set object's bounding box based on DerivedMesh min/max data */
void DM_set_object_boundbox(struct Object *ob, DerivedMesh *dm);
+void DM_init_origspace(DerivedMesh *dm);
+
/* debug only */
#ifndef NDEBUG
char *DM_debug_info(DerivedMesh *dm);
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index b09122d022b..e94ad6ecfac 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -107,6 +107,7 @@ void armature_mat_world_to_pose(struct Object *ob, float inmat[][4], float outma
void armature_loc_world_to_pose(struct Object *ob, float *inloc, float *outloc);
void armature_mat_pose_to_bone(struct bPoseChannel *pchan, float inmat[][4], float outmat[][4]);
void armature_loc_pose_to_bone(struct bPoseChannel *pchan, float *inloc, float *outloc);
+void armature_mat_bone_to_pose(struct bPoseChannel *pchan, float inmat[][4], float outmat[][4]);
void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float arm_mat[][4]);
void armature_mat_pose_to_bone_ex(struct Object *ob, struct bPoseChannel *pchan, float inmat[][4], float outmat[][4]);
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 1c661b3804f..237bfc1b588 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -90,6 +90,7 @@ extern void BKE_reset_undo(void);
extern char *BKE_undo_menu_string(void);
extern void BKE_undo_number(struct bContext *C, int nr);
extern const char *BKE_undo_get_name(int nr, int *active);
+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 51fb0da61fa..36760d387a1 100644
--- a/source/blender/blenkernel/BKE_bmesh.h
+++ b/source/blender/blenkernel/BKE_bmesh.h
@@ -44,6 +44,7 @@
#include "BLI_editVert.h"
#include "BKE_DerivedMesh.h"
//XXX #include "transform.h"
+#include "bmesh.h"
/*forward declerations*/
struct BME_Vert;
@@ -51,6 +52,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
@@ -208,9 +210,13 @@ int BME_loop_reverse(struct BME_Mesh *bm, struct BME_Poly *f);
#define BME_BEVEL_RUNNING (1<<9)
#define BME_BEVEL_RES (1<<10)
+#define BME_BEVEL_EVEN (1<<11) /* this is a new setting not related to old (trunk bmesh bevel code) but adding
+ * here because they are mixed - campbell */
+#define BME_BEVEL_DIST (1<<12) /* same as above */
+
typedef struct BME_TransData {
- BME_Mesh *bm; /* the bmesh the vert belongs to */
- BME_Vert *v; /* pointer to the vert this tdata applies to */
+ BMesh *bm; /* the bmesh the vert belongs to */
+ BMVert *v; /* pointer to the vert this tdata applies to */
float co[3]; /* the original coordinate */
float org[3]; /* the origin */
float vec[3]; /* a directional vector; always, always normalize! */
@@ -231,7 +237,7 @@ typedef struct BME_TransData_Head {
} BME_TransData_Head;
typedef struct BME_Glob { /* stored in Global G for Transform() purposes */
- BME_Mesh *bm;
+ BMesh *bm;
BME_TransData_Head *td;
struct TransInfo *Trans; /* a pointer to the global Trans struct */
int imval[2]; /* for restoring original mouse co when initTransform() is called multiple times */
@@ -239,10 +245,10 @@ typedef struct BME_Glob { /* stored in Global G for Transform() purposes */
int res;
} BME_Glob;
-struct BME_TransData *BME_get_transdata(struct BME_TransData_Head *td, struct BME_Vert *v);
+struct BME_TransData *BME_get_transdata(struct BME_TransData_Head *td, struct BMVert *v);
void BME_free_transdata(struct BME_TransData_Head *td);
float *BME_bevel_calc_polynormal(struct BME_Poly *f, struct BME_TransData_Head *td);
-struct BME_Mesh *BME_bevel(struct BME_Mesh *bm, float value, int res, int options, int defgrp_index, float angle, BME_TransData_Head **rtd);
+struct BMesh *BME_bevel(struct BMEditMesh *em, float value, int res, int options, int defgrp_index, float angle, BME_TransData_Head **rtd);
/*CONVERSION FUNCTIONS*/
struct BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em);
diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h
index 9b274a8a411..053749148a0 100644
--- a/source/blender/blenkernel/BKE_cdderivedmesh.h
+++ b/source/blender/blenkernel/BKE_cdderivedmesh.h
@@ -38,12 +38,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
@@ -51,8 +56,11 @@ struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces);
data to not overwrite the original */
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, int use_mdisps, int use_tessface);
+
+/* merge verts */
+DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap);
/* creates a CDDerivedMesh from the given curve object */
struct DerivedMesh *CDDM_from_curve(struct Object *ob);
@@ -65,13 +73,20 @@ DerivedMesh *CDDM_from_curve_customDB(struct Object *ob, struct ListBase *dispba
* custom element data.
*/
struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm);
+struct DerivedMesh *CDDM_copy_from_tessface(struct DerivedMesh *dm);
/* 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
@@ -82,19 +97,31 @@ void CDDM_apply_vert_normals(struct DerivedMesh *cddm, short (*vertNormals)[3]);
/* recalculates vertex and face normals for a CDDerivedMesh
*/
+void CDDM_calc_normals_mapping(struct DerivedMesh *dm);
void CDDM_calc_normals(struct DerivedMesh *dm);
+void CDDM_calc_normals_tessface(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_tessface(struct DerivedMesh *dm);
+
+/* same as CDDM_calc_edges_tessface only makes edges from ngon faces instead of tesselation
+ faces*/
void CDDM_calc_edges(struct DerivedMesh *dm);
+/* reconstitute face triangulation */
+void CDDM_recalc_tesselation(struct DerivedMesh *dm);
+void CDDM_recalc_tesselation_ex(struct DerivedMesh *dm, const int do_face_nor_cpy);
+
/* lowers the number of vertices/edges/faces in a CDDerivedMesh
* the layer data stays the same size
*/
void CDDM_lower_num_verts(struct DerivedMesh *dm, int numVerts);
void CDDM_lower_num_edges(struct DerivedMesh *dm, int numEdges);
-void CDDM_lower_num_faces(struct DerivedMesh *dm, int numFaces);
+void CDDM_lower_num_polys(struct DerivedMesh *dm, int numPolys);
+void CDDM_lower_num_tessfaces(DerivedMesh *dm, int numTessFaces);
/* vertex/edge/face access functions
* should always succeed if index is within bounds
@@ -102,7 +129,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_poly(struct DerivedMesh *dm, int index);
/* vertex/edge/face array access functions - return the array holding the
* desired data
@@ -111,6 +140,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_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 764088da47b..6159240f92d 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -40,11 +40,15 @@ extern "C" {
#include "../blenloader/BLO_sys_types.h" /* XXX, should have a more generic include for this */
+struct BMesh;
struct ID;
struct CustomData;
struct CustomDataLayer;
typedef uint64_t 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;
@@ -69,6 +73,25 @@ extern const CustomDataMask CD_MASK_FACECORNERS;
#define CD_TYPE_AS_MASK(_type) (CustomDataMask)((CustomDataMask)1 << (CustomDataMask)(_type))
+/* 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. */
@@ -83,6 +106,12 @@ void CustomData_update_typemap(struct CustomData *data);
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)
*/
@@ -308,8 +337,9 @@ 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);
+ 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_update_active_layers(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata);
void CustomData_bmesh_init_pool(struct CustomData *data, int allocsize);
/* External file storage */
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index c1f75baf8ff..c241160102e 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -48,8 +48,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 ba6bf330b1e..39e5a32404e 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -36,7 +36,8 @@
struct BoundBox;
struct DispList;
struct ListBase;
-struct EditMesh;
+struct BMEditMesh;
+struct BMesh;
struct Mesh;
struct MPoly;
struct MLoop;
@@ -60,19 +61,50 @@ struct UvElement;
extern "C" {
#endif
-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,
+ const int do_face_normals);
/* for forwards compat only quad->tri polys to mface, skip ngons.
*/
int mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
struct CustomData *pdata, int totface, int totloop, int totpoly);
+/*calculates a face normal.*/
+void mesh_calc_poly_normal(struct MPoly *mpoly, struct MLoop *loopstart,
+ struct MVert *mvarray, float no[3]);
+
+void mesh_calc_poly_normal_coords(struct MPoly *mpoly, struct MLoop *loopstart,
+ const float (*vertex_coords)[3], float no[3]);
+
+void mesh_calc_poly_center(struct MPoly *mpoly, struct MLoop *loopstart,
+ struct MVert *mvarray, float cent[3]);
+
+float mesh_calc_poly_area(struct MPoly *mpoly, struct MLoop *loopstart,
+ struct MVert *mvarray, float polynormal[3]);
+
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);
+void mesh_update_customdata_pointers(struct Mesh *me, const short do_ensure_tess_cd);
+
void make_local_mesh(struct Mesh *me);
void boundbox_mesh(struct Mesh *me, float *loc, float *size);
void tex_space_mesh(struct Mesh *me);
@@ -82,17 +114,26 @@ int test_index_face(struct MFace *mface, struct CustomData *mfdata, int mfindex,
struct Mesh *get_mesh(struct Object *ob);
void set_mesh(struct Object *ob, struct Mesh *me);
void mball_to_mesh(struct ListBase *lb, struct Mesh *me);
-int nurbs_to_mdata(struct Object *ob, struct MVert **allvert, int *_totvert,
- struct MEdge **alledge, int *_totedge, struct MFace **allface, int *_totface);
-int nurbs_to_mdata_customdb(struct Object *ob, struct ListBase *dispbase,
- struct MVert **allvert, int *_totvert, struct MEdge **alledge, int *_totedge,
- struct MFace **allface, int *_totface);
+int nurbs_to_mdata(struct Object *ob, struct MVert **allvert, int *totvert,
+ struct MEdge **alledge, int *totedge, struct MLoop **allloop, struct MPoly **allpoly,
+ int *totloop, int *totpoly);
+int nurbs_to_mdata_customdb(struct Object *ob, struct ListBase *dispbase, struct MVert **allvert, int *_totvert,
+ struct MEdge **alledge, int *_totedge, struct MLoop **allloop, struct MPoly **allpoly,
+ int *_totloop, int *_totpoly);
void nurbs_to_mesh(struct Object *ob);
void mesh_to_curve(struct Scene *scene, struct Object *ob);
void free_dverts(struct MDeformVert *dvert, int totvert);
void copy_dverts(struct MDeformVert *dst, struct MDeformVert *src, int totvert); /* __NLA */
void mesh_delete_material_index(struct Mesh *me, short index);
void mesh_set_smooth_flag(struct Object *meshOb, int enableSmooth);
+void convert_mfaces_to_mpolys(struct Mesh *mesh);
+void mesh_calc_normals_tessface(struct MVert *mverts, int numVerts,struct MFace *mfaces, int numFaces, float (*faceNors_r)[3]);
+
+/*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.*/
+const 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);
@@ -106,7 +147,21 @@ void mesh_strip_loose_edges(struct Mesh *me);
/* Calculate vertex and face normals, face normals are returned in *faceNors_r if non-NULL
* and vertex normals are stored in actual mverts.
*/
-void mesh_calc_normals(struct MVert *mverts, int numVerts, struct MFace *mfaces, int numFaces, float (*faceNors_r)[3]);
+void mesh_calc_normals_mapping(
+ struct MVert *mverts, int numVerts,
+ struct MLoop *mloop, struct MPoly *mpolys, int numLoops, int numPolys, float (*polyNors_r)[3],
+ struct MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3]);
+ /* extended version of 'mesh_calc_normals' with option not to calc vertex normals */
+void mesh_calc_normals_mapping_ex(
+ struct MVert *mverts, int numVerts,
+ struct MLoop *mloop, struct MPoly *mpolys, int numLoops, int numPolys, float (*polyNors_r)[3],
+ struct MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3],
+ const short only_face_normals);
+
+void mesh_calc_normals(
+ struct MVert *mverts, int numVerts,
+ struct MLoop *mloop, struct MPoly *mpolys,
+ int numLoops, int numPolys, float (*polyNors_r)[3]);
/* Return a newly MEM_malloc'd array of all the mesh vertex locations
* (_numVerts_r_ may be NULL) */
@@ -129,24 +184,14 @@ typedef struct UvMapVert {
unsigned char tfindex, separate, flag;
} UvMapVert;
-typedef struct UvElementMap {
- /* address UvElements by their vertex */
- struct UvElement **vert;
- /* UvElement Store */
- struct UvElement *buf;
- /* Total number of UVs in the layer. Useful to know */
- int totalUVs;
- /* Number of Islands in the mesh */
- int totalIslands;
- /* Stores the starting index in buf where each island begins */
- int *islandIndices;
-} UvElementMap;
-
+/* UvElement stores per uv information so that we can quickly access information for a uv.
+ * it is actually an improved UvMapVert, including an island and a direct pointer to the face
+ * to avoid initialising face arrays */
typedef struct UvElement {
/* Next UvElement corresponding to same vertex */
struct UvElement *next;
/* Face the element belongs to */
- struct EditFace *face;
+ struct BMFace *face;
/* Index in the editFace of the uv */
unsigned char tfindex;
/* Whether this element is the first of coincident elements */
@@ -157,12 +202,29 @@ typedef struct UvElement {
unsigned short island;
} UvElement;
+
+/* UvElementMap is a container for UvElements of a mesh. It stores some UvElements belonging to the
+ * same uv island in sequence and the number of uvs per island so it is possible to access all uvs
+ * belonging to an island directly by iterating through the buffer.
+ */
+typedef struct UvElementMap {
+ /* address UvElements by their vertex */
+ struct UvElement **vert;
+ /* UvElement Store */
+ struct UvElement *buf;
+ /* Total number of UVs in the layer. Useful to know */
+ int totalUVs;
+ /* Number of Islands in the mesh */
+ int totalIslands;
+ /* Stores the starting index in buf where each island begins */
+ int *islandIndices;
+} UvElementMap;
+
/* invalid island index is max short. If any one has the patience
* to make that many islands, he can bite me :p */
#define INVALID_ISLAND 0xFFFF
-
-UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned int totface, unsigned int totvert, int selected, float *limit);
+UvVertMap *make_uv_vert_map(struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv, unsigned int totpoly, unsigned int totvert, int selected, float *limit);
UvMapVert *get_uv_map_vert(UvVertMap *vmap, unsigned int v);
void free_uv_vert_map(UvVertMap *vmap);
@@ -171,6 +233,9 @@ typedef struct IndexNode {
struct IndexNode *next, *prev;
int index;
} IndexNode;
+void create_vert_poly_map(struct ListBase **map, IndexNode **mem,
+ struct MPoly *mface, struct MLoop *mloop,
+ const int totvert, const int totface, const int totloop);
void create_vert_face_map(struct ListBase **map, IndexNode **mem, const struct MFace *mface,
const int totvert, const int totface);
void create_vert_edge_map(struct ListBase **map, IndexNode **mem, const struct MEdge *medge,
@@ -203,11 +268,15 @@ void BKE_mesh_calc_edges(struct Mesh *mesh, int update);
void BKE_mesh_ensure_navmesh(struct Mesh *me);
+void BKE_mesh_tessface_calc(struct Mesh *mesh);
+void BKE_mesh_tessface_ensure(struct Mesh *mesh);
+void BKE_mesh_tessface_clear(struct Mesh *mesh);
+
/*convert a triangle of loop facedata to mface facedata*/
void mesh_loops_to_mface_corners(struct CustomData *fdata, struct CustomData *ldata,
struct CustomData *pdata, int lindex[4], int findex,
const int polyindex, const int mf_len,
- const int numTex, const int numCol, const int hasWCol);
+ const int numTex, const int numCol, const int hasWCol, const int hasOrigSpace);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 895fe64bea8..f3307b73187 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -45,6 +45,7 @@ struct ListBase;
struct LinkNode;
struct bArmature;
struct ModifierData;
+struct BMEditMesh;
typedef enum {
/* Should not be used, only for None modifier type */
@@ -154,13 +155,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 *********************/
@@ -198,7 +199,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_multires.h b/source/blender/blenkernel/BKE_multires.h
index 53a92f8c2ce..bbf87c186e3 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -71,6 +71,14 @@ int multiresModifier_reshapeFromDeformMod(struct Scene *scene, struct MultiresMo
void multires_stitch_grids(struct Object *);
+/*switch mdisp data in dm between tangent and object space*/
+enum {
+ MULTIRES_SPACE_TANGENT,
+ MULTIRES_SPACE_OBJECT,
+ MULTIRES_SPACE_ABSOLUTE,
+};
+void multires_set_space(struct DerivedMesh *dm, struct Object *ob, int from, int to);
+
/* Related to the old multires */
void multires_free(struct Multires *mr);
void multires_load_old(struct Object *ob, struct Mesh *me);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index c048dad82eb..045e11c18b8 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -67,13 +67,14 @@ typedef struct SculptSession {
/* Mesh data (not copied) can come either directly from a Mesh, or from a MultiresDM */
struct MultiresModifierData *multires; /* Special handling for multires meshes */
struct MVert *mvert;
- struct MFace *mface;
- int totvert, totface;
+ struct MPoly *mpoly;
+ struct MLoop *mloop;
+ int totvert, totpoly;
float *face_normals;
struct KeyBlock *kb;
/* Mesh connectivity */
- struct ListBase *fmap;
+ struct ListBase *pmap;
/* PBVH acceleration structure */
struct PBVH *pbvh;
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index 5e56cc7b3be..cf77ea85c15 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -46,6 +46,10 @@ struct _CCGEdge;
struct _CCGFace;
struct _CCGSubsurf;
struct _CCGVert;
+struct EdgeHash;
+struct PBVH;
+struct DMGridData;
+struct DMGridAdjacency;
/**************************** External *****************************/
@@ -74,10 +78,15 @@ typedef struct CCGDerivedMesh {
short *edgeFlags;
char *faceFlags;
+ int *reverseFaceMap;
+
struct PBVH *pbvh;
struct ListBase *fmap;
struct IndexNode *fmap_mem;
+ struct ListBase *pmap;
+ struct IndexNode *pmap_mem;
+
struct DMGridData **gridData;
struct DMGridAdjacency *gridAdjacency;
int *gridOffset;
@@ -95,6 +104,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..cc3f2870711
--- /dev/null
+++ b/source/blender/blenkernel/BKE_tessmesh.h
@@ -0,0 +1,94 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#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;
+
+ /* 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*/
+ short selectmode;
+ short 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; /* -1 is invalid */
+ int mirr_free_arrays;
+} BMEditMesh;
+
+/* undo triggers editmesh tessface update, this is odd but works OK.
+ * BMESH_TODO, look into having the update elsewhere. */
+#define BMESH_EM_UNDO_RECALC_TESSFACE_WORKAROUND
+
+void BMEdit_RecalcTesselation(BMEditMesh *tm);
+BMEditMesh *BMEdit_Create(BMesh *bm, int do_tesselate);
+BMEditMesh *BMEdit_Copy(BMEditMesh *tm);
+void BMEdit_Free(BMEditMesh *em);
+void BMEdit_UpdateLinkedCustomData(BMEditMesh *em);
+
+#endif /* __BKE_TESSMESH_H__ */
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 1d5bdb36de7..fe9ba5be2ac 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -35,6 +35,7 @@ set(INC
../imbuf
../makesdna
../makesrna
+ ../bmesh
../modifiers
../nodes
../render/extern/include
@@ -58,12 +59,6 @@ set(INC_SYS
)
set(SRC
- intern/BME_Customdata.c
- intern/BME_conversions.c
- intern/BME_eulers.c
- intern/BME_mesh.c
- intern/BME_structure.c
- intern/BME_tools.c
intern/CCGSubSurf.c
intern/DerivedMesh.c
intern/action.c
@@ -116,6 +111,7 @@ set(SRC
intern/mesh.c
intern/mesh_validate.c
intern/modifier.c
+ intern/modifiers_bmesh.c
intern/movieclip.c
intern/multires.c
intern/nla.c
@@ -230,6 +226,7 @@ set(SRC
BKE_speaker.h
BKE_subsurf.h
BKE_suggestions.h
+ BKE_tessmesh.h
BKE_text.h
BKE_texture.h
BKE_tracking.h
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
index b5d4915f8d4..6fed2072e04 100644
--- a/source/blender/blenkernel/SConscript
+++ b/source/blender/blenkernel/SConscript
@@ -12,6 +12,7 @@ incs += ' #/intern/iksolver/extern ../blenloader ../freestyle'
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
deleted file mode 100644
index bb909dcbbdd..00000000000
--- a/source/blender/blenkernel/intern/BME_Customdata.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * BME_customdata.c jan 2007
- *
- * Custom Data functions for Bmesh
- *
- *
- * ***** 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): Geoffrey Bantle, Brecht Van Lommel, Ben Batt
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/BME_Customdata.c
- * \ingroup bke
- */
-
-
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-#include "BKE_bmeshCustomData.h"
-#include "bmesh_private.h"
-
-/********************* Layer type information **********************/
-typedef struct BME_LayerTypeInfo {
- int size;
- const char *defaultname;
- void (*copy)(const void *source, void *dest, int count);
- void (*free)(void *data, int count, int size);
- void (*interp)(void **sources, float *weights, float *sub_weights, int count, void *dest);
- void (*set_default)(void *data, int count);
-} BME_LayerTypeInfo;
-const BME_LayerTypeInfo BMELAYERTYPEINFO[BME_CD_NUMTYPES] = {
- {sizeof(BME_facetex), "TexFace", NULL, NULL, NULL, NULL},
- {sizeof(BME_looptex), "UV", NULL, NULL, NULL, NULL},
- {sizeof(BME_loopcol), "VCol", NULL, NULL, NULL, NULL},
- {sizeof(BME_DeformVert), "Group", NULL, NULL, NULL, NULL}
-};
-static const BME_LayerTypeInfo *BME_layerType_getInfo(int type)
-{
- if(type < 0 || type >= CD_NUMTYPES) return NULL;
-
- return &BMELAYERTYPEINFO[type];
-}
-void BME_CD_Create(BME_CustomData *data, BME_CustomDataInit *init, int initalloc)
-{
- int i, j, offset=0;
- const BME_LayerTypeInfo *info;
-
- /*initialize data members*/
- data->layers = NULL;
- data->pool = NULL;
- data->totlayer = 0;
- data->totsize = 0;
-
- /*first count how many layers to alloc*/
- for(i=0; i < BME_CD_NUMTYPES; i++){
- info = BME_layerType_getInfo(i);
- data->totlayer += init->layout[i];
- data->totsize += (init->layout[i] * info->size);
- }
- /*alloc our layers*/
- 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, FALSE, FALSE);
- /*initialize layer data*/
- for(i=0; i < BME_CD_NUMTYPES; i++){
- if(init->layout[i]){
- info = BME_layerType_getInfo(i);
- for(j=0; j < init->layout[i]; j++){
- if(j==0) data->layers[j+i].active = init->active[i];
- data->layers[j+i].type = i;
- data->layers[j+i].offset = offset;
- strcpy(data->layers[j+i].name, &(init->nametemplate[j+i]));
- offset += info->size;
- }
- }
- }
- }
-}
-
-void BME_CD_Free(BME_CustomData *data)
-{
- if(data->pool) BLI_mempool_destroy(data->pool);
-}
-
-/*Block level ops*/
-void BME_CD_free_block(BME_CustomData *data, void **block)
-{
- const BME_LayerTypeInfo *typeInfo;
- int i;
-
- if(!*block) return;
- for(i = 0; i < data->totlayer; ++i) {
- typeInfo = BME_layerType_getInfo(data->layers[i].type);
- if(typeInfo->free) {
- int offset = data->layers[i].offset;
- typeInfo->free((char*)*block + offset, 1, typeInfo->size);
- }
- }
- BLI_mempool_free(data->pool, *block);
- *block = NULL;
-}
-
-
-static void BME_CD_alloc_block(BME_CustomData *data, void **block)
-{
-
- if (*block) BME_CD_free_block(data, block); //if we copy layers that have their own free functions like deformverts
-
- if (data->totsize > 0)
- *block = BLI_mempool_alloc(data->pool);
- else
- *block = NULL;
-}
-
-void BME_CD_copy_data(const BME_CustomData *source, BME_CustomData *dest,
- void *src_block, void **dest_block)
-{
- const BME_LayerTypeInfo *typeInfo;
- int dest_i, src_i;
-
- if (!*dest_block) /*for addXXXlist functions!*/
- BME_CD_alloc_block(dest, dest_block);
-
- /* copies a layer at a time */
- dest_i = 0;
- for(src_i = 0; src_i < source->totlayer; ++src_i) {
-
- /* find the first dest layer with type >= the source type
- * (this should work because layers are ordered by type)
- */
- while(dest_i < dest->totlayer
- && dest->layers[dest_i].type < source->layers[src_i].type)
- ++dest_i;
-
- /* if there are no more dest layers, we're done */
- if(dest_i >= dest->totlayer) return;
-
- /* if we found a matching layer, copy the data */
- if(dest->layers[dest_i].type == source->layers[src_i].type &&
- strcmp(dest->layers[dest_i].name, source->layers[src_i].name) == 0) {
- char *src_data = (char*)src_block + source->layers[src_i].offset;
- char *dest_data = (char*)*dest_block + dest->layers[dest_i].offset;
-
- typeInfo = BME_layerType_getInfo(source->layers[src_i].type);
-
- if(typeInfo->copy)
- typeInfo->copy(src_data, dest_data, 1);
- else
- memcpy(dest_data, src_data, typeInfo->size);
-
- /* if there are multiple source & dest layers of the same type,
- * we don't want to copy all source layers to the same dest, so
- * increment dest_i
- */
- ++dest_i;
- }
- }
-}
-void BME_CD_set_default(BME_CustomData *data, void **block)
-{
- const BME_LayerTypeInfo *typeInfo;
- int i;
-
- if (!*block)
- BME_CD_alloc_block(data, block); //for addXXXlist functions...
-
- for(i = 0; i < data->totlayer; ++i) {
- int offset = data->layers[i].offset;
-
- typeInfo = BME_layerType_getInfo(data->layers[i].type);
-
- if(typeInfo->set_default)
- typeInfo->set_default((char*)*block + offset, 1);
- }
-}
diff --git a/source/blender/blenkernel/intern/BME_conversions.c b/source/blender/blenkernel/intern/BME_conversions.c
deleted file mode 100644
index bc87c5dbb6a..00000000000
--- a/source/blender/blenkernel/intern/BME_conversions.c
+++ /dev/null
@@ -1,650 +0,0 @@
-/*
- * BME_mesh.c jan 2007
- *
- * BMesh mesh level 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., 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): Geoffrey Bantle, Levi Schooley.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/BME_conversions.c
- * \ingroup bke
- */
-
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-
-#include "BLI_edgehash.h"
-#include "BLI_listbase.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_mesh.h"
-#include "BKE_cdderivedmesh.h"
-
-//XXX #include "BIF_editmesh.h"
-//XXX #include "editmesh.h"
-#include "bmesh_private.h"
-
-//XXX #include "BSE_edit.h"
-
-/* XXX IMPORTANT: editmesh stuff doesn't belong in kernel! (ton) */
-
-/*merge these functions*/
-static void BME_DMcorners_to_loops(BME_Mesh *bm, CustomData *facedata, int index, BME_Poly *f, int numCol, int numTex){
- int i, j;
- BME_Loop *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);
- }
-}
-
-static void BME_DMloops_to_corners(BME_Mesh *bm, CustomData *facedata, int index, BME_Poly *f,int numCol, int numTex){
- int i, j;
- BME_Loop *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);
- }
-}
-
-
-static void BME_corners_to_loops(BME_Mesh *bm, CustomData *facedata, void *face_block, BME_Poly *f,int numCol, int numTex){
- int i, j;
- BME_Loop *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->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;
-
- j = 0;
- l = f->loopbase;
- do{
- mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
- mloopuv->uv[0] = texface->uv[j][0];
- mloopuv->uv[1] = texface->uv[j][1];
- j++;
- l = l->next;
- }while(l!=f->loopbase);
-
- }
- 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->data, CD_MLOOPCOL, i);
- mloopcol->r = mcol[j].r;
- mloopcol->g = mcol[j].g;
- mloopcol->b = mcol[j].b;
- mloopcol->a = mcol[j].a;
- j++;
- l = l->next;
- }while(l!=f->loopbase);
- }
-}
-
-static void BME_loops_to_corners(BME_Mesh *bm, CustomData *facedata, void *face_block, BME_Poly *f,int numCol, int numTex){
- int i, j;
- BME_Loop *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->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->data, CD_MLOOPUV, i);
- texface->uv[j][0] = mloopuv->uv[0];
- texface->uv[j][1] = mloopuv->uv[1];
- j++;
- l = l->next;
- }while(l!=f->loopbase);
-
- }
- 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->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 = l->next;
- }while(l!=f->loopbase);
- }
-}
-/*move the EditMesh conversion functions to editmesh_tools.c*/
-BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em) {
- BME_Mesh *bm;
- int allocsize[4] = {512,512,2048,512}, numTex, numCol;
- BME_Vert *v1, *v2;
- BME_Edge *e, *edar[4];
- BME_Poly *f;
-
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- int len;
- bm = BME_make_mesh(allocsize);
-
- /*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);
- /*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);
-
- BME_model_begin(bm);
- /*add verts*/
- eve= em->verts.first;
- while(eve) {
- v1 = BME_MV(bm,eve->co);
- VECCOPY(v1->no,eve->no);
- v1->flag = eve->f;
- v1->h = eve->h;
- v1->bweight = eve->bweight;
- /*Copy Custom Data*/
- CustomData_bmesh_copy_data(&em->vdata, &bm->vdata, eve->data, &v1->data);
- eve->tmp.v = (EditVert*)v1;
- eve = eve->next;
- }
-
- /*add edges*/
- eed= em->edges.first;
- while(eed) {
- v1 = (BME_Vert*)eed->v1->tmp.v;
- v2 = (BME_Vert*)eed->v2->tmp.v;
- e = BME_ME(bm, v1, v2);
- e->crease = eed->crease;
- e->bweight = eed->bweight;
- e->flag = eed->f & SELECT;
- if(eed->sharp) e->flag |= ME_SHARP;
- if(eed->seam) e->flag |= ME_SEAM;
- if(eed->freestyle) e->flag |= ME_FREESTYLE_EDGE;
- //XXX if(eed->h & EM_FGON) e->flag |= ME_FGON;
- if(eed->h & 1) e->flag |= ME_HIDE;
- eed->tmp.e = (EditEdge*)e;
- CustomData_bmesh_copy_data(&em->edata, &bm->edata, eed->data, &e->data);
- eed = eed->next;
- }
- /*add faces.*/
- efa= em->faces.first;
- while(efa) {
- if(efa->v4) len = 4;
- else len = 3;
-
- edar[0] = (BME_Edge*)efa->e1->tmp.e;
- edar[1] = (BME_Edge*)efa->e2->tmp.e;
- edar[2] = (BME_Edge*)efa->e3->tmp.e;
- if(len == 4){
- edar[3] = (BME_Edge*)efa->e4->tmp.e;
- }
-
- /*find v1 and v2*/
- v1 = (BME_Vert*)efa->v1->tmp.v;
- v2 = (BME_Vert*)efa->v2->tmp.v;
-
- f = BME_MF(bm,v1,v2,edar,len);
- f->mat_nr = efa->mat_nr;
- f->flag = efa->flag;
- if(efa->h) {
- f->flag |= ME_HIDE;
- f->flag &= ~ME_FACE_SEL;
- }
- else {
- if(efa->f & 1) f->flag |= ME_FACE_SEL;
- else f->flag &= ~ME_FACE_SEL;
- }
- CustomData_bmesh_copy_data(&em->fdata, &bm->pdata, efa->data, &f->data);
- BME_corners_to_loops(bm, &em->fdata, efa->data, f,numCol,numTex);
- efa = efa->next;
- }
- BME_model_end(bm);
- return bm;
-}
-/* adds the geometry in the bmesh to editMesh (does not free editMesh)
- * if td != NULL, the transdata will be mapped to the EditVert's co */
-void BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td, EditMesh *em) {
- BME_Vert *v1;
- BME_Edge *e;
- BME_Poly *f;
-
- BME_TransData *vtd;
-
- EditVert *eve1, /* *eve2, *eve3, *eve4, */ /* UNUSED */ **evlist;
- EditEdge *eed;
- EditFace *efa;
-
- int totvert, len, i, numTex, numCol;
-
- if (em == NULL) return;
-
- CustomData_copy(&bm->vdata, &em->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
- CustomData_copy(&bm->edata, &em->edata, CD_MASK_BMESH, CD_CALLOC, 0);
- CustomData_copy(&bm->pdata, &em->fdata, CD_MASK_BMESH, 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);
-
-
- /* convert to EditMesh */
- /* make editverts */
- totvert = BLI_countlist(&(bm->verts));
- evlist= (EditVert **)MEM_mallocN(totvert*sizeof(void *),"evlist");
- for (i=0,v1=bm->verts.first;v1;v1=v1->next,i++) {
- v1->tflag1 = i;
- eve1 = NULL; //XXX addvertlist(v1->co,NULL);
- if (td && (vtd = BME_get_transdata(td,v1))) {
- vtd->loc = eve1->co;
- }
- eve1->keyindex = i;
- evlist[i]= eve1;
- eve1->f = (unsigned char)v1->flag;
- eve1->h = (unsigned char)v1->h;
- eve1->bweight = v1->bweight;
- CustomData_em_copy_data(&bm->vdata, &em->vdata, v1->data, &eve1->data);
- }
-
- /* make edges */
- for (e=bm->edges.first;e;e=e->next) {
- if(0) { //XXX if(!(findedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1]))){
- eed= NULL; //XXX addedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1], NULL);
- eed->crease = e->crease;
- eed->bweight = e->bweight;
- if(e->flag & ME_SEAM) eed->seam = 1;
- if(e->flag & ME_SHARP) eed->sharp = 1;
- if(e->flag & ME_FREESTYLE_EDGE) eed->freestyle = 1;
- if(e->flag & SELECT) eed->f |= SELECT;
- //XXX if(e->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines!
- if(e->flag & ME_HIDE) eed->h |= 1;
- if(em->selectmode==SCE_SELECT_EDGE) {
- ; //XXX EM_select_edge(eed, eed->f & SELECT);
- }
- CustomData_em_copy_data(&bm->edata, &em->edata, e->data, &eed->data);
- }
- }
-
- /* make faces */
- for (f=bm->polys.first;f;f=f->next) {
- len = BME_cycle_length(f->loopbase);
- if (len==3 || len==4) {
- eve1= evlist[f->loopbase->v->tflag1];
- /* eve2= evlist[f->loopbase->next->v->tflag1]; */ /* UNUSED */
- /* eve3= evlist[f->loopbase->next->next->v->tflag1]; */ /* UNUSED */
- /* if (len == 4) {
- eve4= evlist[f->loopbase->prev->v->tflag1];
- }
- else {
- eve4= NULL;
- } */ /* UNUSED */
-
- efa = NULL; //XXX addfacelist(eve1, eve2, eve3, eve4, NULL, NULL);
- efa->mat_nr = (unsigned char)f->mat_nr;
- efa->flag= f->flag & ~ME_HIDE;
- if(f->flag & ME_FACE_SEL) {
- efa->f |= SELECT;
- }
- if(f->flag & ME_HIDE) efa->h= 1;
- // XXX flag depricated
- // if((G.f & G_FACESELECT) && (efa->f & SELECT))
- //XXX EM_select_face(efa, 1); /* flush down */
- CustomData_em_copy_data(&bm->pdata, &em->fdata, f->data, &efa->data);
- BME_loops_to_corners(bm, &em->fdata, efa->data, f,numCol,numTex);
- }
- }
-
- MEM_freeN(evlist);
-
-}
-
-/* Adds the geometry found in dm to bm
- */
-BME_Mesh *BME_derivedmesh_to_bmesh(DerivedMesh *dm)
-{
-
- BME_Mesh *bm;
- int allocsize[4] = {512,512,2048,512};
- MVert *mvert, *mv;
- MEdge *medge, *me;
- MFace *mface, *mf;
- int totface,totedge,totvert,i,len, numTex, numCol;
- BME_Vert *v1=NULL,*v2=NULL, **vert_array;
- BME_Edge *e=NULL;
- BME_Poly *f=NULL;
-
- EdgeHash *edge_hash = BLI_edgehash_new();
-
- bm = BME_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(*vert_array)*totvert,"BME_derivedmesh_to_bmesh BME_Vert* array");
-
- BME_model_begin(bm);
- /*add verts*/
- for(i=0,mv = mvert; i < totvert;i++,mv++){
- v1 = BME_MV(bm,mv->co);
- vert_array[i] = v1;
- v1->flag = mv->flag;
- v1->bweight = mv->bweight/255.0f;
- CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v1->data);
- }
- /*add edges*/
- for(i=0,me = medge; i < totedge;i++,me++){
- v1 = vert_array[me->v1];
- v2 = vert_array[me->v2];
- e = BME_ME(bm, v1, v2);
- e->crease = me->crease/255.0f;
- e->bweight = me->bweight/255.0f;
- e->flag = (unsigned char)me->flag;
- BLI_edgehash_insert(edge_hash,me->v1,me->v2,e);
- CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->data);
- }
- /*add faces.*/
- for(i=0,mf = mface; i < totface;i++,mf++){
- BME_Edge *edar[4];
- 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 = BME_MF(bm,v1,v2,edar,len);
- f->mat_nr = mf->mat_nr;
- f->flag = mf->flag;
- CustomData_to_bmesh_block(&dm->faceData,&bm->pdata,i,&f->data);
- BME_DMcorners_to_loops(bm, &dm->faceData,i,f, numCol,numTex);
- }
-
- BME_model_end(bm);
- BLI_edgehash_free(edge_hash, NULL);
- MEM_freeN(vert_array);
- return bm;
-}
-
-DerivedMesh *BME_bmesh_to_derivedmesh(BME_Mesh *bm, DerivedMesh *dm)
-{
- MFace *mface, *mf;
- MEdge *medge, *me;
- MVert *mvert, *mv;
- int *origindex;
- int totface, totedge, totvert, i, /* bmeshok, */ /* UNUSED */ len, numTex, numCol;
-
- BME_Vert *v1=NULL;
- BME_Edge *e=NULL, *oe=NULL;
- BME_Poly *f=NULL;
-
- DerivedMesh *result;
- EdgeHash *edge_hash = BLI_edgehash_new();
-
- totvert = BLI_countlist(&(bm->verts));
- totedge = 0;
-
- /*we cannot have double edges in a derived mesh!*/
- for(i=0, v1=bm->verts.first; v1; v1=v1->next, i++) v1->tflag1 = i;
- for(e=bm->edges.first; e; e=e->next){
- oe = BLI_edgehash_lookup(edge_hash,e->v1->tflag1, e->v2->tflag1);
- if(!oe){
- totedge++;
- BLI_edgehash_insert(edge_hash,e->v1->tflag1,e->v2->tflag1,e);
- e->tflag2 = 1;
- }
- else{
- e->tflag2 = 0;
- }
- }
-
- /*count quads and tris*/
- totface = 0;
- /* bmeshok = 1; */ /* UNUSED */
- for(f=bm->polys.first;f;f=f->next){
- len = BME_cycle_length(f->loopbase);
- if(len == 3 || len == 4) totface++;
- }
-
- /*convert back to mesh*/
- 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);
- origindex = result->getVertDataArray(result, CD_ORIGINDEX);
- for(i=0,v1=bm->verts.first,mv=mvert;v1;v1=v1->next,i++,mv++){
- VECCOPY(mv->co,v1->co);
- mv->flag = (unsigned char)v1->flag;
- mv->bweight = (char)(255.0*v1->bweight);
- CustomData_from_bmesh_block(&bm->vdata, &result->vertData, &v1->data, i);
- origindex[i] = ORIGINDEX_NONE;
- }
- medge = CDDM_get_edges(result);
- origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
- i=0;
- for(e=bm->edges.first,me=medge;e;e=e->next){
- if(e->tflag2){
- if(e->v1->tflag1 < e->v2->tflag1){
- me->v1 = e->v1->tflag1;
- me->v2 = e->v2->tflag1;
- }
- else{
- me->v1 = e->v2->tflag1;
- me->v2 = e->v1->tflag1;
- }
-
- me->crease = (char)(255.0*e->crease);
- me->bweight = (char)(255.0*e->bweight);
- me->flag = e->flag;
- CustomData_from_bmesh_block(&bm->edata, &result->edgeData, &e->data, i);
- origindex[i] = ORIGINDEX_NONE;
- me++;
- i++;
- }
- }
- if(totface){
- mface = CDDM_get_faces(result);
- origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
- /*make faces*/
- for(i=0,f=bm->polys.first;f;f=f->next){
- mf = &mface[i];
- len = BME_cycle_length(f->loopbase);
- if(len==3 || len==4){
- mf->v1 = f->loopbase->v->tflag1;
- mf->v2 = f->loopbase->next->v->tflag1;
- mf->v3 = f->loopbase->next->next->v->tflag1;
- if(len == 4){
- mf->v4 = f->loopbase->prev->v->tflag1;
- }
- /* test and rotate indexes if necessary so that verts 3 and 4 aren't index 0 */
- if(mf->v3 == 0 || (len == 4 && mf->v4 == 0)){
- test_index_face(mf, NULL, i, len);
- }
- mf->mat_nr = (unsigned char)f->mat_nr;
- mf->flag = (unsigned char)f->flag;
- CustomData_from_bmesh_block(&bm->pdata, &result->faceData, &f->data, i);
- BME_DMloops_to_corners(bm, &result->faceData, i, f,numCol,numTex);
- origindex[i] = ORIGINDEX_NONE;
- i++;
- }
- }
- }
- BLI_edgehash_free(edge_hash, NULL);
- return result;
-}
diff --git a/source/blender/blenkernel/intern/BME_eulers.c b/source/blender/blenkernel/intern/BME_eulers.c
deleted file mode 100644
index 25970dd8d91..00000000000
--- a/source/blender/blenkernel/intern/BME_eulers.c
+++ /dev/null
@@ -1,973 +0,0 @@
-/*
- * BME_eulers.c jan 2007
- *
- * BMesh Euler construction API.
- *
- *
- * ***** 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., 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): Geoffrey Bantle.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/BME_eulers.c
- * \ingroup bke
- */
-
-
-#include "MEM_guardedalloc.h"
-#include "BLI_listbase.h"
-#include "BLI_utildefines.h"
-
-#include "bmesh_private.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 BMesh 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 BME_loop_reverse, which is its own inverse).
-
- BME_MF/KF: Make Face and Kill Face
- BME_ME/KE: Make Edge and Kill Edge
- BME_MV/KV: Make Vert and Kill Vert
- BME_SEMV/JEKV: Split Edge, Make Vert and Join Edge, Kill Vert
- BME_SFME/JFKE: Split Face, Make Edge and Join Face, Kill Edge
- BME_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:
- -Finish inserting 'strict' validation in all Eulers
-*/
-
-void *BME_exit(char *s) {
- if (s) printf("%s\n",s);
- return NULL;
-}
-
-#define RETCLEAR(bm) {bm->rval->v = bm->rval->e = bm->rval->f = bm->rva->l = NULL;}
-/*MAKE Eulers*/
-
-/**
- * BME_MV
- *
- * MAKE VERT EULER:
- *
- * Makes a single loose vertex.
- *
- * Returns -
- * A BME_Vert pointer.
- */
-
-BME_Vert *BME_MV(BME_Mesh *bm, float *vec){
- BME_Vert *v = BME_addvertlist(bm, NULL);
- VECCOPY(v->co,vec);
- return v;
-}
-
-/**
- * BME_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 BME_Edge pointer.
- */
-
-BME_Edge *BME_ME(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2){
- BME_Edge *e=NULL;
- BME_CycleNode *d1=NULL, *d2=NULL;
- int valance1=0, valance2=0, edok;
-
- /*edge must be between two distinct vertices...*/
- if(v1 == v2) return NULL;
-
- #ifndef BME_FASTEULER
- /*count valance of v1*/
- if(v1->edge){
- d1 = BME_disk_getpointer(v1->edge,v1);
- if(d1) valance1 = BME_cycle_length(d1);
- else BME_error();
- }
- if(v2->edge){
- d2 = BME_disk_getpointer(v2->edge,v2);
- if(d2) valance2 = BME_cycle_length(d2);
- else BME_error();
- }
- #endif
-
- /*go ahead and add*/
- e = BME_addedgelist(bm, v1, v2, NULL);
- BME_disk_append_edge(e, e->v1);
- BME_disk_append_edge(e, e->v2);
-
- #ifndef BME_FASTEULER
- /*verify disk cycle lengths*/
- d1 = BME_disk_getpointer(e, e->v1);
- edok = BME_cycle_validate(valance1+1, d1);
- if(!edok) BME_error();
- d2 = BME_disk_getpointer(e, e->v2);
- edok = BME_cycle_validate(valance2+1, d2);
- if(!edok) BME_error();
-
- /*verify that edge actually made it into the cycle*/
- edok = BME_disk_hasedge(v1, e);
- if(!edok) BME_error();
- edok = BME_disk_hasedge(v2, e);
- if(!edok) BME_error();
- #endif
- return e;
-}
-
-
-
-/**
- * BME_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 BME_Poly pointer
- */
-
-#define MF_CANDIDATE 1
-#define MF_VISITED 2
-#define MF_TAKEN 4
-
-BME_Poly *BME_MF(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Edge **elist, int len)
-{
- BME_Poly *f = NULL;
- BME_Edge *curedge;
- BME_Vert *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(BME_verts_in_edge(v1,v2,elist[0]) == 0) return NULL;
-
- /*clear euler flags*/
- for(i=0;i<len;i++) elist[i]->eflag1=elist[i]->eflag2 = 0;
- for(i=0;i<len;i++){
- 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));
- else elist[i]->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 = BME_disk_count_edgeflag(elist[i]->v1, MF_CANDIDATE, 0);
- if(edok != 2) return NULL;
- edok = BME_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){
- MEM_freeN(bm->vtar);
- bm->vtar = MEM_callocN(sizeof(BME_Vert *)* len, "BMesh 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->eflag1 |= MF_VISITED;
-
- /*find next edge and vert*/
- curedge = BME_disk_next_edgeflag(curedge, curvert, MF_CANDIDATE, 0);
- curvert = BME_edge_getothervert(curedge, curvert);
- if(curvert == tv){
- curedge->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]->eflag1 & MF_VISITED) == 0) cont = 0;
- }
-
- /*if we get this far, its ok to allocate the face and add the loops*/
- if(cont){
- BME_Loop *l;
- BME_Edge *e;
- f = BME_addpolylist(bm, NULL);
- f->len = len;
- 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);
- }
-
- /*take care of edge pointers and radial cycle*/
- for(i=0, l = f->loopbase; i<len; i++, l=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 = BME_verts_in_edge(l->v, l->next->v, elist[j]);
- if(edok){
- e = elist[j];
- break;
- }
- }
- }
- l->e = e; /*set pointer*/
- BME_radial_append(e, l); /*append into radial*/
- }
-
- f->len = len;
-
- /*Validation Loop cycle*/
- edok = BME_cycle_validate(len, f->loopbase);
- if(!edok) BME_error();
- for(i=0, l = f->loopbase; i<len; i++, l=l->next){
- /*validate loop vert pointers*/
- edok = BME_verts_in_edge(l->v, l->next->v, l->e);
- if(!edok) BME_error();
- /*validate the radial cycle of each edge*/
- edok = BME_cycle_length(&(l->radial));
- if(edok != (l->e->eflag2 + 1)) BME_error();
- }
- }
- return f;
-}
-
-/* KILL Eulers */
-
-/**
- * BME_KV
- *
- * KILL VERT EULER:
- *
- * Kills a single loose vertex.
- *
- * Returns -
- * 1 for success, 0 for failure.
- */
-
-int BME_KV(BME_Mesh *bm, BME_Vert *v){
- if(v->edge == NULL){
- BLI_remlink(&(bm->verts), v);
- BME_free_vert(bm,v);
- return 1;
- }
- return 0;
-}
-
-/**
- * BME_KE
- *
- * KILL EDGE EULER:
- *
- * Kills a wire edge.
- *
- * Returns -
- * 1 for success, 0 for failure.
- */
-
-int BME_KE(BME_Mesh *bm, BME_Edge *e){
- int edok;
-
- /*Make sure that no faces!*/
- if(e->loop == NULL){
- BME_disk_remove_edge(e, e->v1);
- BME_disk_remove_edge(e, e->v2);
-
- /*verify that edge out of disk*/
- edok = BME_disk_hasedge(e->v1, e);
- if(edok) BME_error();
- edok = BME_disk_hasedge(e->v2, e);
- if(edok) BME_error();
-
- /*remove and deallocate*/
- BLI_remlink(&(bm->edges), e);
- BME_free_edge(bm, e);
- return 1;
- }
- return 0;
-}
-
-/**
- * BME_KF
- *
- * KILL FACE EULER:
- *
- * The logical inverse of BME_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 BME_KF(BME_Mesh *bm, BME_Poly *bply){
- BME_Loop *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 = BME_cycle_length(bply->loopbase);
- 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;
- BME_cycle_remove(oldbase, oldbase);
- BME_free_loop(bm, oldbase);
- bply->loopbase = newbase;
- }
-
- BLI_remlink(&(bm->polys), bply);
- BME_free_poly(bm, bply);
- return 1;
-}
-
-/*SPLIT Eulers*/
-
-/**
- * BME_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 -
- * BME_Vert pointer.
- *
-*/
-
-BME_Vert *BME_SEMV(BME_Mesh *bm, BME_Vert *tv, BME_Edge *e, BME_Edge **re){
- BME_Vert *nv, *ov;
- BME_CycleNode *diskbase;
- BME_Edge *ne;
- int i, edok, valance1=0, valance2=0;
-
- if(BME_vert_in_edge(e,tv) == 0) return NULL;
- ov = BME_edge_getothervert(e,tv);
- //v2 = tv;
-
- /*count valance of v1*/
- diskbase = BME_disk_getpointer(e, ov);
- valance1 = BME_cycle_length(diskbase);
- /*count valance of v2*/
- diskbase = BME_disk_getpointer(e, tv);
- valance2 = BME_cycle_length(diskbase);
-
- nv = BME_addvertlist(bm, tv);
- ne = BME_addedgelist(bm, nv, tv, e);
-
- //e->v2 = nv;
- /*remove e from v2's disk cycle*/
- BME_disk_remove_edge(e, tv);
- /*swap out tv for nv in e*/
- BME_edge_swapverts(e, tv, nv);
- /*add e to nv's disk cycle*/
- BME_disk_append_edge(e, nv);
- /*add ne to nv's disk cycle*/
- BME_disk_append_edge(ne, nv);
- /*add ne to tv's disk cycle*/
- BME_disk_append_edge(ne, tv);
- /*verify disk cycles*/
- diskbase = BME_disk_getpointer(ov->edge,ov);
- edok = BME_cycle_validate(valance1, diskbase);
- if(!edok) BME_error();
- diskbase = BME_disk_getpointer(tv->edge,tv);
- edok = BME_cycle_validate(valance2, diskbase);
- if(!edok) BME_error();
- diskbase = BME_disk_getpointer(nv->edge,nv);
- edok = BME_cycle_validate(2, diskbase);
- if(!edok) BME_error();
-
- /*Split the radial cycle if present*/
- if(e->loop){
- BME_Loop *nl,*l;
- BME_CycleNode *radEBase=NULL, *radNEBase=NULL;
- int radlen = BME_cycle_length(&(e->loop->radial));
- /*Take the next loop. Remove it from radial. Split it. Append to appropriate radials.*/
- while(e->loop){
- l=e->loop;
- l->f->len++;
- BME_radial_remove_loop(l,e);
-
- nl = BME_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(BME_verts_in_edge(nl->v, 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;
- }
-
- BME_cycle_append(radEBase,&(nl->radial));
- BME_cycle_append(radNEBase,&(l->radial));
-
- }
- else if(BME_verts_in_edge(nl->v,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;
- }
- BME_cycle_append(radEBase,&(l->radial));
- BME_cycle_append(radNEBase,&(nl->radial));
- }
-
- }
-
- e->loop = radEBase->data;
- ne->loop = radNEBase->data;
-
- /*verify length of radial cycle*/
- edok = BME_cycle_validate(radlen,&(e->loop->radial));
- if(!edok) BME_error();
- edok = BME_cycle_validate(radlen,&(ne->loop->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){
- if(!(l->e == e)) BME_error();
- if(!(l->radial.data == l)) BME_error();
- if(l->prev->e != ne && l->next->e != ne) BME_error();
- edok = BME_verts_in_edge(l->v, l->next->v, e);
- if(!edok) BME_error();
- 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);
- 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){
- if(!(l->e == ne)) BME_error();
- if(!(l->radial.data == l)) BME_error();
- if(l->prev->e != e && l->next->e != e) BME_error();
- edok = BME_verts_in_edge(l->v, l->next->v, ne);
- if(!edok) BME_error();
- 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);
- if(!edok) BME_error();
- }
- }
-
- if(re) *re = ne;
- return nv;
-}
-
-/**
- * BME_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.
- *
- * Returns -
- * A BME_Poly pointer
- */
-BME_Poly *BME_SFME(BME_Mesh *bm, BME_Poly *f, BME_Vert *v1, BME_Vert *v2, BME_Loop **rl){
-
- BME_Poly *f2;
- BME_Loop *v1loop = NULL, *v2loop = NULL, *curloop, *f1loop=NULL, *f2loop=NULL;
- BME_Edge *e;
- int i, len, f1len, f2len;
-
-
- /*verify that v1 and v2 are in face.*/
- len = BME_cycle_length(f->loopbase);
- 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;
- }
-
- if(!v1loop || !v2loop) return NULL;
-
- /*allocate new edge between v1 and v2*/
- e = BME_addedgelist(bm, v1, v2,NULL);
- BME_disk_append_edge(e, v1);
- BME_disk_append_edge(e, v2);
-
- f2 = BME_addpolylist(bm,f);
- f1loop = BME_create_loop(bm,v2,e,f,v2loop);
- f2loop = BME_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;
-
- 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 = BME_cycle_length(f2->loopbase);
- 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*/
- BME_radial_append(e, f1loop);
- BME_radial_append(e, f2loop);
-
-
- f2->len = f2len;
-
- f1len = BME_cycle_length(f->loopbase);
- f->len = f1len;
-
- if(rl) *rl = f2loop;
- return f2;
-}
-
-
-/**
- * BME_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 BME_JEKV(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv)
-{
- BME_Edge *oe;
- BME_Vert *ov, *tv;
- BME_CycleNode *diskbase;
- BME_Loop *killoop,*nextl;
- 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);
- len = BME_cycle_length(diskbase);
-
- if(len == 2){
- oe = BME_disk_nextedge(ke, kv);
- tv = BME_edge_getothervert(ke, kv);
- ov = BME_edge_getothervert(oe, kv);
- halt = BME_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 = BME_disk_getpointer(ov->edge, ov);
- valance1 = BME_cycle_length(diskbase);
- diskbase = BME_disk_getpointer(tv->edge, tv);
- valance2 = BME_cycle_length(diskbase);
-
- /*remove oe from kv's disk cycle*/
- BME_disk_remove_edge(oe,kv);
- /*relink oe->kv to be oe->tv*/
- BME_edge_swapverts(oe, kv, tv);
- /*append oe to tv's disk cycle*/
- BME_disk_append_edge(oe, tv);
- /*remove ke from tv's disk cycle*/
- BME_disk_remove_edge(ke, tv);
-
-
-
- /*deal with radial cycle of ke*/
- if(ke->loop){
- /*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)){
- /*relink loops and fix vertex pointer*/
- killoop->next->prev = killoop->prev;
- killoop->prev->next = killoop->next;
- if(killoop->next->v == kv) killoop->next->v = tv;
-
- /*fix len attribute of face*/
- killoop->f->len--;
- if(killoop->f->loopbase == killoop) killoop->f->loopbase = killoop->next;
- }
- /*second step, remove all the hanging loops attached to ke*/
- killoop = ke->loop;
- radlen = BME_cycle_length(&(ke->loop->radial));
- /*make sure we have enough room in bm->lpar*/
- if(bm->lparlen < radlen){
- MEM_freeN(bm->lpar);
- bm->lpar = MEM_callocN(sizeof(BME_Loop *)* radlen, "BMesh Loop pointer array");
- bm->lparlen = bm->lparlen * radlen;
- }
- /*this should be wrapped into a bme_free_radial function to be used by BME_KF as well...*/
- i=0;
- while(i<radlen){
- bm->lpar[i] = killoop;
- killoop = killoop->radial.next->data;
- i++;
- }
- i=0;
- while(i<radlen){
- BME_free_loop(bm,bm->lpar[i]);
- i++;
- }
- /*Validate radial cycle of oe*/
- edok = BME_cycle_validate(radlen,&(oe->loop->radial));
-
- }
-
-
- /*Validate disk cycles*/
- diskbase = BME_disk_getpointer(ov->edge,ov);
- edok = BME_cycle_validate(valance1, diskbase);
- if(!edok) BME_error();
- diskbase = BME_disk_getpointer(tv->edge,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);
- if(!edok) BME_error();
- }
- /*deallocate edge*/
- BLI_remlink(&(bm->edges), ke);
- BME_free_edge(bm, ke);
- /*deallocate vertex*/
- BLI_remlink(&(bm->verts), kv);
- BME_free_vert(bm, kv);
- return 1;
- }
- }
- return 0;
-}
-
-
-/**
- * BME_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 BME_loop_reverse(BME_Mesh *bm, BME_Poly *f){
- BME_Loop *l = f->loopbase, *curloop, *oldprev, *oldnext;
- int i, j, edok, len = 0;
-
- len = BME_cycle_length(l);
- if(bm->edarlen < len){
- MEM_freeN(bm->edar);
- bm->edar = MEM_callocN(sizeof(BME_Edge *)* len, "BMesh Edge pointer array");
- bm->edarlen = len;
- }
-
- for(i=0, curloop = l; i< len; i++, curloop=curloop->next){
- curloop->e->eflag1 = 0;
- curloop->e->eflag2 = BME_cycle_length(&curloop->radial);
- BME_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 BME_cycle_reverse!*/
- for(i=0, curloop = l; i < len; i++){
- oldnext = curloop->next;
- oldprev = curloop->prev;
- curloop->next = oldprev;
- curloop->prev = oldnext;
- curloop = oldnext;
- }
-
- if(len == 2){ //two edged face
- //do some verification here!
- l->e = bm->edar[1];
- l->next->e = bm->edar[0];
- }
- else{
- for(i=0, curloop = l; i < len; i++, curloop = curloop->next){
- edok = 0;
- for(j=0; j < len; j++){
- edok = BME_verts_in_edge(curloop->v, 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 = curloop->next) BME_radial_append(curloop->e, curloop);
-
- /*validate radial*/
- for(i=0, curloop = l; i < len; i++, curloop = curloop->next){
- edok = BME_cycle_validate(curloop->e->eflag2, &(curloop->radial));
- if(!edok){
- BME_error();
- }
- }
- return 1;
-}
-
-/**
- * BME_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 BME_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 BME_Poly pointer
-*/
-
-BME_Poly *BME_JFKE(BME_Mesh *bm, BME_Poly *f1, BME_Poly *f2, BME_Edge *e)
-{
-
- BME_Loop *curloop, *f1loop=NULL, *f2loop=NULL;
- int loopok = 0, newlen = 0,i, f1len=0, f2len=0, radlen=0, edok;
-
- 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);
- for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = curloop->next){
- if(curloop->e == e){
- f1loop = curloop;
- break;
- }
- }
- for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = curloop->next){
- if(curloop->e==e){
- f2loop = curloop;
- break;
- }
- }
- if(!(f1loop && f2loop)) return NULL;
-
- /*validate that edge is 2-manifold edge*/
- radlen = BME_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;
-
- /*
- Finally validate that for each face, each vertex has another edge in its disk cycle that is
- not e, and not shared.
- */
- if(BME_radial_find_face(f1loop->next->e,f2)) return NULL;
- if(BME_radial_find_face(f1loop->prev->e,f2)) return NULL;
- if(BME_radial_find_face(f2loop->next->e,f1)) return NULL;
- if(BME_radial_find_face(f2loop->prev->e,f1)) 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->loopbase = f1loop->next;
-
- /*validate the new loop*/
- loopok = BME_cycle_validate((f1len+f2len)-2, f1->loopbase);
- if(!loopok) BME_error();
-
- /*make sure each loop points to the proper face*/
- newlen = BME_cycle_length(f1->loopbase);
- 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);
- if(!edok) BME_error();
-
- /*remove edge from the disk cycle of its two vertices.*/
- BME_disk_remove_edge(f1loop->e, f1loop->e->v1);
- BME_disk_remove_edge(f1loop->e, f1loop->e->v2);
-
- /*deallocate edge and its two loops as well as f2*/
- BLI_remlink(&(bm->edges), f1loop->e);
- BLI_remlink(&(bm->polys), f2);
- BME_free_edge(bm, f1loop->e);
- BME_free_loop(bm, f1loop);
- BME_free_loop(bm, f2loop);
- BME_free_poly(bm, f2);
- return f1;
-}
diff --git a/source/blender/blenkernel/intern/BME_mesh.c b/source/blender/blenkernel/intern/BME_mesh.c
deleted file mode 100644
index cda66de6f22..00000000000
--- a/source/blender/blenkernel/intern/BME_mesh.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * BME_mesh.c jan 2007
- *
- * BMesh mesh level 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., 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): Geoffrey Bantle.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/BME_mesh.c
- * \ingroup bke
- */
-
-
-#include "BLI_listbase.h"
-#include "MEM_guardedalloc.h"
-#include "BKE_bmesh.h"
-#include "bmesh_private.h"
-
-/*
- * BME MAKE MESH
- *
- * Allocates a new BME_Mesh structure.
- * Returns -
- * Pointer to a Bmesh
- *
-*/
-
-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], FALSE, FALSE);
- bm->epool = BLI_mempool_create(sizeof(BME_Edge), allocsize[1], allocsize[1], FALSE, FALSE);
- bm->lpool = BLI_mempool_create(sizeof(BME_Loop), allocsize[2], allocsize[2], FALSE, FALSE);
- bm->ppool = BLI_mempool_create(sizeof(BME_Poly), allocsize[3], allocsize[3], FALSE, FALSE);
- return bm;
-}
-/*
- * BME FREE MESH
- *
- * Frees a BME_Mesh structure.
-*/
-
-void BME_free_mesh(BME_Mesh *bm)
-{
- BME_Vert *v;
- BME_Edge *e;
- BME_Loop *l;
- BME_Poly *f;
-
- for(v=bm->verts.first; v; v=v->next) CustomData_bmesh_free_block(&bm->vdata, &v->data);
- for(e=bm->edges.first; e; e=e->next) CustomData_bmesh_free_block(&bm->edata, &e->data);
- for(f=bm->polys.first; f; f=f->next){
- CustomData_bmesh_free_block(&bm->pdata, &f->data);
- l = f->loopbase;
- do{
- CustomData_bmesh_free_block(&bm->ldata, &l->data);
- l = l->next;
- }while(l!=f->loopbase);
- }
-
- /*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->ppool);
- BLI_mempool_destroy(bm->lpool);
-
- MEM_freeN(bm);
-}
-
-/*
- * BME MODEL BEGIN AND END
- *
- * These two functions represent the 'point of entry' for tools. Every BMesh tool
- * must begin with a call to BME_model_end() and finish with a call to BME_model_end().
- * No modification of mesh data is allowed except in between these two calls.
- *
- * The purpose of these calls is allow for housekeeping tasks to be performed,
- * such as allocating/freeing scratch arrays or performing debug validation of
- * the mesh structure.
- *
- * Returns -
- * Nothing
- *
-*/
-
-int BME_model_begin(BME_Mesh *bm){
- /*Initialize some scratch pointer arrays used by eulers*/
- bm->vtar = MEM_callocN(sizeof(BME_Vert *) * 1024, "BMesh scratch vert array");
- bm->edar = MEM_callocN(sizeof(BME_Edge *) * 1024, "BMesh scratch edge array");
- bm->lpar = MEM_callocN(sizeof(BME_Loop *) * 1024, "BMesh scratch loop array");
- bm->plar = MEM_callocN(sizeof(BME_Poly *) * 1024, "BMesh scratch poly array");
-
- bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 1024;
-
- return 1;
-}
-
-void BME_model_end(BME_Mesh *bm){
- int meshok, totvert, totedge, totpoly;
-
- totvert = BLI_countlist(&(bm->verts));
- totedge = BLI_countlist(&(bm->edges));
- totpoly = BLI_countlist(&(bm->polys));
-
- if(bm->vtar) MEM_freeN(bm->vtar);
- if(bm->edar) MEM_freeN(bm->edar);
- if(bm->lpar) MEM_freeN(bm->lpar);
- if(bm->plar) MEM_freeN(bm->plar);
-
- bm->vtar = NULL;
- bm->edar = NULL;
- bm->lpar = NULL;
- bm->plar = NULL;
- bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 0;
-
-
- if(bm->totvert!=totvert || bm->totedge!=totedge || bm->totpoly!=totpoly)
- BME_error();
-
- meshok = BME_validate_mesh(bm, 1);
- if(!meshok){
- BME_error();
- }
-}
-
-/*
- * BME VALIDATE MESH
- *
- * There are several levels of validation for meshes. At the
- * Euler level, some basic validation is done to local topology.
- * To catch more subtle problems however, BME_validate_mesh() is
- * called by BME_model_end() whenever a tool is done executing.
- * The purpose of this function is to insure that during the course
- * of tool execution that nothing has been done to invalidate the
- * structure, and if it has, provide a way of reporting that so that
- * we can restore the proper structure from a backup. Since a full mesh
- * validation would be too expensive, this is presented as a compromise.
- *
- * TODO
- *
- * -Make this only part of debug builds
- */
-
-#define VHALT(halt) {BME_error(); if(halt) return 0;}
-
-int BME_validate_mesh(struct BME_Mesh *bm, int halt)
-{
- BME_Vert *v;
- BME_Edge *e;
- BME_Poly *f;
- BME_Loop *l;
- BME_CycleNode *diskbase;
- int i, ok;
-
- /*Simple edge verification*/
- for(e=bm->edges.first; e; e=e->next){
- 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);
- }
- }
-
- /*calculate disk cycle lengths*/
- for(v=bm->verts.first; v; v=v->next) v->tflag1 = v->tflag2 = 0;
- for(e=bm->edges.first; e; e=e->next){
- e->v1->tflag1++;
- e->v2->tflag1++;
- }
- /*Validate vertices and disk cycle*/
- for(v=bm->verts.first; v; v=v->next){
- /*validate v->edge pointer*/
- if(v->tflag1){
- if(v->edge){
- ok = BME_vert_in_edge(v->edge,v);
- if(!ok) VHALT(halt);
- /*validate length of disk cycle*/
- diskbase = BME_disk_getpointer(v->edge, 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)){
- ok = BME_vert_in_edge(e, v);
- if(!ok) VHALT(halt);
- }
- }
- else VHALT(halt);
- }
- }
- /*validate edges*/
- for(e=bm->edges.first; e; e=e->next){
- /*seperate these into BME_disk_hasedge (takes pointer to edge)*/
- /*search v1 disk cycle for edge*/
- ok = BME_disk_hasedge(e->v1,e);
- if(!ok) VHALT(halt);
- /*search v2 disk cycle for edge*/
- ok = BME_disk_hasedge(e->v2,e);
- if(!ok) VHALT(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);
- if(ok > 1){
- f->tflag1 = ok;
- }
- else VHALT(halt);
- for(i=0, l=f->loopbase; i < f->tflag1; i++, l=l->next){
- /*verify loop->v pointers*/
- ok = BME_verts_in_edge(l->v, l->next->v, l->e);
- 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->f pointer*/
- if(l->f != f) VHALT(halt);
- /*see if l->e->loop is actually in radial cycle*/
-
- l->e->tflag2++;
- }
- }
-
- /*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(!ok) VHALT(halt);
- }
- }
-
- /*validate that EIDs are within range... if not indicates corrupted mem*/
-
- /*if we get this far, pretty safe to return 1*/
- return 1;
-}
-
-/* Currently just a convient place for a breakpoint.
- Probably should take an error string
-*/
-void BME_error(void){
- printf("BME modelling error!");
-}
diff --git a/source/blender/blenkernel/intern/BME_structure.c b/source/blender/blenkernel/intern/BME_structure.c
deleted file mode 100644
index 6d8a8339e46..00000000000
--- a/source/blender/blenkernel/intern/BME_structure.c
+++ /dev/null
@@ -1,628 +0,0 @@
-/*
- * BME_structure.c jan 2007
- *
- * Low level routines for manipulating the BMesh structure.
- *
- *
- * ***** 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., 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): Geoffrey Bantle.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/BME_structure.c
- * \ingroup bke
- */
-
-
-#include <limits.h>
-
-#include "MEM_guardedalloc.h"
-#include "BLI_listbase.h"
-#include "BLI_utildefines.h"
-#include "BKE_bmesh.h"
-/**
- * MISC utility functions.
- *
- */
-
-int BME_vert_in_edge(BME_Edge *e, BME_Vert *v){
- if(e->v1 == v || e->v2 == v) return 1;
- return 0;
-}
-int BME_verts_in_edge(BME_Vert *v1, BME_Vert *v2, BME_Edge *e){
- if(e->v1 == v1 && e->v2 == v2) return 1;
- else if(e->v1 == v2 && e->v2 == v1) return 1;
- return 0;
-}
-
-BME_Vert *BME_edge_getothervert(BME_Edge *e, BME_Vert *v){
- if(e->v1 == v) return e->v2;
- else if(e->v2 == v) return e->v1;
- return NULL;
-}
-
-int BME_edge_swapverts(BME_Edge *e, BME_Vert *orig, BME_Vert *new){
- if(e->v1 == orig){
- e->v1 = new;
- e->d1.next = NULL;
- e->d1.prev = NULL;
- return 1;
- }
- else if(e->v2 == orig){
- e->v2 = new;
- e->d2.next = NULL;
- e->d2.prev = NULL;
- return 1;
- }
- return 0;
-}
-
-/**
- * ALLOCATION/DEALLOCATION FUNCTIONS
- */
-
-BME_Vert *BME_addvertlist(BME_Mesh *bm, BME_Vert *example){
- BME_Vert *v=NULL;
- v = BLI_mempool_alloc(bm->vpool);
- v->next = v->prev = NULL;
- 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->data = NULL;
- v->eflag1 = v->eflag2 = v->tflag1 = v->tflag2 = 0;
- v->flag = v->h = 0;
- v->bweight = 0.0f;
- BLI_addtail(&(bm->verts), v);
- bm->nextv++;
- bm->totvert++;
-
- if(example){
- VECCOPY(v->co,example->co);
- CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, example->data, &v->data);
- }
- else
- CustomData_bmesh_set_default(&bm->vdata, &v->data);
-
- return v;
-}
-BME_Edge *BME_addedgelist(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Edge *example){
- BME_Edge *e=NULL;
- e = BLI_mempool_alloc(bm->epool);
- e->next = e->prev = NULL;
- e->EID = bm->nexte;
- e->v1 = v1;
- e->v2 = v2;
- 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->data = NULL;
- e->eflag1 = e->eflag2 = e->tflag1 = e->tflag2 = 0;
- e->flag = e->h = 0;
- e->crease = e->bweight = 0.0f;
- bm->nexte++;
- bm->totedge++;
- BLI_addtail(&(bm->edges), e);
-
- if(example)
- CustomData_bmesh_copy_data(&bm->edata, &bm->edata, example->data, &e->data);
- else
- CustomData_bmesh_set_default(&bm->edata, &e->data);
-
-
- return e;
-}
-BME_Loop *BME_create_loop(BME_Mesh *bm, BME_Vert *v, BME_Edge *e, BME_Poly *f, BME_Loop *example){
- BME_Loop *l=NULL;
- l = BLI_mempool_alloc(bm->lpool);
- l->next = l->prev = NULL;
- l->EID = bm->nextl;
- l->radial.next = l->radial.prev = NULL;
- l->radial.data = l;
- l->v = v;
- l->e = e;
- l->f = f;
- l->data = NULL;
- l->eflag1 = l->eflag2 = l->tflag1 = l->tflag2 = 0;
- l->flag = l->h = 0; //stupid waste!
- bm->nextl++;
- bm->totloop++;
-
- if(example)
- CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, example->data, &l->data);
- else
- CustomData_bmesh_set_default(&bm->ldata, &l->data);
-
- return l;
-}
-
-BME_Poly *BME_addpolylist(BME_Mesh *bm, BME_Poly *example){
- BME_Poly *f = NULL;
- f = BLI_mempool_alloc(bm->ppool);
- f->next = f->prev = NULL;
- f->EID = bm->nextp;
- f->loopbase = NULL;
- f->len = 0;
- f->data = NULL;
- f->eflag1 = f->eflag2 = f->tflag1 = f->tflag2 = 0;
- f->flag = f->h = f->mat_nr;
- BLI_addtail(&(bm->polys),f);
- bm->nextp++;
- bm->totpoly++;
-
- if(example)
- CustomData_bmesh_copy_data(&bm->pdata, &bm->pdata, example->data, &f->data);
- else
- CustomData_bmesh_set_default(&bm->pdata, &f->data);
-
-
- return f;
-}
-
-/* free functions dont do much *yet*. When per-vertex, per-edge and per-face/faceloop
- data is added though these will be needed.
-*/
-void BME_free_vert(BME_Mesh *bm, BME_Vert *v){
- bm->totvert--;
- CustomData_bmesh_free_block(&bm->vdata, &v->data);
- BLI_mempool_free(bm->vpool, v);
-}
-void BME_free_edge(BME_Mesh *bm, BME_Edge *e){
- bm->totedge--;
- CustomData_bmesh_free_block(&bm->edata, &e->data);
- BLI_mempool_free(bm->epool, e);
-}
-void BME_free_poly(BME_Mesh *bm, BME_Poly *f){
- bm->totpoly--;
- CustomData_bmesh_free_block(&bm->pdata, &f->data);
- BLI_mempool_free(bm->ppool, f);
-}
-void BME_free_loop(BME_Mesh *bm, BME_Loop *l){
- bm->totloop--;
- CustomData_bmesh_free_block(&bm->ldata, &l->data);
- BLI_mempool_free(bm->lpool, l);
-}
-/**
- * BMESH CYCLES
- *
- * 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
- * BME_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 BMesh 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 BME_Edge contains
- * two BME_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 BME_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:
- *
- * BME_disk_append_edge
- * BME_disk_remove_edge
- * BME_disk_nextedge
- * BME_disk_getpointer
- *
- * 2: The Radial Cycle - A circle of face edges (BME_Loop) around an edge
- * Base: edge->loop->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 BMesh does not keep track of region/shell
- * information.
- *
- * Functions relating to this cycle:
- *
- * BME_radial_append
- * BME_radial_remove_loop
- * BME_radial_nextloop
- * BME_radial_find_face
- *
- *
- * 3: The Loop Cycle - A circle of face edges around a polygon.
- * Base: polygon->loopbase.
- *
- * 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:
- *
- * BME_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.
- *
-*/
-
-
-void BME_cycle_append(void *h, void *nt)
-{
- BME_CycleNode *oldtail, *head, *newtail;
-
- head = (BME_CycleNode*)h;
- newtail = (BME_CycleNode*)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;
-
- }
-}
-
-/**
- * BME_cycle_length
- *
- * Count the nodes in a cycle.
- *
- * Returns -
- * Integer
- */
-
-int BME_cycle_length(void *h){
-
- int len = 0;
- BME_CycleNode *head, *curnode;
- head = (BME_CycleNode*)h;
-
- if(head){
- len = 1;
- for(curnode = head->next; curnode != head; curnode=curnode->next){
- if(len == INT_MAX){ //check for infinite loop/corrupted cycle
- return -1;
- }
- len++;
- }
- }
- return len;
-}
-
-
-/**
- * BME_cycle_remove
- *
- * Removes a node from a cycle.
- *
- * Returns -
- * 1 for success, 0 for failure.
- */
-
-int BME_cycle_remove(void *h, void *remn)
-{
- int i, len;
- BME_CycleNode *head, *remnode, *curnode;
-
- head = (BME_CycleNode*)h;
- remnode = (BME_CycleNode*)remn;
- len = BME_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;
-}
-
-/**
- * BME_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 BME_cycle_validate(int len, void *h){
- int i;
- BME_CycleNode *curnode, *head;
- head = (BME_CycleNode*)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*/
-
-/**
- * BME_disk_nextedge
- *
- * Find the next edge in a disk cycle
- *
- * Returns -
- * Pointer to the next edge in the disk cycle for the vertex v.
- */
-
-BME_Edge *BME_disk_nextedge(BME_Edge *e, BME_Vert *v)
-{
- if(BME_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;
-}
-
-/**
- * BME_disk_getpointer
- *
- * Given an edge and one of its vertices, find the apporpriate CycleNode
- *
- * Returns -
- * Pointer to BME_CycleNode.
- */
-BME_CycleNode *BME_disk_getpointer(BME_Edge *e, BME_Vert *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;
-}
-
-/**
- * BME_disk_append_edge
- *
- * Appends edge to the end of a vertex disk cycle.
- *
- * Returns -
- * 1 for success, 0 for failure
- */
-
-int BME_disk_append_edge(BME_Edge *e, BME_Vert *v)
-{
-
- BME_CycleNode *base, *tail;
-
- 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;
- 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);
- tail = BME_disk_getpointer(e, v);
- BME_cycle_append(base, tail);
- return 1;
-}
-
-/**
- * BME_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 BME_disk_remove_edge(BME_Edge *e, BME_Vert *v)
-{
- BME_CycleNode *base, *remnode;
- BME_Edge *newbase;
- int len;
-
- base = BME_disk_getpointer(v->edge, v);
- remnode = BME_disk_getpointer(e, v);
-
- /*first deal with v->edge pointer...*/
- len = BME_cycle_length(base);
- if(len == 1) newbase = NULL;
- else if(v->edge == e) newbase = base->next-> data;
- else newbase = v->edge;
-
- /*remove and rebase*/
- BME_cycle_remove(base, remnode);
- v->edge = newbase;
-}
-
-/**
- * BME_disk_next_edgeflag
- *
- * Searches the disk cycle of v, starting with e, for the
- * next edge that has either eflag or tflag.
- *
- * BME_Edge pointer.
- */
-
-BME_Edge *BME_disk_next_edgeflag(BME_Edge *e, BME_Vert *v, int eflag, int tflag){
-
- /* BME_CycleNode *diskbase; */ /* UNUSED */
- BME_Edge *curedge;
- int /* len, */ /* UNUSED */ ok;
-
- if(eflag && tflag) return NULL;
-
- ok = BME_vert_in_edge(e,v);
- if(ok){
- /* diskbase = BME_disk_getpointer(e, v); */ /* UNUSED */
- /* len = BME_cycle_length(diskbase); */ /* UNUSED */
- curedge = BME_disk_nextedge(e,v);
- while(curedge != e){
- if(tflag){
- if(curedge->tflag1 == tflag) return curedge;
- }
- else if(eflag){
- if(curedge->eflag1 == eflag) return curedge;
- }
- curedge = BME_disk_nextedge(curedge, v);
- }
- }
- return NULL;
-}
-
-/**
- * BME_disk_count_edgeflag
- *
- * Counts number of edges in this verts disk cycle which have
- * either eflag or tflag (but not both!)
- *
- * Returns -
- * Integer.
- */
-
-int BME_disk_count_edgeflag(BME_Vert *v, int eflag, int tflag){
- BME_CycleNode *diskbase;
- BME_Edge *curedge;
- int i, len=0, count=0;
-
- if(v->edge){
- if(eflag && tflag) return 0; /*tflag and eflag are reserved for different functions!*/
- diskbase = BME_disk_getpointer(v->edge, v);
- len = BME_cycle_length(diskbase);
-
- for(i = 0, curedge=v->edge; i<len; i++){
- if(tflag){
- if(curedge->tflag1 == tflag) count++;
- }
- else if(eflag){
- if(curedge->eflag1 == eflag) count++;
- }
- curedge = BME_disk_nextedge(curedge, v);
- }
- }
- return count;
-}
-
-int BME_disk_hasedge(BME_Vert *v, BME_Edge *e){
- BME_CycleNode *diskbase;
- BME_Edge *curedge;
- int i, len=0;
-
- if(v->edge){
- diskbase = BME_disk_getpointer(v->edge,v);
- len = BME_cycle_length(diskbase);
-
- for(i = 0, curedge=v->edge; i<len; i++){
- if(curedge == e) return 1;
- else curedge=BME_disk_nextedge(curedge, v);
- }
- }
- return 0;
-}
-/*end disk cycle routines*/
-
-BME_Loop *BME_radial_nextloop(BME_Loop *l){
- return (BME_Loop*)(l->radial.next->data);
-}
-
-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));
-}
-
-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));
- if(len == 1) newbase = NULL;
- else if(e->loop == l) newbase = e->loop->radial.next->data;
- else newbase = e->loop;
-
- /*remove and rebase*/
- BME_cycle_remove(&(e->loop->radial), &(l->radial));
- e->loop = newbase;
-}
-
-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){
- if(curloop->f == f) return 1;
- }
- return 0;
-}
-
-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);
- for (i = 0, l=f->loopbase; i < len; i++, l=l->next) {
- if (l->v == v) return l;
- }
- return NULL;
-}
diff --git a/source/blender/blenkernel/intern/BME_tools.c b/source/blender/blenkernel/intern/BME_tools.c
deleted file mode 100644
index 44258f92024..00000000000
--- a/source/blender/blenkernel/intern/BME_tools.c
+++ /dev/null
@@ -1,1343 +0,0 @@
-/*
- * BME_tools.c jan 2007
- *
- * Functions for changing the topology of a mesh.
- *
- *
- * ***** 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): Geoffrey Bantle and Levi Schooley.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/BME_tools.c
- * \ingroup bke
- */
-
-
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_bmesh.h"
-
-/*split this all into a seperate bevel.c file in src*/
-
-/* ------- Bevel code starts here -------- */
-
-BME_TransData_Head *BME_init_transdata(int bufsize) {
- BME_TransData_Head *td;
-
- td = MEM_callocN(sizeof(BME_TransData_Head), "BMesh transdata header");
- td->gh = BLI_ghash_new(BLI_ghashutil_ptrhash,BLI_ghashutil_ptrcmp, "BME_init_transdata gh");
- td->ma = BLI_memarena_new(bufsize, "BME_TransData arena");
- 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, BME_Mesh *bm, BME_Vert *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) {
- copy_v3_v3(vtd->co, co);
- }
-
- if (org == NULL && is_new) {
- copy_v3_v3(vtd->org, v->co); /* default */
- }
- else if (org != NULL) {
- copy_v3_v3(vtd->org,org);
- }
-
- if (vec != NULL) {
- copy_v3_v3(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, BME_Vert *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_is_nonmanifold_vert(BME_Mesh *UNUSED(bm), BME_Vert *v) {
- BME_Edge *e, *oe;
- BME_Loop *l;
- int len, count, flag;
-
- if (v->edge == 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) {
- /* loose edge */
- return 1;
- }
-
- if (BME_cycle_length(&(e->loop->radial)) > 2) {
- /* edge shared by more than two faces */
- return 1;
- }
- }
-
- count = 1;
- flag = 1;
- e = NULL;
- oe = v->edge;
- l = oe->loop;
- 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) {
- /* we've hit the edge of an open mesh, reset once */
- flag = 0;
- count = 1;
- oe = e;
- e = NULL;
- l = oe->loop;
- }
- else if (l->radial.next->data == l) {
- /* break the loop */
- e = oe;
- }
- else {
- l = l->radial.next->data;
- }
- }
-
- if (count < len) {
- /* vert shared by multiple regions */
- return 1;
- }
-
- return 0;
-}
-
-/* a wrapper for BME_JFKE that [for now just] checks to
- * make sure loop directions are compatible */
-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;
- if (l1->v == l2->v) {
- BME_loop_reverse(bm, f2);
- }
-
- return BME_JFKE(bm, f1, f2, e);
-}
-
-/* a wrapper for BME_SFME that transfers element flags */
-static BME_Poly *BME_split_face(BME_Mesh *bm, BME_Poly *f, BME_Vert *v1, BME_Vert *v2, BME_Loop **nl, BME_Edge *example) {
- BME_Poly *nf;
- nf = BME_SFME(bm,f,v1,v2,nl);
- nf->flag = f->flag;
- /* if the edge was selected, select this face, too */
- if (example && (example->flag & SELECT)) f->flag |= ME_FACE_SEL;
- nf->h = f->h;
- nf->mat_nr = f->mat_nr;
- if (nl && example) {
- (*nl)->e->flag = example->flag;
- (*nl)->e->h = example->h;
- (*nl)->e->crease = example->crease;
- (*nl)->e->bweight = example->bweight;
- }
-
- return nf;
-}
-
-
-#if 0
-static void BME_data_interp_from_verts(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Vert *v, 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_bmesh_interp(&bm->vdata, src, w, NULL, 2, v->data);
- }
-}
-#endif
-
-
-static void BME_data_facevert_edgesplit(BME_Mesh *bm, BME_Vert *v1, BME_Vert *UNUSED(v2), BME_Vert *v, BME_Edge *e1, float fac){
- void *src[2];
- float w[2];
- BME_Loop *l=NULL, *v1loop = NULL, *vloop = NULL, *v2loop = NULL;
-
- w[0] = 1.0f - fac;
- w[1] = fac;
-
- if(!e1->loop) return;
- l = e1->loop;
- do{
- if(l->v == v1){
- v1loop = l;
- vloop = v1loop->next;
- v2loop = vloop->next;
- }else if(l->v == v){
- v1loop = l->next;
- vloop = l;
- v2loop = l->prev;
-
- }
-
- src[0] = v1loop->data;
- src[1] = v2loop->data;
-
- CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, vloop->data);
- l = l->radial.next->data;
- }while(l!=e1->loop);
-}
-
-
-/* a wrapper for BME_SEMV that transfers element flags */ /*add custom data interpolation in here!*/
-static BME_Vert *BME_split_edge(BME_Mesh *bm, BME_Vert *v, BME_Edge *e, BME_Edge **ne, float percent) {
- BME_Vert *nv, *v2;
- float len;
-
- v2 = BME_edge_getothervert(e,v);
- nv = BME_SEMV(bm,v,e,ne);
- if (nv == NULL) return NULL;
- VECSUB(nv->co,v2->co,v->co);
- len = len_v3(nv->co);
- VECADDFAC(nv->co,v->co,nv->co,len*percent);
- nv->flag = v->flag;
- nv->bweight = v->bweight;
- if (ne) {
- (*ne)->flag = e->flag;
- (*ne)->h = e->h;
- (*ne)->crease = e->crease;
- (*ne)->bweight = e->bweight;
- }
- /*v->nv->v2*/
- BME_data_facevert_edgesplit(bm,v2, v, nv, e, 0.75);
- return nv;
-}
-
-static void BME_collapse_vert(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv, float fac){
- void *src[2];
- float w[2];
- BME_Loop *l=NULL, *kvloop=NULL, *tvloop=NULL;
- BME_Vert *tv = BME_edge_getothervert(ke,kv);
-
- w[0] = 1.0f - fac;
- w[1] = fac;
-
- if(ke->loop){
- l = ke->loop;
- do{
- if(l->v == tv && l->next->v == kv){
- tvloop = l;
- kvloop = l->next;
-
- src[0] = kvloop->data;
- src[1] = tvloop->data;
- CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, kvloop->data);
- }
- l=l->radial.next->data;
- }while(l!=ke->loop);
- }
- BME_JEKV(bm,ke,kv);
-}
-
-
-
-static int BME_bevel_is_split_vert(BME_Loop *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, BME_Vert *v1, BME_Vert *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)) {
- sub_v3_v3v3(vec, v2->co, v1->co);
- if (len_v3(vec) < 0.000001f) {
- zero_v3(vec);
- }
- return 0;
- }
- else {
- sub_v3_v3v3(vec,vtd2->org,vtd1->org);
- if (len_v3(vec) < 0.000001f) {
- zero_v3(vec);
- }
- 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 *UNUSED(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 (fabsf(c1) < 0.000001f || fabsf(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 BME_Vert *BME_bevel_split_edge(BME_Mesh *bm, BME_Vert *v, BME_Vert *v1, BME_Loop *l, float *up_vec, float value, BME_TransData_Head *td) {
- BME_TransData *vtd, *vtd1 /* , *vtd2 */ /* UNUSED */;
- BME_Vert *sv, *v2, *v3 /* , *ov */ /* UNUSED */;
- BME_Loop *lv1, *lv2;
- BME_Edge *ne, *e1, *e2;
- float maxfactor, scale, len, dis, vec1[3], vec2[3], t_up_vec[3];
- int is_edge, forward /* , is_split_vert */ /* UNUSED */;
-
- 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; */ /* UNUSED */
- if (v->edge == 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);
- if (e1 == e2) {
- //printf("You need at least two edges to use BME_bevel_split_edge()\n");
- return NULL;
- }
- v2 = BME_edge_getothervert(e1, v);
- v3 = BME_edge_getothervert(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 = BME_edge_getothervert(e1,v); */ /* UNUSED */
- sv = BME_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; */ /* UNUSED */
- sv = v1;
- if (forward) v1 = l->next->next->v;
- else v1 = l->prev->v;
- }
- else {
- /* is_split_vert = 0; */ /* UNUSED */
- /* ov = BME_edge_getothervert(l->e,v); */ /* UNUSED */
- sv = BME_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); */ /* UNUSED */
-
- 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;
- }
- madd_v3_v3v3fl(sv->co, v->co, vec1, dis);
- sub_v3_v3v3(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(BME_Vert *v1, BME_Vert *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 {
- copy_v3_v3(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 {
- copy_v3_v3(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 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);
-
- /* 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) {
- BME_JEKV(bm,v->edge,v);
- }
-
- return v1;
-}
-
-static BME_Loop *BME_bevel_edge(BME_Mesh *bm, BME_Loop *l, float value, int UNUSED(options), float *up_vec, BME_TransData_Head *td) {
- BME_Vert *v1, *v2, *kv;
- BME_Loop *kl=NULL, *nl;
- BME_Edge *e;
- BME_Poly *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->data;
- 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) {
- 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_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_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->data;
- 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) {
- 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_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_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) {
- BME_split_face(bm,f,v2,v1,&l,e);
- l->e->tflag1 = BME_BEVEL_BEVEL;
- l = l->radial.next->data;
- }
-
- if (l->f != f){
- //printf("Whoops! You got something out of order in BME_bevel_edge()!\n");
- }
-
- return l;
-}
-
-static BME_Loop *BME_bevel_vert(BME_Mesh *bm, BME_Loop *l, float value, int UNUSED(options), float *up_vec, BME_TransData_Head *td) {
- BME_Vert *v1, *v2;
- /* BME_Poly *f; */ /* UNUSED */
-
- /* 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 = */ /* UNUSED */ BME_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 BME_Poly pointer to the resulting inner face.
-*/
-static BME_Poly *BME_bevel_poly(BME_Mesh *bm, BME_Poly *f, float value, int options, BME_TransData_Head *td) {
- BME_Loop *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);
- add_v3_v3(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 {
- copy_v3_v3(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 {
- copy_v3_v3(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, BME_Mesh *bm, BME_Vert *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 float BME_bevel_get_angle(BME_Mesh *UNUSED(bm), BME_Edge *e, BME_Vert *v) {
- BME_Vert *v1, *v2;
- BME_Loop *l1, *l2;
- float vec1[3], vec2[3], vec3[3], vec4[3];
-
- l1 = e->loop;
- l2 = e->loop->radial.next->data;
- if (l1->v == v) {
- v1 = l1->prev->v;
- v2 = l1->next->v;
- }
- else {
- v1 = l1->next->next->v;
- v2 = l1->v;
- }
- VECSUB(vec1,v1->co,v->co);
- VECSUB(vec2,v2->co,v->co);
- cross_v3_v3v3(vec3,vec1,vec2);
-
- l1 = l2;
- if (l1->v == v) {
- v1 = l1->prev->v;
- v2 = l1->next->v;
- }
- else {
- v1 = l1->next->next->v;
- v2 = l1->v;
- }
- VECSUB(vec1,v1->co,v->co);
- VECSUB(vec2,v2->co,v->co);
- cross_v3_v3v3(vec4,vec2,vec1);
-
- normalize_v3(vec3);
- normalize_v3(vec4);
-
- return dot_v3v3(vec3,vec4);
-}
-static int BME_face_sharededges(BME_Poly *f1, BME_Poly *f2){
- BME_Loop *l;
- int count = 0;
-
- l = f1->loopbase;
- do{
- if(BME_radial_find_face(l->e,f2)) count++;
- l = l->next;
- }while(l != f1->loopbase);
-
- return count;
-}
-/**
- * BME_bevel_initialize
- *
- * Prepare the mesh for beveling:
- *
- * Sets the tflag1's of the mesh elements based on the options passed.
- *
- * Returns -
- * A BME_Mesh pointer to the BMesh passed as a parameter.
-*/
-static BME_Mesh *BME_bevel_initialize(BME_Mesh *bm, int options, int UNUSED(defgrp_index), float angle, BME_TransData_Head *td) {
- BME_Vert *v;
- BME_Edge *e;
- BME_Poly *f;
- /* BME_TransData *vtd; */ /* UNUSED */
- /* MDeformVert *dvert; */ /* UNUSED */
- /* MDeformWeight *dw; */ /* UNUSED */
- int len;
- float weight, threshold;
-
- /* vert pass */
- for (v=bm->verts.first; v; v=v->next) {
- /* dvert = NULL; */ /* UNUSED */
- /* dw = NULL; */ /* UNUSED */
- v->tflag1 = BME_BEVEL_ORIG;
- /* originally coded, a vertex gets tagged with BME_BEVEL_BEVEL in this pass if
- * the vert is manifold (or is shared by only two edges - wire bevel)
- * BME_BEVEL_SELECT is passed and the vert has v->flag&SELECT or
- * BME_BEVEL_VWEIGHT is passed, and the vert has a defgrp and weight
- * BME_BEVEL_ANGLE is not passed
- * BME_BEVEL_EWEIGHT is not passed
- */
- /* originally coded, a vertex gets tagged with BME_BEVEL_NONMAN in this pass if
- * the vert is loose, shared by multiple regions, or is shared by wire edges
- * note: verts belonging to edges of open meshes are not tagged with BME_BEVEL_NONMAN
- */
- /* originally coded, a vertex gets a transform weight set in this pass if
- * BME_BEVEL_VWEIGHT is passed, and the vert has a defgrp and weight
- */
-
- /* get disk cycle length */
- if (v->edge == NULL) {
- len = 0;
- }
- else {
- len = BME_cycle_length(BME_disk_getpointer(v->edge,v));
- /* we'll assign a default transform data to every vert (except the loose ones) */
- /* vtd = */ /* UNUSED */ BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 0, -1, -1, NULL);
- }
-
- /* check for non-manifold vert */
- if (BME_is_nonmanifold_vert(bm,v)) {
- v->tflag1 |= BME_BEVEL_NONMAN;
- }
-
- /* BME_BEVEL_BEVEL tests */
- if ((v->tflag1 & BME_BEVEL_NONMAN) == 0 || len == 2) { /* either manifold vert, or wire vert */
- if (((options & BME_BEVEL_SELECT) && (v->flag & SELECT))
- || ((options & BME_BEVEL_WEIGHT) && (options & BME_BEVEL_VERT)) /* use weights for verts */
- || ((options & BME_BEVEL_ANGLE) == 0
- && (options & BME_BEVEL_SELECT) == 0
- && (options & BME_BEVEL_WEIGHT) == 0))
- {
- if (options & BME_BEVEL_WEIGHT) {
- /* do vert weight stuff */
- //~ dvert = CustomData_em_get(&bm->vdata,v->data,CD_MDEFORMVERT);
- //~ if (!dvert) continue;
- //~ for (i = 0; i < dvert->totweight; ++i) {
- //~ if(dvert->dw[i].def_nr == defgrp_index) {
- //~ dw = &dvert->dw[i];
- //~ break;
- //~ }
- //~ }
- //~ if (!dw || dw->weight == 0.0) continue;
- if (v->bweight == 0.0) continue;
- /* vtd = */ /* UNUSED */ BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 1.0, v->bweight, -1, NULL);
- v->tflag1 |= BME_BEVEL_BEVEL;
- }
- else {
- /* vtd = */ /* UNUSED */ BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 1.0, 1.0, -1, NULL);
- v->tflag1 |= BME_BEVEL_BEVEL;
- }
- }
- }
- }
-
- /* edge pass */
- threshold = (float)cos((angle + 0.001) * M_PI / 180.0);
- for (e=bm->edges.first; e; e=e->next) {
- e->tflag1 = BME_BEVEL_ORIG;
- weight = 0.0;
- /* originally coded, an edge gets tagged with BME_BEVEL_BEVEL in this pass if
- * BME_BEVEL_VERT is not set
- * the edge is manifold (shared by exactly two faces)
- * BME_BEVEL_SELECT is passed and the edge has e->flag&SELECT or
- * BME_BEVEL_EWEIGHT is passed, and the edge has the crease set or
- * BME_BEVEL_ANGLE is passed, and the edge is sharp enough
- * BME_BEVEL_VWEIGHT is passed, and both verts are set for bevel
- */
- /* originally coded, a vertex gets tagged with BME_BEVEL_BEVEL in this pass if
- * the vert belongs to the edge
- * the vert is not tagged with BME_BEVEL_NONMAN
- * the edge is eligible for bevel (even if BME_BEVEL_VERT is set, or the edge is shared by less than 2 faces)
- */
- /* originally coded, a vertex gets a transform weight set in this pass if
- * the vert belongs to the edge
- * the edge has a weight
- */
- /* note: edge weights are cumulative at the verts,
- * i.e. the vert's weight is the average of the weights of its weighted edges
- */
-
- if (e->loop == NULL) {
- len = 0;
- e->v1->tflag1 |= BME_BEVEL_NONMAN;
- e->v2->tflag1 |= BME_BEVEL_NONMAN;
- }
- else {
- len = BME_cycle_length(&(e->loop->radial));
- }
-
- if (len > 2) {
- /* non-manifold edge of the worst kind */
- continue;
- }
-
- if ((options & BME_BEVEL_SELECT) && (e->flag & SELECT)) {
- weight = 1.0;
- /* stupid editmode doesn't always flush selections, or something */
- e->v1->flag |= SELECT;
- e->v2->flag |= SELECT;
- }
- else if ((options & BME_BEVEL_WEIGHT) && (options & BME_BEVEL_VERT) == 0) {
- weight = e->bweight;
- }
- else if (options & BME_BEVEL_ANGLE) {
- if ((e->v1->tflag1 & BME_BEVEL_NONMAN) == 0 && BME_bevel_get_angle(bm,e,e->v1) < threshold) {
- e->tflag1 |= BME_BEVEL_BEVEL;
- e->v1->tflag1 |= BME_BEVEL_BEVEL;
- BME_bevel_add_vweight(td, bm, e->v1, 1.0, 1.0, options);
- }
- else {
- BME_bevel_add_vweight(td, bm, e->v1, 0.0, 1.0, options);
- }
- if ((e->v2->tflag1 & BME_BEVEL_NONMAN) == 0 && BME_bevel_get_angle(bm,e,e->v2) < threshold) {
- e->tflag1 |= BME_BEVEL_BEVEL;
- e->v2->tflag1 |= BME_BEVEL_BEVEL;
- BME_bevel_add_vweight(td, bm, e->v2, 1.0, 1.0, options);
- }
- else {
- BME_bevel_add_vweight(td, bm, e->v2, 0.0, 1.0, options);
- }
- }
- //~ else if ((options & BME_BEVEL_VWEIGHT) && (options & BME_BEVEL_VERT) == 0) {
- //~ if ((e->v1->tflag1 & BME_BEVEL_BEVEL) && (e->v2->tflag1 & BME_BEVEL_BEVEL)) {
- //~ e->tflag1 |= BME_BEVEL_BEVEL;
- //~ }
- //~ }
- else if ((options & BME_BEVEL_SELECT) == 0
- && (options & BME_BEVEL_VERT) == 0)
- {
- weight = 1.0;
- }
-
- if (weight > 0.0) {
- e->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);
- }
-
- if (len != 2 || options & BME_BEVEL_VERT) {
- e->tflag1 &= ~BME_BEVEL_BEVEL;
- }
- }
-
- /* face pass */
- for (f=bm->polys.first; f; f=f->next) f->tflag1 = BME_BEVEL_ORIG;
-
- /*clean up edges with 2 faces that share more than one edge*/
- 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);
- if(count > 1){
- e->tflag1 &= ~BME_BEVEL_BEVEL;
- }
- }
- }
-
- return bm;
-
-}
-
-/* tags all elements as originals */
-static BME_Mesh *BME_bevel_reinitialize(BME_Mesh *bm) {
- BME_Vert *v;
- BME_Edge *e;
- BME_Poly *f;
-
- for (v = bm->verts.first; v; v=v->next) {
- v->tflag1 |= BME_BEVEL_ORIG;
- }
-
- for (e=bm->edges.first; e; e=e->next) {
- e->tflag1 |= BME_BEVEL_ORIG;
- }
-
- for (f=bm->polys.first; f; f=f->next) {
- 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 BME_Mesh pointer to the BMesh passed as a parameter.
-*/
-
-static void bmesh_dissolve_disk(BME_Mesh *bm, BME_Vert *v){
- BME_Poly *f;
- BME_Edge *e;
- int done, len;
-
- if(v->edge){
- done = 0;
- while(!done){
- done = 1;
- e = v->edge; /*loop the edge looking for a edge to dissolve*/
- do{
- f = NULL;
- len = BME_cycle_length(&(e->loop->radial));
- if(len == 2){
- f = BME_JFKE_safe(bm,e->loop->f, ((BME_Loop*)(e->loop->radial.next->data))->f, e);
- }
- if(f){
- done = 0;
- break;
- }
- e = BME_disk_nextedge(e,v);
- }while(e != v->edge);
- }
- BME_collapse_vert(bm, v->edge, v, 1.0);
- //BME_JEKV(bm,v->edge,v);
- }
-}
-static BME_Mesh *BME_bevel_mesh(BME_Mesh *bm, float value, int res, int options, int UNUSED(defgrp_index), BME_TransData_Head *td) {
- BME_Vert *v, *nv;
- BME_Edge *e, *oe;
- BME_Loop *l, *l2;
- BME_Poly *f;
- unsigned int i, len;
-
- for (f=bm->polys.first; f; f=f->next) {
- if(f->tflag1 & BME_BEVEL_ORIG) {
- BME_bevel_poly(bm,f,value,options,td);
- }
- }
-
- /* here we will loop through all the verts to clean up the left over geometry */
- /* crazy idea. when res == 0, don't remove the original geometry */
- for (v = bm->verts.first; v; /* we may kill v, so increment in-loop */) {
- nv = v->next;
- if ((v->tflag1 & BME_BEVEL_NONMAN) && (v->tflag1 & BME_BEVEL_BEVEL) && (v->tflag1 & BME_BEVEL_ORIG)) {
- v = BME_bevel_wire(bm, v, value, res, options, td);
- }
- 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;
- e = BME_disk_nextedge(oe,v);
- while ((e->tflag1 & BME_BEVEL_BEVEL) && (e->tflag1 & BME_BEVEL_ORIG)) {
- e = BME_disk_nextedge(e,v);
- if (e == oe) {
- //printf("Something's wrong! We can't remove every edge here!\n");
- break;
- }
- }
- /* look for original edges, and remove them */
- oe = e;
- 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);
- if (!f){
- //printf("Non-manifold geometry not getting tagged right?\n");
- }
- }
-
- /*need to do double check *before* you bevel to make sure that manifold edges are for two faces that share only *one* edge to make sure it doesnt hang here!*/
-
-
- /* 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;
- 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 */
- if (l->f->len > 3) {
- BME_split_face(bm,l->f,l->next->v,l->prev->v,&l,l->e); /* clip this corner off */
- if (len > 2) {
- l->e->tflag1 |= BME_BEVEL_BEVEL;
- }
- }
- if (l2->f->len > 3) {
- BME_split_face(bm,l2->f,l2->next->v,l2->prev->v,&l,l2->e); /* clip this corner off */
- if (len > 2) {
- l->e->tflag1 |= BME_BEVEL_BEVEL;
- }
- }
- }
- bmesh_dissolve_disk(bm, v);
- }
- v = nv;
- }
-
- return bm;
-}
-
-static BME_Mesh *BME_tesselate(BME_Mesh *bm) {
- BME_Loop *l, *nextloop;
- BME_Poly *f;
-
- for (f=bm->polys.first; f; f=f->next) {
- l = f->loopbase;
- while (l->f->len > 4) {
- nextloop = l->next->next->next;
- /* make a quad */
- BME_split_face(bm,l->f,l->v,nextloop->v,NULL,l->e);
- l = nextloop;
- }
- }
- return bm;
-}
-
-
-/*Main bevel function:
- Should be only one exported
-
-*/
-
-/* options that can be passed:
- * BME_BEVEL_VWEIGHT <---- v, Look at vertex weights; use defgrp_index if option is present
- * BME_BEVEL_SELECT <---- v,e, check selection for verts and edges
- * BME_BEVEL_ANGLE <---- v,e, don't bevel-tag verts - tag verts per edge
- * BME_BEVEL_VERT <---- e, don't tag edges
- * BME_BEVEL_EWEIGHT <---- e, use crease flag for now
- * BME_BEVEL_PERCENT <---- Will need to think about this one; will probably need to incorporate into actual bevel routine
- * BME_BEVEL_RADIUS <---- Will need to think about this one; will probably need to incorporate into actual bevel routine
- * All weights/limits are stored per-vertex
- */
-BME_Mesh *BME_bevel(BME_Mesh *bm, float value, int res, int options, int defgrp_index, float angle, BME_TransData_Head **rtd) {
- BME_Vert *v;
- BME_TransData_Head *td;
- BME_TransData *vtd;
- int i;
- float fac=1, d;
-
- td = BME_init_transdata(BLI_MEMARENA_STD_BUFSIZE);
-
- BME_bevel_initialize(bm, options, defgrp_index, angle, td);
-
- /* 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;
- /* crazy idea. if res == 0, don't remove original geometry */
- for (i=0; i<res || (res==0 && i==0); i++) {
- if (i != 0) BME_bevel_reinitialize(bm);
- BME_model_begin(bm);
- BME_bevel_mesh(bm,d,res,options,defgrp_index,td);
- BME_model_end(bm);
- if (i==0) d /= 3; else d /= 2;
- }
-
- BME_tesselate(bm);
-
- if (rtd) {
- *rtd = td;
- return bm;
- }
-
- /* transform pass */
- for (v = bm->verts.first; v; v=v->next) {
- if ( (vtd = BME_get_transdata(td, v)) ) {
- if (vtd->max && (*vtd->max > 0 && value > *vtd->max)) {
- d = *vtd->max;
- }
- else {
- d = value;
- }
- madd_v3_v3v3fl(v->co,vtd->org,vtd->vec,vtd->factor*d);
- }
- v->tflag1 = 0;
- }
-
- BME_free_transdata(td);
- return bm;
-}
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 27aeeb95903..573edb78687 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -31,7 +31,7 @@
#include <string.h>
-
+#include "limits.h"
#include "MEM_guardedalloc.h"
@@ -46,6 +46,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"
#include "BLI_linklist.h"
@@ -60,6 +61,9 @@
#include "BKE_texture.h"
#include "BKE_multires.h"
#include "BKE_armature.h"
+#include "BKE_particle.h"
+#include "BKE_tessmesh.h"
+#include "BKE_bvhutils.h"
#include "BKE_deform.h"
#ifdef WITH_GAMEENGINE
@@ -78,6 +82,9 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */
+static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *ob);
+static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid);
+
///////////////////////////////////
///////////////////////////////////
@@ -109,20 +116,48 @@ static MEdge *dm_getEdgeArray(DerivedMesh *dm)
return medge;
}
-static MFace *dm_getFaceArray(DerivedMesh *dm)
+static MFace *dm_getTessFaceArray(DerivedMesh *dm)
{
MFace *mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
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;
}
+static MLoop *dm_getLoopArray(DerivedMesh *dm)
+{
+ MLoop *mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+
+ if (!mloop) {
+ mloop = CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL,
+ dm->getNumLoops(dm));
+ CustomData_set_layer_flag(&dm->loopData, CD_MLOOP, CD_FLAG_TEMPORARY);
+ dm->copyLoopArray(dm, mloop);
+ }
+
+ return mloop;
+}
+
+static MPoly *dm_getPolyArray(DerivedMesh *dm)
+{
+ MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
+
+ if (!mpoly) {
+ mpoly = CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL,
+ dm->getNumPolys(dm));
+ CustomData_set_layer_flag(&dm->polyData, CD_MPOLY, CD_FLAG_TEMPORARY);
+ dm->copyPolyArray(dm, mpoly);
+ }
+
+ return mpoly;
+}
+
static MVert *dm_dupVertArray(DerivedMesh *dm)
{
MVert *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumVerts(dm),
@@ -145,41 +180,98 @@ 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;
}
+static MLoop *dm_dupLoopArray(DerivedMesh *dm)
+{
+ MLoop *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumLoops(dm),
+ "dm_dupLoopArray tmp");
+
+ if(tmp) dm->copyLoopArray(dm, tmp);
+
+ return tmp;
+}
+
+static MPoly *dm_dupPolyArray(DerivedMesh *dm)
+{
+ MPoly *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumPolys(dm),
+ "dm_dupPolyArray tmp");
+
+ if(tmp) dm->copyPolyArray(dm, tmp);
+
+ return tmp;
+}
+
+static CustomData *dm_getVertCData(DerivedMesh *dm)
+{
+ return &dm->vertData;
+}
+
+static CustomData *dm_getEdgeCData(DerivedMesh *dm)
+{
+ return &dm->edgeData;
+}
+
+static CustomData *dm_getTessFaceCData(DerivedMesh *dm)
+{
+ return &dm->faceData;
+}
+
+static CustomData *dm_getLoopCData(DerivedMesh *dm)
+{
+ return &dm->loopData;
+}
+
+static 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_getTessFaceArray;
+ dm->getLoopArray = dm_getLoopArray;
+ dm->getPolyArray = dm_getPolyArray;
dm->dupVertArray = dm_dupVertArray;
dm->dupEdgeArray = dm_dupEdgeArray;
- dm->dupFaceArray = dm_dupFaceArray;
+ dm->dupTessFaceArray = dm_dupFaceArray;
+ dm->dupLoopArray = dm_dupLoopArray;
+ dm->dupPolyArray = dm_dupPolyArray;
+
+ dm->getVertDataLayout = dm_getVertCData;
+ dm->getEdgeDataLayout = dm_getEdgeCData;
+ dm->getTessFaceDataLayout = dm_getTessFaceCData;
+ dm->getLoopDataLayout = dm_getLoopCData;
+ dm->getPolyDataLayout = dm_getPolyCData;
dm->getVertData = DM_get_vert_data;
dm->getEdgeData = DM_get_edge_data;
- dm->getFaceData = DM_get_face_data;
+ dm->getTessFaceData = DM_get_tessface_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 numTessFaces, int numLoops, int numPolys)
{
dm->type = type;
dm->numVertData = numVerts;
dm->numEdgeData = numEdges;
- dm->numFaceData = numFaces;
+ dm->numTessFaceData = numTessFaces;
+ dm->numLoopData = numLoops;
+ dm->numPolyData = numPolys;
DM_init_funcs(dm);
@@ -188,19 +280,26 @@ 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 numTessFaces,
+ int numLoops, int numPolys)
{
CustomData_copy(&source->vertData, &dm->vertData, CD_MASK_DERIVEDMESH,
CD_CALLOC, numVerts);
CustomData_copy(&source->edgeData, &dm->edgeData, CD_MASK_DERIVEDMESH,
CD_CALLOC, numEdges);
CustomData_copy(&source->faceData, &dm->faceData, CD_MASK_DERIVEDMESH,
- CD_CALLOC, numFaces);
+ CD_CALLOC, numTessFaces);
+ 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->numTessFaceData = numTessFaces;
+ dm->numLoopData = numLoops;
+ dm->numPolyData = numPolys;
DM_init_funcs(dm);
@@ -214,63 +313,152 @@ int DM_release(DerivedMesh *dm)
GPU_drawobject_free( dm );
CustomData_free(&dm->vertData, dm->numVertData);
CustomData_free(&dm->edgeData, dm->numEdgeData);
- CustomData_free(&dm->faceData, dm->numFaceData);
+ CustomData_free(&dm->faceData, dm->numTessFaceData);
+ CustomData_free(&dm->loopData, dm->numLoopData);
+ CustomData_free(&dm->polyData, dm->numPolyData);
return 1;
}
else {
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->faceData, dm->numTessFaceData);
+ CustomData_free_temporary(&dm->loopData, dm->numLoopData);
+ CustomData_free_temporary(&dm->polyData, dm->numPolyData);
return 0;
}
}
-void DM_to_mesh(DerivedMesh *dm, Mesh *me)
+void DM_DupPolys(DerivedMesh *source, DerivedMesh *target)
+{
+ CustomData_free(&target->loopData, source->numLoopData);
+ CustomData_free(&target->polyData, source->numPolyData);
+
+ CustomData_copy(&source->loopData, &target->loopData, CD_MASK_DERIVEDMESH, CD_DUPLICATE, source->numLoopData);
+ CustomData_copy(&source->polyData, &target->polyData, CD_MASK_DERIVEDMESH, CD_DUPLICATE, source->numPolyData);
+
+ target->numLoopData = source->numLoopData;
+ target->numPolyData = source->numPolyData;
+
+ if (!CustomData_has_layer(&target->polyData, CD_MPOLY)) {
+ MPoly *mpoly;
+ MLoop *mloop;
+
+ mloop = source->dupLoopArray(source);
+ mpoly = source->dupPolyArray(source);
+ CustomData_add_layer(&target->loopData, CD_MLOOP, CD_ASSIGN, mloop, source->numLoopData);
+ CustomData_add_layer(&target->polyData, CD_MPOLY, CD_ASSIGN, mpoly, source->numPolyData);
+ }
+}
+
+/* note: until all modifiers can take MPoly's as input,
+ * use this at the start of modifiers */
+void DM_ensure_tessface(DerivedMesh *dm)
+{
+ const int numTessFaces = dm->getNumTessFaces(dm);
+ const int numPolys = dm->getNumPolys(dm);
+
+ if ( (numTessFaces == 0) && (numPolys != 0)) {
+ dm->recalcTesselation(dm);
+
+ if (dm->getNumTessFaces(dm) != 0) {
+ /* printf("info %s: polys -> ngons calculated\n", __func__); */
+ }
+ else {
+ printf("warning %s: could not create tessfaces from %d polygons, dm->type=%d\n",
+ __func__, numPolys, dm->type);
+ }
+ }
+}
+
+void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob)
{
/* dm might depend on me, so we need to do everything with a local copy */
Mesh tmp = *me;
- int totvert, totedge, totface;
-
+ int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
+ int did_shapekeys=0;
+
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);
+ totloop = tmp.totloop = dm->getNumLoops(dm);
+ totpoly = tmp.totpoly = dm->getNumPolys(dm);
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);
+
+ if (CustomData_has_layer(&dm->vertData, CD_SHAPEKEY)) {
+ KeyBlock *kb;
+ int uid;
+
+ if (ob) {
+ kb = BLI_findlink(&me->key->block, ob->shapenr-1);
+ if (kb) {
+ uid = kb->uid;
+ }
+ else {
+ printf("%s: error - could not find active shapekey %d!\n",
+ __func__, ob->shapenr-1);
+ uid = INT_MAX;
+ }
+ }
+ else {
+ /*if no object, set to INT_MAX so we don't mess up any shapekey layers*/
+ uid = INT_MAX;
+ }
+
+ shapekey_layers_to_keyblocks(dm, me, uid);
+ did_shapekeys = 1;
+ }
+
/* not all DerivedMeshes store their verts/edges/faces in CustomData, so
we set them here in case they are missing */
if(!CustomData_has_layer(&tmp.vdata, CD_MVERT))
CustomData_add_layer(&tmp.vdata, CD_MVERT, CD_ASSIGN, dm->dupVertArray(dm), totvert);
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);
+ if(!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) {
+ tmp.mloop = dm->dupLoopArray(dm);
+ tmp.mpoly = dm->dupPolyArray(dm);
+
+ CustomData_add_layer(&tmp.ldata, CD_MLOOP, CD_ASSIGN, tmp.mloop, tmp.totloop);
+ CustomData_add_layer(&tmp.pdata, CD_MPOLY, CD_ASSIGN, tmp.mpoly, tmp.totpoly);
+ }
/* object had got displacement layer, should copy this layer to save sculpted data */
/* NOTE: maybe some other layers should be copied? nazgul */
- if(CustomData_has_layer(&me->fdata, CD_MDISPS)) {
- if (totface == me->totface) {
- MDisps *mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
- CustomData_add_layer(&tmp.fdata, CD_MDISPS, CD_DUPLICATE, mdisps, totface);
+ if(CustomData_has_layer(&me->ldata, CD_MDISPS)) {
+ if (totloop == me->totloop) {
+ MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
+ CustomData_add_layer(&tmp.ldata, CD_MDISPS, CD_DUPLICATE, mdisps, totloop);
}
}
- mesh_update_customdata_pointers(&tmp);
+ /* yes, must be before _and_ after tesselate */
+ mesh_update_customdata_pointers(&tmp, TRUE);
+
+ BKE_mesh_tessface_calc(&tmp);
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
CustomData_free(&me->fdata, me->totface);
-
- /* if the number of verts has changed, remove invalid data */
- if(tmp.totvert != me->totvert) {
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
+
+ /* ok, this should now use new CD shapekey data,
+ which shouuld be fed through the modifier
+ stack*/
+ if(tmp.totvert != me->totvert && !did_shapekeys && me->key) {
+ printf("YEEK! this should be recoded! Shape key loss!!!\n");
if(tmp.key) tmp.key->id.us--;
tmp.key = NULL;
}
@@ -315,9 +503,19 @@ 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->numTessFaceData);
+}
+
+void DM_add_loop_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
{
- CustomData_add_layer(&dm->faceData, type, alloctype, layer, dm->numFaceData);
+ CustomData_add_layer(&dm->loopData, type, alloctype, layer, dm->numLoopData);
+}
+
+void DM_add_poly_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)
@@ -330,7 +528,7 @@ void *DM_get_edge_data(DerivedMesh *dm, int index, int type)
return CustomData_get(&dm->edgeData, index, type);
}
-void *DM_get_face_data(DerivedMesh *dm, int index, int type)
+void *DM_get_tessface_data(DerivedMesh *dm, int index, int type)
{
return CustomData_get(&dm->faceData, index, type);
}
@@ -351,14 +549,24 @@ 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);
+ if (type == CD_MFACE)
+ return dm->getTessFaceArray(dm);
return CustomData_get_layer(&dm->faceData, type);
}
+void *DM_get_poly_data_layer(DerivedMesh *dm, int type)
+{
+ return CustomData_get_layer(&dm->polyData, type);
+}
+
+void *DM_get_loop_data_layer(DerivedMesh *dm, int type)
+{
+ return CustomData_get_layer(&dm->loopData, type);
+}
+
void DM_set_vert_data(DerivedMesh *dm, int index, int type, void *data)
{
CustomData_set(&dm->vertData, index, type, data);
@@ -369,7 +577,7 @@ void DM_set_edge_data(DerivedMesh *dm, int index, int type, void *data)
CustomData_set(&dm->edgeData, index, type, data);
}
-void DM_set_face_data(DerivedMesh *dm, int index, int type, void *data)
+void DM_set_tessface_data(DerivedMesh *dm, int index, int type, void *data)
{
CustomData_set(&dm->faceData, index, type, data);
}
@@ -388,13 +596,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_poly_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);
@@ -405,11 +627,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_poly_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)
@@ -427,7 +659,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)
@@ -436,13 +668,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_poly_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);
@@ -458,17 +705,25 @@ DerivedMesh *mesh_create_derived(Mesh *me, Object *ob, float (*vertCos)[3])
return dm;
}
-DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob, ModifierData *md)
+/***/
+
+DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob,
+ ModifierData *md, int build_shapekey_layers)
{
Mesh *me = ob->data;
ModifierTypeInfo *mti = modifierType_getInfo(md->type);
DerivedMesh *dm;
+ KeyBlock *kb;
md->scene= scene;
if (!(md->mode&eModifierMode_Realtime)) return NULL;
if (mti->isDisabled && mti->isDisabled(md, 0)) return NULL;
-
+
+ if (build_shapekey_layers && me->key && (kb = BLI_findlink(&me->key->block, ob->shapenr-1))) {
+ key_to_mesh(kb, me);
+ }
+
if (mti->type==eModifierTypeType_OnlyDeform) {
int numVerts;
float (*deformedVerts)[3] = mesh_getVertexCos(me, &numVerts);
@@ -476,9 +731,16 @@ DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob, Modifier
mti->deformVerts(md, ob, NULL, deformedVerts, numVerts, 0, 0);
dm = mesh_create_derived(me, ob, deformedVerts);
+ if (build_shapekey_layers)
+ add_shapekey_layers(dm, me, ob);
+
MEM_freeN(deformedVerts);
} else {
DerivedMesh *tdm = mesh_create_derived(me, ob, NULL);
+
+ if (build_shapekey_layers)
+ add_shapekey_layers(tdm, me, ob);
+
dm = mti->applyModifier(md, ob, tdm, 0, 0);
if(tdm != dm) tdm->release(tdm);
@@ -487,22 +749,22 @@ 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 = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for (a=0; eve; eve=BM_iter_step(&iter), a+=3) {
copy_v3_v3(orco+a, eve->co);
}
@@ -510,8 +772,7 @@ static float *get_editmesh_orco_verts(EditMesh *em)
}
/* 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;
@@ -520,7 +781,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);
}
@@ -541,13 +802,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, FALSE, FALSE);
else dm= CDDM_from_mesh(me, ob);
orco= get_orco_coords_dm(ob, em, layer, &free);
@@ -562,7 +823,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;
@@ -775,19 +1037,35 @@ void DM_update_weight_mcol(Object *ob, DerivedMesh *dm, int const draw_flag,
{
ColorBand *coba= stored_cb; /* warning, not a local var */
- MFace *mf = dm->getFaceArray(dm);
- int numFaces = dm->getNumFaces(dm);
- int numVerts = dm->getNumVerts(dm);
unsigned char *wtcol_v;
- unsigned char *wtcol_f = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL);
- int i;
+#if 0 /* See coment below. */
+ unsigned char *wtcol_f = dm->getTessFaceDataArray(dm, CD_WEIGHT_MCOL);
+#endif
+ unsigned char(*wtcol_l)[4] = CustomData_get_layer(dm->getLoopDataLayout(dm), CD_WEIGHT_MLOOPCOL);
+#if 0 /* See coment below. */
+ MFace *mf = dm->getTessFaceArray(dm);
+#endif
+ MLoop *mloop = dm->getLoopArray(dm), *ml;
+ MPoly *mp = dm->getPolyArray(dm);
+ int numFaces = dm->getNumTessFaces(dm);
+ int numVerts = dm->getNumVerts(dm);
+ int totloop;
+ int i, j;
+#if 0 /* See comment below */
/* If no CD_WEIGHT_MCOL existed yet, add a new one! */
if (!wtcol_f)
wtcol_f = CustomData_add_layer(&dm->faceData, CD_WEIGHT_MCOL, CD_CALLOC, NULL, numFaces);
if (wtcol_f) {
unsigned char *wtcol_f_step = wtcol_f;
+# else
+ /* XXX We have to create a CD_WEIGHT_MCOL, else it might sigsev (after a SubSurf mod, eg)... */
+ if(!dm->getTessFaceDataArray(dm, CD_WEIGHT_MCOL))
+ CustomData_add_layer(&dm->faceData, CD_WEIGHT_MCOL, CD_CALLOC, NULL, numFaces);
+
+ {
+#endif
/* Weights are given by caller. */
if (weights) {
@@ -813,7 +1091,13 @@ void DM_update_weight_mcol(Object *ob, DerivedMesh *dm, int const draw_flag,
wtcol_v = calc_weightpaint_vert_array(ob, dm, draw_flag, coba);
/* Now copy colors in all face verts. */
+ /*first add colors to the tesselation faces*/
+ /* XXX Why update that layer? We have to update WEIGHT_MLOOPCOL anyway,
+ * and tesselation recreates mface layers from mloop/mpoly ones, so no
+ * need to fill WEIGHT_MCOL here. */
+#if 0
for (i = 0; i < numFaces; i++, mf++, wtcol_f_step += (4 * 4)) {
+ /*origindex being NULL means we're operating on original mesh data*/
#if 0
unsigned int fidx= mf->v4 ? 3:2;
@@ -830,13 +1114,137 @@ void DM_update_weight_mcol(Object *ob, DerivedMesh *dm, int const draw_flag,
do {
copy_v4_v4_char((char *)&wtcol_f_step[fidx * 4],
- (char *)&wtcol_v[4 * (*(&mf->v1 + fidx))]);
+ (char *)&wtcol_v[4 * (*(&mf->v1 + fidx))]);
} while (fidx--);
}
+#endif
+ /*now add to loops, so the data can be passed through the modifier stack*/
+ /* If no CD_WEIGHT_MLOOPCOL existed yet, we have to add a new one! */
+ if (!wtcol_l) {
+ BLI_array_declare(wtcol_l);
+ totloop = 0;
+ for (i=0; i<dm->numPolyData; i++, mp++) {
+ ml = mloop + mp->loopstart;
+
+ BLI_array_growitems(wtcol_l, mp->totloop);
+ for (j = 0; j < mp->totloop; j++, ml++, totloop++) {
+ copy_v4_v4_char((char *)&wtcol_l[totloop],
+ (char *)&wtcol_v[4 * ml->v]);
+ }
+ }
+ CustomData_add_layer(&dm->loopData, CD_WEIGHT_MLOOPCOL, CD_ASSIGN, wtcol_l, totloop);
+ }
+ else {
+ totloop = 0;
+ for (i=0; i < dm->numPolyData; i++, mp++) {
+ ml = mloop + mp->loopstart;
+
+ for (j=0; j < mp->totloop; j++, ml++, totloop++) {
+ copy_v4_v4_char((char *)&wtcol_l[totloop],
+ (char *)&wtcol_v[4 * ml->v]);
+ }
+ }
+ }
MEM_freeN(wtcol_v);
}
}
+
+static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid)
+{
+ KeyBlock *kb;
+ int i, j, tot;
+
+ if (!me->key)
+ return;
+
+ tot = CustomData_number_of_layers(&dm->vertData, CD_SHAPEKEY);
+ for (i=0; i<tot; i++) {
+ CustomDataLayer *layer = &dm->vertData.layers[CustomData_get_layer_index_n(&dm->vertData, CD_SHAPEKEY, i)];
+ float (*cos)[3], (*kbcos)[3];
+
+ for (kb=me->key->block.first; kb; kb=kb->next) {
+ if (kb->uid == layer->uid)
+ break;
+ }
+
+ if (!kb) {
+ kb = add_keyblock(me->key, layer->name);
+ kb->uid = layer->uid;
+ }
+
+ if (kb->data)
+ MEM_freeN(kb->data);
+
+ cos = CustomData_get_layer_n(&dm->vertData, CD_SHAPEKEY, i);
+ kb->totelem = dm->numVertData;
+
+ kb->data = kbcos = MEM_mallocN(sizeof(float)*3*kb->totelem, "kbcos DerivedMesh.c");
+ if (kb->uid == actshape_uid) {
+ MVert *mvert = dm->getVertArray(dm);
+
+ for (j=0; j<dm->numVertData; j++, kbcos++, mvert++) {
+ copy_v3_v3(*kbcos, mvert->co);
+ }
+ } else {
+ for (j=0; j<kb->totelem; j++, cos++, kbcos++) {
+ copy_v3_v3(*kbcos, *cos);
+ }
+ }
+ }
+
+ for (kb=me->key->block.first; kb; kb=kb->next) {
+ if (kb->totelem != dm->numVertData) {
+ if (kb->data)
+ MEM_freeN(kb->data);
+
+ kb->totelem = dm->numVertData;
+ kb->data = MEM_callocN(sizeof(float)*3*kb->totelem, "kb->data derivedmesh.c");
+ fprintf(stderr, "%s: lost a shapekey layer! (bmesh internal error)\n", __func__);
+ }
+ }
+}
+
+static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob))
+{
+ KeyBlock *kb;
+ Key *key = me->key;
+ int i;
+ const size_t shape_alloc_len = sizeof(float) * 3 * me->totvert;
+
+ if (!me->key)
+ return;
+
+ /* ensure we can use mesh vertex count for derived mesh custom data */
+ if (me->totvert != dm->getNumVerts(dm)) {
+ fprintf(stderr,
+ "%s: vertex size mismatch (mesh/dm) '%s' (%d != %d)\n",
+ __func__, me->id.name+2, me->totvert, dm->getNumVerts(dm));
+ return;
+ }
+
+ for (i=0, kb=key->block.first; kb; kb=kb->next, i++) {
+ int ci;
+ float *array;
+
+ if (me->totvert != kb->totelem) {
+ fprintf(stderr,
+ "%s: vertex size mismatch (mesh/keyblock) '%s' (%d != %d)\n",
+ __func__, me->id.name+2, me->totvert, kb->totelem);
+ array = MEM_callocN(shape_alloc_len, __func__);
+ }
+ else {
+ array = MEM_mallocN(shape_alloc_len, __func__);
+ memcpy(array, kb->data, shape_alloc_len);
+ }
+
+ CustomData_add_layer_named(&dm->vertData, CD_SHAPEKEY, CD_ASSIGN, array, dm->numVertData, kb->name);
+ ci = CustomData_get_layer_index_n(&dm->vertData, CD_SHAPEKEY, i);
+
+ dm->vertData.layers[ci].uid = kb->uid;
+ }
+}
+
/* new value for useDeform -1 (hack for the gameengine):
* - apply only the modifier stack of the object, skipping the virtual modifiers,
* - don't apply the key
@@ -845,14 +1253,15 @@ void DM_update_weight_mcol(Object *ob, DerivedMesh *dm, int const draw_flag,
static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos)[3],
DerivedMesh **deform_r, DerivedMesh **final_r,
int useRenderParams, int useDeform,
- int needMapping, CustomDataMask dataMask, int index, int useCache)
+ int needMapping, CustomDataMask dataMask,
+ int index, int useCache, int build_shapekey_layers)
{
Mesh *me = ob->data;
ModifierData *firstmd, *md, *previewmd = NULL;
LinkNode *datamasks, *curr;
CustomDataMask mask, nextmask, append_mask = 0;
float (*deformedVerts)[3] = NULL;
- DerivedMesh *dm, *orcodm, *clothorcodm, *finaldm;
+ DerivedMesh *dm=NULL, *orcodm, *clothorcodm, *finaldm;
int numVerts = me->totvert;
int required_mode;
int isPrevDeform= FALSE;
@@ -940,7 +1349,10 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
*/
if (deform_r) {
*deform_r = CDDM_from_mesh(me, ob);
-
+
+ if (build_shapekey_layers)
+ add_shapekey_layers(dm, me, ob);
+
if(deformedVerts) {
CDDM_apply_vert_coords(*deform_r, deformedVerts);
CDDM_calc_normals(*deform_r);
@@ -1054,6 +1466,9 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
} else {
dm = CDDM_from_mesh(me, ob);
+ if (build_shapekey_layers)
+ add_shapekey_layers(dm, me, ob);
+
if(deformedVerts) {
CDDM_apply_vert_coords(dm, deformedVerts);
CDDM_calc_normals(dm);
@@ -1073,11 +1488,11 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
/* 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);
+ DM_add_poly_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
range_vn_i(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0);
range_vn_i(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0);
- range_vn_i(DM_get_face_data_layer(dm, CD_ORIGINDEX), dm->numFaceData, 0);
+ range_vn_i(DM_get_poly_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0);
}
}
@@ -1094,9 +1509,12 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
add_orco_dm(ob, NULL, dm, clothorcodm, CD_CLOTH_ORCO);
/* 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);
+ if(((CustomDataMask)GET_INT_FROM_POINTER(curr->link)) & CD_MASK_ORIGSPACE_MLOOP) {
+ if(!CustomData_has_layer(&dm->loopData, CD_ORIGSPACE_MLOOP)) {
+ DM_add_loop_layer(dm, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL);
+ DM_init_origspace(dm);
+ }
+ }
ndm = mti->applyModifier(md, ob, dm, useRenderParams, useCache);
@@ -1196,10 +1614,21 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
DM_update_weight_mcol(ob, finaldm, draw_flag, NULL, 0, NULL);
#endif
} else {
- finaldm = CDDM_from_mesh(me, ob);
+ int recalc_normals= 0;
+ finaldm = CDDM_from_mesh(me, ob);
+
+ if(build_shapekey_layers) {
+ add_shapekey_layers(finaldm, me, ob);
+ recalc_normals= 1;
+ }
+
if(deformedVerts) {
CDDM_apply_vert_coords(finaldm, deformedVerts);
+ recalc_normals= 1;
+ }
+
+ if(recalc_normals) {
CDDM_calc_normals(finaldm);
}
@@ -1228,6 +1657,36 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
}
#endif /* WITH_GAMEENGINE */
+ {
+ /* calculating normals can re-calculate tessfaces in some cases */
+ int num_tessface = finaldm->getNumTessFaces(finaldm);
+ /* --------------------------------------------------------------------- */
+ /* First calculate the polygon and vertex normals, re-tesselation
+ * copies these into the tessface's normal layer */
+
+
+ /* comment because this causes a bug when deform is applied after a
+ * bug when applied after a subsurf modifier (SubSurf -> Cast) for eg,
+ * it also looks like this isn't even needed since code above recalc's
+ * normals - campbell */
+#if 0
+ finaldm->calcNormals(finaldm);
+#endif
+
+ /* Re-tesselation is necessary to push render data (uvs, textures, colors)
+ * from loops and polys onto the tessfaces. This may be currently be
+ * redundantin cases where the render mode doesn't use these inputs, but
+ * ideally eventually tesselation would happen on-demand, and this is one
+ * of the primary places it would be needed. */
+ if (num_tessface == 0 && finaldm->getNumTessFaces(finaldm) == 0) {
+ finaldm->recalcTesselation(finaldm);
+ }
+ /* Need to watch this, it can cause issues, see bug [#29338] */
+ /* take care with this block, we really need testing frameworks */
+ /* --------------------------------------------------------------------- */
+ }
+
+
*final_r = finaldm;
if(orcodm)
@@ -1241,21 +1700,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(float)*3*numVerts, "vertexcos");
- cos = MEM_mallocN(sizeof(*cos)*numVerts, "vertexcos");
- for (i=0,eve=em->verts.first; i<numVerts; i++,eve=eve->next) {
+ eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BM_iter_step(&iter), i++) {
copy_v3_v3(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;
@@ -1269,7 +1731,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)
{
@@ -1284,7 +1746,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;
@@ -1298,7 +1760,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 */
@@ -1326,7 +1788,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);
}
}
@@ -1352,7 +1814,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
}
} else {
- dm = CDDM_from_editmesh(em, ob->data);
+ dm = CDDM_from_BMEditMesh(em, ob->data, FALSE, FALSE);
if(deformedVerts) {
CDDM_apply_vert_coords(dm, deformedVerts);
@@ -1386,9 +1848,12 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
DM_set_only_copy(dm, mask | CD_MASK_ORIGINDEX);
- if(mask & CD_MASK_ORIGSPACE)
- if(!CustomData_has_layer(&dm->faceData, CD_ORIGSPACE))
- DM_add_face_layer(dm, CD_ORIGSPACE, CD_DEFAULT, NULL);
+ if(mask & CD_MASK_ORIGSPACE_MLOOP) {
+ if(!CustomData_has_layer(&dm->loopData, CD_ORIGSPACE_MLOOP)) {
+ DM_add_loop_layer(dm, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL);
+ DM_init_origspace(dm);
+ }
+ }
if (mti->applyModifierEM)
ndm = mti->applyModifierEM(md, ob, em, dm);
@@ -1416,7 +1881,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
*cage_r = dm;
} else {
*cage_r =
- editmesh_get_derived(em,
+ getEditDerivedBMesh(em, ob,
deformedVerts ? MEM_dupallocN(deformedVerts) : NULL);
}
}
@@ -1434,16 +1899,26 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
if(!(cage_r && dm == *cage_r)) dm->release(dm);
CDDM_apply_vert_coords(*final_r, deformedVerts);
- CDDM_calc_normals(*final_r);
+ CDDM_calc_normals(*final_r); /* was CDDM_calc_normals_mapping - campbell */
} else if (dm) {
*final_r = dm;
+ (*final_r)->calcNormals(*final_r); /* BMESH_ONLY - BMESH_TODO. check if this is needed */
} else if (!deformedVerts && cage_r && *cage_r) {
*final_r = *cage_r;
+ (*final_r)->calcNormals(*final_r); /* BMESH_ONLY - BMESH_TODO. check if this is needed */
} else {
- *final_r = editmesh_get_derived(em, deformedVerts);
+ *final_r = getEditDerivedBMesh(em, ob, deformedVerts);
deformedVerts = NULL;
+ (*final_r)->calcNormals(*final_r); /* BMESH_ONLY - BMESH_TODO. check if this is needed */
}
+ /* --- */
+ /* BMESH_ONLY, ensure tessface's used for drawing,
+ * but dont recalculate if the last modifier in the stack gives us tessfaces */
+ DM_ensure_tessface(*final_r);
+ if (cage_r && (*cage_r != *final_r)) DM_ensure_tessface(*cage_r);
+ /* --- */
+
/* add an orco layer if needed */
if(dataMask & CD_MASK_ORCO)
add_orco_dm(ob, em, *final_r, orcodm, CD_ORCO);
@@ -1487,18 +1962,19 @@ static void clear_mesh_caches(Object *ob)
}
}
-static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask)
+static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask,
+ int build_shapekey_layers)
{
Object *obact = scene->basact?scene->basact->object:NULL;
- int editing = paint_facesel_test(ob) || paint_vertsel_test(ob);/* paint_vertsel_test */
+ int editing = paint_facesel_test(ob);
/* weight paint and face select need original indices because of selection buffer drawing */
- int needMapping = (ob==obact) && (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT|OB_MODE_VERTEX_PAINT)));
+ int needMapping = (ob==obact) && (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT|OB_MODE_VERTEX_PAINT|OB_MODE_TEXTURE_PAINT)));
clear_mesh_caches(ob);
mesh_calc_modifiers(scene, ob, NULL, &ob->derivedDeform,
&ob->derivedFinal, 0, 1,
- needMapping, dataMask, -1, 1);
+ needMapping, dataMask, -1, 1, build_shapekey_layers);
DM_set_object_boundbox (ob, ob->derivedFinal);
@@ -1507,7 +1983,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);
@@ -1524,7 +2000,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;
@@ -1532,12 +2008,13 @@ 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, int build_shapekey_layers)
{
if (em) {
- editmesh_build_data(scene, ob, em, dataMask);
+ editbmesh_build_data(scene, ob, em, dataMask);
} else {
- mesh_build_data(scene, ob, dataMask);
+ mesh_build_data(scene, ob, dataMask, build_shapekey_layers);
}
}
@@ -1549,7 +2026,7 @@ DerivedMesh *mesh_get_derived_final(Scene *scene, Object *ob, CustomDataMask dat
* the data we need, rebuild the derived mesh
*/
if(!ob->derivedFinal || (dataMask & ob->lastDataMask) != dataMask)
- mesh_build_data(scene, ob, dataMask);
+ mesh_build_data(scene, ob, dataMask, 0);
return ob->derivedFinal;
}
@@ -1560,7 +2037,7 @@ DerivedMesh *mesh_get_derived_deform(Scene *scene, Object *ob, CustomDataMask da
* the data we need, rebuild the derived mesh
*/
if(!ob->derivedDeform || (dataMask & ob->lastDataMask) != dataMask)
- mesh_build_data(scene, ob, dataMask);
+ mesh_build_data(scene, ob, dataMask, 0);
return ob->derivedDeform;
}
@@ -1569,7 +2046,7 @@ DerivedMesh *mesh_create_derived_render(Scene *scene, Object *ob, CustomDataMask
{
DerivedMesh *final;
- mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 1, 1, 0, dataMask, -1, 0);
+ mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 1, 1, 0, dataMask, -1, 0, 0);
return final;
}
@@ -1578,7 +2055,7 @@ DerivedMesh *mesh_create_derived_index_render(Scene *scene, Object *ob, CustomDa
{
DerivedMesh *final;
- mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 1, 1, 0, dataMask, index, 0);
+ mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 1, 1, 0, dataMask, index, 0, 0);
return final;
}
@@ -1587,7 +2064,7 @@ DerivedMesh *mesh_create_derived_view(Scene *scene, Object *ob, CustomDataMask d
{
DerivedMesh *final;
- mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 0, 1, 0, dataMask, -1, 0);
+ mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 0, 1, 0, dataMask, -1, 0, 0);
return final;
}
@@ -1597,7 +2074,7 @@ DerivedMesh *mesh_create_derived_no_deform(Scene *scene, Object *ob, float (*ver
{
DerivedMesh *final;
- mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 0, 0, 0, dataMask, -1, 0);
+ mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 0, 0, 0, dataMask, -1, 0, 0);
return final;
}
@@ -1607,7 +2084,7 @@ DerivedMesh *mesh_create_derived_no_virtual(Scene *scene, Object *ob, float (*ve
{
DerivedMesh *final;
- mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 0, -1, 0, dataMask, -1, 0);
+ mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 0, -1, 0, dataMask, -1, 0, 0);
return final;
}
@@ -1617,7 +2094,7 @@ DerivedMesh *mesh_create_derived_physics(Scene *scene, Object *ob, float (*vertC
{
DerivedMesh *final;
- mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 0, -1, 1, dataMask, -1, 0);
+ mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 0, -1, 1, dataMask, -1, 0, 0);
return final;
}
@@ -1628,14 +2105,14 @@ DerivedMesh *mesh_create_derived_no_deform_render(Scene *scene, Object *ob,
{
DerivedMesh *final;
- mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 1, 0, 0, dataMask, -1, 0);
+ mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 1, 0, 0, dataMask, -1, 0, 0);
return final;
}
/***/
-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
@@ -1643,27 +2120,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);
}
@@ -1703,7 +2180,7 @@ float *mesh_get_mapped_verts_nors(Scene *scene, Object *ob)
if(ob->type!=OB_MESH || me->totvert==0)
return NULL;
- dm= mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ dm= mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH|CD_MASK_ORIGINDEX);
vertexcosnos= MEM_callocN(6*sizeof(float)*me->totvert, "vertexcosnos map");
if(dm->foreachMappedVert) {
@@ -1733,7 +2210,7 @@ typedef struct
MVert * mvert; // vertices & normals
float (*orco)[3];
float (*tangent)[4]; // destination
- int numFaces;
+ int numTessFaces;
} SGLSLMeshToTangent;
@@ -1743,7 +2220,7 @@ typedef struct
static int GetNumFaces(const SMikkTSpaceContext * pContext)
{
SGLSLMeshToTangent * pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
- return pMesh->numFaces;
+ return pMesh->numTessFaces;
}
static int GetNumVertsOfFace(const SMikkTSpaceContext * pContext, const int face_num)
@@ -1832,15 +2309,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);
@@ -1849,8 +2326,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");
@@ -1870,7 +2347,7 @@ void DM_add_tangent_layer(DerivedMesh *dm)
mesh2tangent.mvert = mvert;
mesh2tangent.orco = orco;
mesh2tangent.tangent = tangent;
- mesh2tangent.numFaces = totface;
+ mesh2tangent.numTessFaces = totface;
sContext.m_pUserData = &mesh2tangent;
sContext.m_pInterface = &sInterface;
@@ -1963,11 +2440,11 @@ void DM_add_tangent_layer(DerivedMesh *dm)
void DM_calc_auto_bump_scale(DerivedMesh *dm)
{
/* int totvert= dm->getNumVerts(dm); */ /* UNUSED */
- int totface= dm->getNumFaces(dm);
+ int totface= dm->getNumTessFaces(dm);
MVert * mvert = dm->getVertArray(dm);
- MFace * mface = dm->getFaceArray(dm);
- MTFace * mtface = dm->getFaceDataArray(dm, CD_MTFACE);
+ MFace * mface = dm->getTessFaceArray(dm);
+ MTFace * mtface = dm->getTessFaceDataArray(dm, CD_MTFACE);
if(mtface)
{
@@ -2124,15 +2601,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->type == DM_TYPE_EDITMESH)
- tfdata = &((EditMeshDerivedMesh*)dm)->em->fdata;
- else
- tfdata = fdata;
-
+ fdata = tfdata = dm->getTessFaceDataLayout(dm);
+
/* calc auto bump scale if necessary */
if(dm->auto_bump_scale<=0.0f)
DM_calc_auto_bump_scale(dm);
@@ -2158,8 +2628,30 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
attribs->tface[a].array = tfdata->layers[layer].data;
attribs->tface[a].emOffset = tfdata->layers[layer].offset;
attribs->tface[a].glIndex = gattribs->layer[b].glindex;
- attribs->tface[a].glTexco = gattribs->layer[b].gltexco;
+ /* attribs->tface[a].glTexco = gattribs->layer[b].gltexco; */ /* BMESH_TODO, trunk has this but not bmesh, need to investigate whats going on here - campbell */
+ }
+ /* BMESH ONLY, may need to get this working?, otherwise remove */
+ /* else {
+ int player;
+ CustomData *pdata = dm->getPolyDataLayout(dm);
+
+ if(gattribs->layer[b].name[0])
+ player = CustomData_get_named_layer_index(pdata, CD_MTEXPOLY,
+ gattribs->layer[b].name);
+ else
+ player = CustomData_get_active_layer_index(pdata, CD_MTEXPOLY);
+
+ if (player != -1) {
+ a = attribs->tottface++;
+
+ attribs->tface[a].array = NULL;
+ attribs->tface[a].emOffset = pdata->layers[layer].offset;
+ attribs->tface[a].glIndex = gattribs->layer[b].glindex;
+ attribs->tface[a].glTexco = gattribs->layer[b].gltexco;
+
+ }
}
+ */
}
else if(gattribs->layer[b].type == CD_MCOL) {
/* vertex colors */
@@ -2223,6 +2715,15 @@ void DM_set_object_boundbox(Object *ob, DerivedMesh *dm)
/* --- NAVMESH (begin) --- */
#ifdef WITH_GAMEENGINE
+/* BMESH_TODO, navmesh is not working right currently
+ * All tools set this as MPoly data, but derived mesh currently draws from MFace (tessface)
+ *
+ * Proposed solution, rather then copy CD_RECAST into the MFace array,
+ * use ORIGINDEX to get the original poly index and then get the CD_RECAST
+ * data from the original me->mpoly layer. - campbell
+ */
+
+
BM_INLINE int navmesh_bit(int a, int b)
{
return (a & (1 << b)) >> b;
@@ -2262,7 +2763,7 @@ static void navmesh_drawColored(DerivedMesh *dm)
DEBUG_VBO( "Using legacy code. drawNavMeshColored\n" );
//glShadeModel(GL_SMOOTH);
glBegin(glmode = GL_QUADS);
- for(a = 0; a < dm->numFaceData; a++, mface++) {
+ for(a = 0; a < dm->numTessFaceData; a++, mface++) {
int new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
int pi = polygonIdx[a];
if (pi <= 0) {
@@ -2315,7 +2816,7 @@ static void navmesh_DM_drawFacesSolid(DerivedMesh *dm,
static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm)
{
DerivedMesh *result;
- int maxFaces = dm->getNumFaces(dm);
+ int maxFaces = dm->getNumPolys(dm);
int *recastData;
int vertsPerPoly=0, nverts=0, ndtris=0, npolys=0;
float* verts=NULL;
@@ -2393,6 +2894,30 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm)
/* --- NAVMESH (end) --- */
+void DM_init_origspace(DerivedMesh *dm)
+{
+ static float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
+
+ OrigSpaceLoop *lof_array = CustomData_get_layer(&dm->loopData, CD_ORIGSPACE_MLOOP);
+ OrigSpaceLoop *lof;
+ const int numpoly = dm->getNumPolys(dm);
+ // const int numloop = dm->getNumLoops(dm);
+ MPoly *mp = dm->getPolyArray(dm);
+ int i, j;
+
+ for (i = 0; i < numpoly; i++, mp++) {
+ /* only quads/tri's for now */
+ if (mp->totloop == 3 || mp->totloop == 4) {
+ lof = lof_array + mp->loopstart;
+ for (j = 0; j < mp->totloop; j++, lof++) {
+ copy_v2_v2(lof->uv, default_osf[j]);
+ }
+ }
+ }
+}
+
+
+
/* derivedmesh info printing function,
* to help track down differences DM output */
@@ -2429,26 +2954,35 @@ char *DM_debug_info(DerivedMesh *dm)
BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)dm);
switch (dm->type) {
case DM_TYPE_CDDM: tstr = "DM_TYPE_CDDM"; break;
- case DM_TYPE_EDITMESH: tstr = "DM_TYPE_EDITMESH"; break;
+ case DM_TYPE_EDITBMESH: tstr = "DM_TYPE_EDITMESH"; break;
case DM_TYPE_CCGDM: tstr = "DM_TYPE_CCGDM"; break;
default: tstr = "UNKNOWN"; break;
}
BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr);
BLI_dynstr_appendf(dynstr, " 'numVertData': %d,\n", dm->numVertData);
BLI_dynstr_appendf(dynstr, " 'numEdgeData': %d,\n", dm->numEdgeData);
- BLI_dynstr_appendf(dynstr, " 'numFaceData': %d,\n", dm->numFaceData);
+ BLI_dynstr_appendf(dynstr, " 'numTessFaceData': %d,\n", dm->numTessFaceData);
+ BLI_dynstr_appendf(dynstr, " 'numPolyData': %d,\n", dm->numPolyData);
BLI_dynstr_appendf(dynstr, " 'deformedOnly': %d,\n", dm->deformedOnly);
BLI_dynstr_appendf(dynstr, " 'vertexLayers': (\n");
dm_debug_info_layers(dynstr, dm, dm->getVertDataArray);
BLI_dynstr_appendf(dynstr, " ),\n");
+ BLI_dynstr_appendf(dynstr, " 'loopLayers': (\n");
+ dm_debug_info_layers(dynstr, dm, DM_get_loop_data_layer);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
BLI_dynstr_appendf(dynstr, " 'edgeLayers': (\n");
dm_debug_info_layers(dynstr, dm, dm->getEdgeDataArray);
BLI_dynstr_appendf(dynstr, " ),\n");
- BLI_dynstr_appendf(dynstr, " 'faceLayers': (\n");
- dm_debug_info_layers(dynstr, dm, dm->getFaceDataArray);
+ BLI_dynstr_appendf(dynstr, " 'tessFaceLayers': (\n");
+ dm_debug_info_layers(dynstr, dm, dm->getTessFaceDataArray);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, " 'polyLayers': (\n");
+ dm_debug_info_layers(dynstr, dm, DM_get_poly_data_layer);
BLI_dynstr_appendf(dynstr, " ),\n");
BLI_dynstr_appendf(dynstr, "}\n");
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index fabc35361b9..11700d7f072 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -65,6 +65,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"
#include "BKE_report.h"
@@ -898,7 +899,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;
@@ -908,11 +909,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);
@@ -974,7 +974,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 {
@@ -1015,44 +1015,45 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
DupliObject *dob;
DerivedMesh *dm;
Mesh *me= par->data;
- MTFace *mtface;
- MFace *mface;
+ MLoopUV *mloopuv;
+ MPoly *mpoly, *mp;
+ MLoop *mloop;
MVert *mvert;
float pmat[4][4], imat[3][3], (*orco)[3] = NULL, w;
int lay, oblay, totface, a;
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) {
- 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);
}
- totface= dm->getNumFaces(dm);
- mface= dm->getFaceArray(dm);
+ totface= dm->getNumPolys(dm);
+ mpoly= dm->getPolyArray(dm);
+ mloop= dm->getLoopArray(dm);
mvert= dm->getVertArray(dm);
if(G.rendering) {
orco= (float(*)[3])get_mesh_orco_verts(par);
transform_mesh_orco_verts(me, orco, me->totvert, 0);
- mtface= me->mtface;
+ mloopuv= me->mloopuv;
}
else {
orco= NULL;
- mtface= NULL;
+ mloopuv= NULL;
}
/* having to loop on scene OR group objects is NOT FUN */
@@ -1096,22 +1097,36 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
/* mballs have a different dupli handling */
if(ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */
- for(a=0; a<totface; a++) {
- int mv1 = mface[a].v1;
- int mv2 = mface[a].v2;
- int mv3 = mface[a].v3;
- int mv4 = mface[a].v4;
- float *v1= mvert[mv1].co;
- float *v2= mvert[mv2].co;
- float *v3= mvert[mv3].co;
- float *v4= (mv4)? mvert[mv4].co: NULL;
+ for(a=0, mp= mpoly; a<totface; a++, mp++) {
+ int mv1;
+ int mv2;
+ int mv3;
+ /* int mv4; */ /* UNUSED */
+ float *v1;
+ float *v2;
+ float *v3;
+ /* float *v4; */ /* UNUSED */
float cent[3], quat[4], mat[3][3], mat3[3][3], tmat[4][4], obmat[4][4];
+ MLoop *loopstart= mloop + mp->loopstart;
+
+ if (mp->totloop < 3) {
+ /* highly unlikely but to be safe */
+ continue;
+ }
+ else {
+ v1= mvert[(mv1= loopstart[0].v)].co;
+ v2= mvert[(mv2= loopstart[1].v)].co;
+ v3= mvert[(mv3= loopstart[2].v)].co;
+ /*
+ if (mp->totloop > 3) {
+ v4= mvert[(mv4= loopstart[3].v)].co;
+ }
+ */
+ }
/* translation */
- if(v4)
- cent_quad_v3(cent, v1, v2, v3, v4);
- else
- cent_tri_v3(cent, v1, v2, v3);
+ mesh_calc_poly_center(mp, loopstart, mvert, cent);
+
mul_m4_v3(pmat, cent);
sub_v3_v3v3(cent, cent, pmat[3]);
@@ -1127,7 +1142,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
/* scale */
if(par->transflag & OB_DUPLIFACES_SCALE) {
- float size= v4? area_quad_v3(v1, v2, v3, v4): area_tri_v3(v1, v2, v3);
+ float size= mesh_calc_poly_area(mp, loopstart, mvert, NULL);
size= sqrtf(size) * par->dupfacesca;
mul_m3_fl(mat, size);
}
@@ -1140,23 +1155,19 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
dob= new_dupli_object(lb, ob, obmat, par->lay, a, OB_DUPLIFACES, animated);
if(G.rendering) {
- w= (mv4)? 0.25f: 1.0f/3.0f;
+ w= 1.0f / (float)mp->totloop;
if(orco) {
- madd_v3_v3v3fl(dob->orco, dob->orco, orco[mv1], w);
- madd_v3_v3v3fl(dob->orco, dob->orco, orco[mv2], w);
- madd_v3_v3v3fl(dob->orco, dob->orco, orco[mv3], w);
- if (mv4) {
- madd_v3_v3v3fl(dob->orco, dob->orco, orco[mv4], w);
+ int j;
+ for (j = 0; j < mpoly->totloop; j++) {
+ madd_v3_v3fl(dob->orco, orco[loopstart[j].v], w);
}
}
- if(mtface) {
- madd_v2_v2v2fl(dob->uv, dob->uv, mtface[a].uv[0], w);
- madd_v2_v2v2fl(dob->uv, dob->uv, mtface[a].uv[1], w);
- madd_v2_v2v2fl(dob->uv, dob->uv, mtface[a].uv[2], w);
- if (mv4) {
- madd_v2_v2v2fl(dob->uv, dob->uv, mtface[a].uv[3], w);
+ if(mloopuv) {
+ int j;
+ for (j = 0; j < mpoly->totloop; j++) {
+ madd_v2_v2fl(dob->orco, mloopuv[loopstart[j].v].uv, w);
}
}
}
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 02b9330d588..036116c54da 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -1302,6 +1302,17 @@ void armature_mat_pose_to_bone(bPoseChannel *pchan, float inmat[][4], float outm
mul_v3_m4v3(outmat[3], loc_mat, inmat[3]);
}
+/* Convert Bone-Space Matrix to Pose-Space Matrix. */
+void armature_mat_bone_to_pose(bPoseChannel *pchan, float inmat[][4], float outmat[][4])
+{
+ float rotscale_mat[4][4], loc_mat[4][4];
+
+ pchan_to_pose_mat(pchan, rotscale_mat, loc_mat);
+
+ mult_m4_m4m4(outmat, rotscale_mat, inmat);
+ mul_v3_m4v3(outmat[3], loc_mat, inmat[3]);
+}
+
/* Convert Pose-Space Location to Bone-Space Location
* NOTE: this cannot be used to convert to pose-space location of the supplied
* pose-channel into its local space (i.e. 'visual'-keyframing)
@@ -2405,6 +2416,8 @@ void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float cti
/* Construct the posemat based on PoseChannels, that we do before applying constraints. */
/* pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b) */
+ armature_mat_bone_to_pose(pchan, pchan->chan_mat, pchan->pose_mat);
+#if 0 /* XXX Old code, will remove this later. */
{
float rotscale_mat[4][4], loc_mat[4][4];
pchan_to_pose_mat(pchan, rotscale_mat, loc_mat);
@@ -2413,6 +2426,7 @@ void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float cti
/* Location. */
mul_v3_m4v3(pchan->pose_mat[3], loc_mat, pchan->chan_mat[3]);
}
+#endif
/* Only rootbones get the cyclic offset (unless user doesn't want that). */
/* XXX That could be a problem for snapping and other "reverse transform" features... */
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index 1aad0a242f9..5c50c14f1a8 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -41,7 +41,7 @@
#include "BLI_linklist.h"
#include "BKE_DerivedMesh.h"
-
+#include "BKE_tessmesh.h"
#include "BLI_math.h"
#include "MEM_guardedalloc.h"
@@ -555,7 +555,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;
}
@@ -572,22 +572,87 @@ BVHTree* bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float
if(tree == NULL)
{
int i;
- int numFaces= mesh->getNumFaces(mesh);
- MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT);
- MFace *face = mesh->getFaceDataArray(mesh, CD_MFACE);
+ int numFaces= mesh->getNumTessFaces(mesh);
- if(vert != NULL && face != NULL)
+ /* BMESH spesific check that we have tessfaces,
+ * we _could_ tesselate here but rather not - campbell
+ *
+ * this assert checks we have tessfaces,
+ * if not caller should use DM_ensure_tessface() */
+ BLI_assert(!(numFaces == 0 && mesh->getNumPolys(mesh) != 0));
+
+ if(numFaces != 0)
{
/* Create a bvh-tree of the given target */
tree = BLI_bvhtree_new(numFaces, epsilon, tree_type, axis);
if(tree != NULL)
{
- /* XXX, for snap only, em & dm are assumed to be aligned, since dm is the em's cage */
- EditMesh *em= data->em_evil;
+ BMEditMesh *em= data->em_evil;
if(em) {
- EditFace *efa= em->faces.first;
- for(i = 0; i < numFaces; i++, efa= efa->next) {
- if(!(efa->f & 1) && efa->h==0 && !((efa->v1->f&1)+(efa->v2->f&1)+(efa->v3->f&1)+(efa->v4?efa->v4->f&1:0))) {
+ /*data->em_evil is only set for snapping, and only for the mesh of the object
+ which is currently open in edit mode. When set, the bvhtree should not contain
+ faces that will interfere with snapping (e.g. faces that are hidden/selected
+ or faces that have selected verts).*/
+
+ /* XXX, for snap only, em & dm are assumed to be aligned, since dm is the em's cage */
+
+ /*Insert BMesh-tesselation triangles into the bvh tree, unless they are hidden
+ and/or selected. Even if the faces themselves are not selected for the snapped
+ transform, having a vertex selected means the face (and thus it's tesselated
+ triangles) will be moving and will not be a good snap targets.*/
+ for (i = 0; i < em->tottri; i++) {
+ BMLoop **tri = em->looptris[i];
+ BMFace *f;
+ BMVert *v;
+ BMIter iter;
+ int insert;
+
+ /*Each loop of the triangle points back to the BMFace it was tesselated from.
+ All three should point to the same face, so just use the face from the first
+ loop.*/
+ f = tri[0]->f;
+
+ /*If the looptris is ordered such that all triangles tesselated from a single
+ faces are consecutive elements in the array, then we could speed up the tests
+ below by using the insert value from the previous iteration.*/
+
+ /*Start with the assumption the triangle should be included for snapping.*/
+ insert = 1;
+
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ /*Don't insert triangles tesselated from faces that are hidden
+ or selected*/
+ insert = 0;
+ }
+ else {
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_FACE, f) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ /*Don't insert triangles tesselated from faces that have
+ any selected verts.*/
+ insert = 0;
+ }
+ }
+ }
+
+ if (insert)
+ {
+ /*No reason found to block hit-testing the triangle for snap,
+ so insert it now.*/
+ float co[4][3];
+ copy_v3_v3(co[0], tri[0]->v->co);
+ copy_v3_v3(co[1], tri[1]->v->co);
+ copy_v3_v3(co[2], tri[2]->v->co);
+
+ BLI_bvhtree_insert(tree, i, co[0], 3);
+ }
+ }
+ }
+ else {
+ MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT);
+ MFace *face = mesh->getTessFaceDataArray(mesh, CD_MFACE);
+
+ if (vert != NULL && face != NULL) {
+ for(i = 0; i < numFaces; i++) {
float co[4][3];
copy_v3_v3(co[0], vert[ face[i].v1 ].co);
copy_v3_v3(co[1], vert[ face[i].v2 ].co);
@@ -599,18 +664,6 @@ BVHTree* bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float
}
}
}
- else {
- for(i = 0; i < numFaces; i++) {
- float co[4][3];
- copy_v3_v3(co[0], vert[ face[i].v1 ].co);
- copy_v3_v3(co[1], vert[ face[i].v2 ].co);
- copy_v3_v3(co[2], vert[ face[i].v3 ].co);
- if(face[i].v4)
- copy_v3_v3(co[3], vert[ face[i].v4 ].co);
-
- BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3);
- }
- }
BLI_bvhtree_balance(tree);
//Save on cache for later use
@@ -638,7 +691,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 8bc8faad0cc..47492dbed37 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -1,4 +1,4 @@
-/*
+ /*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -36,11 +36,23 @@
#include "GL/glew.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;
@@ -80,6 +94,9 @@ typedef struct {
/* Mesh connectivity */
struct ListBase *fmap;
struct IndexNode *fmap_mem;
+
+ struct ListBase *pmap;
+ struct IndexNode *pmap_mem;
} CDDerivedMesh;
/**************** DerivedMesh interface functions ****************/
@@ -93,9 +110,19 @@ static int cdDM_getNumEdges(DerivedMesh *dm)
return dm->numEdgeData;
}
-static int cdDM_getNumFaces(DerivedMesh *dm)
+static int cdDM_getNumTessFaces(DerivedMesh *dm)
+{
+ return dm->numTessFaceData;
+}
+
+static int cdDM_getNumLoops(DerivedMesh *dm)
{
- return dm->numFaceData;
+ return dm->numLoopData;
+}
+
+static int cdDM_getNumPolys(DerivedMesh *dm)
+{
+ return dm->numPolyData;
}
static void cdDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
@@ -110,7 +137,7 @@ static void cdDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
*edge_r = cddm->medge[index];
}
-static void cdDM_getFace(DerivedMesh *dm, int index, MFace *face_r)
+static void cdDM_getTessFace(DerivedMesh *dm, int index, MFace *face_r)
{
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
*face_r = cddm->mface[index];
@@ -128,10 +155,22 @@ static void cdDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
memcpy(edge_r, cddm->medge, sizeof(*edge_r) * dm->numEdgeData);
}
-static void cdDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
+static void cdDM_copyTessFaceArray(DerivedMesh *dm, MFace *face_r)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ memcpy(face_r, cddm->mface, sizeof(*face_r) * dm->numTessFaceData);
+}
+
+static void cdDM_copyLoopArray(DerivedMesh *dm, MLoop *loop_r)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ memcpy(loop_r, cddm->mloop, sizeof(*loop_r) * dm->numLoopData);
+}
+
+static void cdDM_copyPolyArray(DerivedMesh *dm, MPoly *poly_r)
{
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- memcpy(face_r, cddm->mface, sizeof(*face_r) * dm->numFaceData);
+ memcpy(poly_r, cddm->mpoly, sizeof(*poly_r) * dm->numPolyData);
}
static void cdDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
@@ -170,6 +209,21 @@ static void cdDM_getVertNo(DerivedMesh *dm, int index, float no_r[3])
normal_short_to_float_v3(no_r, cddm->mvert[index].no);
}
+static ListBase *cdDM_getPolyMap(Object *ob, DerivedMesh *dm)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+
+ if(!cddm->pmap && ob->type == OB_MESH) {
+ Mesh *me= ob->data;
+
+ create_vert_poly_map(&cddm->pmap, &cddm->pmap_mem,
+ me->mpoly, me->mloop,
+ me->totvert, me->totpoly, me->totloop);
+ }
+
+ return cddm->pmap;
+}
+
static ListBase *cdDM_getFaceMap(Object *ob, DerivedMesh *dm)
{
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
@@ -178,7 +232,7 @@ static ListBase *cdDM_getFaceMap(Object *ob, DerivedMesh *dm)
Mesh *me= ob->data;
create_vert_face_map(&cddm->fmap, &cddm->fmap_mem, me->mface,
- me->totvert, me->totface);
+ me->totvert, me->totface);
}
return cddm->fmap;
@@ -203,7 +257,7 @@ static int can_pbvh_draw(Object *ob, DerivedMesh *dm)
if(deformed)
return 0;
- return (cddm->mvert == me->mvert) || ob->sculpt->kb;
+ return cddm->mvert == me->mvert || ob->sculpt->kb;
}
static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
@@ -230,6 +284,7 @@ static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
Mesh *me= ob->data;
cddm->pbvh = BLI_pbvh_new();
cddm->pbvh_draw = can_pbvh_draw(ob, dm);
+ BLI_assert(!(me->mface == NULL && me->mpoly != NULL)); /* BMESH ONLY complain if mpoly is valid but not mface */
BLI_pbvh_build_mesh(cddm->pbvh, me->mface, me->mvert,
me->totface, me->totvert);
@@ -256,7 +311,7 @@ static void cdDM_update_normals_from_pbvh(DerivedMesh *dm)
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
float (*face_nors)[3];
- if(!cddm->pbvh || !cddm->pbvh_draw || !dm->numFaceData)
+ if(!cddm->pbvh || !cddm->pbvh_draw || !dm->numTessFaceData)
return;
face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
@@ -292,13 +347,13 @@ 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) {
if( GPU_buffer_legacy(dm) ) {
glBegin(GL_LINES);
- for(i = 0; i < dm->numFaceData; i++, mf++, tf++) {
+ for(i = 0; i < dm->numTessFaceData; i++, mf++, tf++) {
if(!(mf->flag&ME_HIDE)) {
glVertex2fv(tf->uv[0]);
glVertex2fv(tf->uv[1]);
@@ -328,7 +383,7 @@ static void cdDM_drawUVEdges(DerivedMesh *dm)
GPU_uvedge_setup(dm);
if( !GPU_buffer_legacy(dm) ) {
- for(i = 0; i < dm->numFaceData; i++, mf++) {
+ for(i = 0; i < dm->numTessFaceData; i++, mf++) {
if(!(mf->flag&ME_HIDE)) {
draw = 1;
}
@@ -463,7 +518,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) { \
@@ -475,7 +530,7 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm,
}
if(cddm->pbvh && cddm->pbvh_draw) {
- if(dm->numFaceData) {
+ if(dm->numTessFaceData) {
float (*face_nors)[3] = CustomData_get_layer(&dm->faceData, CD_NORMAL);
/* should be per face */
@@ -493,7 +548,7 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm,
if( GPU_buffer_legacy(dm) ) {
DEBUG_VBO( "Using legacy code. cdDM_drawFacesSolid\n" );
glBegin(glmode = GL_QUADS);
- for(a = 0; a < dm->numFaceData; a++, mface++) {
+ for(a = 0; a < dm->numTessFaceData; a++, mface++) {
int new_glmode, new_matnr, new_shademodel;
new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
@@ -586,7 +641,7 @@ static void cdDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned cha
DEBUG_VBO( "Using legacy code. cdDM_drawFacesColored\n" );
glShadeModel(GL_SMOOTH);
glBegin(glmode = GL_QUADS);
- for(a = 0; a < dm->numFaceData; a++, mface++, cp1 += 16) {
+ for(a = 0; a < dm->numTessFaceData; a++, mface++, cp1 += 16) {
int new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
if(new_glmode != glmode) {
@@ -652,21 +707,21 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
{
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 */ /* UNUSED */;
- 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);
if( GPU_buffer_legacy(dm) ) {
DEBUG_VBO( "Using legacy code. cdDM_drawFacesTex_common\n" );
- for(i = 0; i < dm->numFaceData; i++, mf++) {
+ for(i = 0; i < dm->numTessFaceData; i++, mf++) {
MVert *mvert;
int flag;
unsigned char *cp = NULL;
@@ -752,8 +807,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++ ) {
/* bgr -> rgb is intentional (and stupid), but how its stored internally */
colors[i*12+j*3] = col[i*4+j].b;
@@ -850,14 +905,14 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm,
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_get_tessface_data_layer(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);
@@ -865,7 +920,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm,
* color array temporarily overwritten for drawing, then reset. */
if( GPU_buffer_legacy(dm) || G.f & G_BACKBUFSEL) {
DEBUG_VBO( "Using legacy code. cdDM_drawMappedFaces\n" );
- for(i = 0; i < dm->numFaceData; i++, mf++) {
+ for(i = 0; i < dm->numTessFaceData; i++, mf++) {
int drawSmooth = (mf->flag & ME_SMOOTH);
int draw= 1;
@@ -1067,10 +1122,10 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm,
DMVertexAttribs attribs;
MVert *mvert = cddm->mvert;
MFace *mface = cddm->mface;
- /* MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */
- float (*nors)[3] = dm->getFaceDataArray(dm, CD_NORMAL);
+ /* MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */
+ float (*nors)[3] = dm->getTessFaceDataArray(dm, CD_NORMAL);
int a, b, dodraw, matnr, new_matnr;
- int orig, *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ int orig, *index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
cdDM_update_normals_from_pbvh(dm);
@@ -1085,7 +1140,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm,
glBegin(GL_QUADS);
- for(a = 0; a < dm->numFaceData; a++, mface++) {
+ for(a = 0; a < dm->numTessFaceData; a++, mface++) {
const int smoothnormal = (mface->flag & ME_SMOOTH);
new_matnr = mface->mat_nr + 1;
@@ -1361,9 +1416,9 @@ static void cdDM_drawMappedFacesMat(DerivedMesh *dm,
DMVertexAttribs attribs;
MVert *mvert = cddm->mvert;
MFace *mf = cddm->mface;
- float (*nors)[3] = dm->getFaceDataArray(dm, CD_NORMAL);
+ float (*nors)[3] = dm->getTessFaceDataArray(dm, CD_NORMAL);
int a, matnr, new_matnr;
- int orig, *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ int orig, *index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
cdDM_update_normals_from_pbvh(dm);
@@ -1375,7 +1430,7 @@ static void cdDM_drawMappedFacesMat(DerivedMesh *dm,
glBegin(GL_QUADS);
- for(a = 0; a < dm->numFaceData; a++, mf++) {
+ for(a = 0; a < dm->numTessFaceData; a++, mf++) {
const int smoothnormal = (mf->flag & ME_SMOOTH);
/* material */
@@ -1505,10 +1560,13 @@ 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];
@@ -1518,28 +1576,60 @@ static void cdDM_foreachMappedFaceCenter(
}
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);
- copy_v3_v3(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);
}
+
+}
+
+void CDDM_recalc_tesselation_ex(DerivedMesh *dm, const int do_face_nor_cpy)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+
+ dm->numTessFaceData = mesh_recalcTesselation(&dm->faceData, &dm->loopData, &dm->polyData,
+ cddm->mvert,
+ dm->numTessFaceData, dm->numLoopData, dm->numPolyData,
+ do_face_nor_cpy);
+
+ if (!CustomData_get_layer(&dm->faceData, CD_ORIGINDEX)) {
+ int *polyIndex = CustomData_get_layer(&dm->faceData, CD_POLYINDEX);
+ CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_REFERENCE, polyIndex, dm->numTessFaceData);
+ }
+
+ cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+
+ /* Tesselation recreated faceData, and the active layer indices need to get re-propagated
+ from loops and polys to faces */
+ CustomData_bmesh_update_active_layers(&dm->faceData, &dm->polyData, &dm->loopData);
+}
+
+void CDDM_recalc_tesselation(DerivedMesh *dm)
+{
+ CDDM_recalc_tesselation_ex(dm, TRUE);
}
static void cdDM_free_internal(CDDerivedMesh *cddm)
{
if(cddm->fmap) MEM_freeN(cddm->fmap);
if(cddm->fmap_mem) MEM_freeN(cddm->fmap_mem);
+
+ if(cddm->pmap) MEM_freeN(cddm->pmap);
+ if(cddm->pmap_mem) MEM_freeN(cddm->pmap_mem);
}
static void cdDM_release(DerivedMesh *dm)
@@ -1552,6 +1642,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)
{
@@ -1564,27 +1659,37 @@ 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->getNumLoops = cdDM_getNumLoops;
+ dm->getNumPolys = cdDM_getNumPolys;
dm->getVert = cdDM_getVert;
dm->getEdge = cdDM_getEdge;
- dm->getFace = cdDM_getFace;
+ dm->getTessFace = cdDM_getTessFace;
+
dm->copyVertArray = cdDM_copyVertArray;
dm->copyEdgeArray = cdDM_copyEdgeArray;
- dm->copyFaceArray = cdDM_copyFaceArray;
+ dm->copyTessFaceArray = cdDM_copyTessFaceArray;
+ dm->copyLoopArray = cdDM_copyLoopArray;
+ dm->copyPolyArray = cdDM_copyPolyArray;
+
dm->getVertData = DM_get_vert_data;
dm->getEdgeData = DM_get_edge_data;
- dm->getFaceData = DM_get_face_data;
+ dm->getTessFaceData = DM_get_tessface_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;
+
+ dm->calcNormals = CDDM_calc_normals_mapping;
+ dm->recalcTesselation = CDDM_recalc_tesselation;
dm->getVertCos = cdDM_getVertCos;
dm->getVertCo = cdDM_getVertCo;
dm->getVertNo = cdDM_getVertNo;
dm->getPBVH = cdDM_getPBVH;
+ dm->getPolyMap = cdDM_getPolyMap;
dm->getFaceMap = cdDM_getFaceMap;
dm->drawVerts = cdDM_drawVerts;
@@ -1612,24 +1717,30 @@ 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 numTessFaces, 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, numTessFaces, 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->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numTessFaces);
+ CustomData_add_layer(&dm->faceData, CD_POLYINDEX, CD_CALLOC, NULL, numTessFaces);
+ 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->faceData, CD_MFACE, CD_CALLOC, NULL, numTessFaces);
+ 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;
}
@@ -1640,10 +1751,12 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *UNUSED(ob))
DerivedMesh *dm = &cddm->dm;
CustomDataMask mask = CD_MASK_MESH & (~CD_MASK_MDISPS);
int alloctype;
+ int *polyindex = NULL;
/* 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;
@@ -1653,21 +1766,38 @@ 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_POLYINDEX, 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);
+ /* commented since even when CD_POLYINDEX was first added this line fails
+ * on the default cube, (after editmode toggle too) - campbell */
+#if 0
+ BLI_assert(CustomData_has_layer(&cddm->dm.faceData, CD_POLYINDEX));
+#endif
+
+ polyindex = CustomData_get_layer(&dm->faceData, CD_POLYINDEX);
+ if (!CustomData_has_layer(&cddm->dm.faceData, CD_ORIGINDEX)) {
+ CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_REFERENCE, polyindex, mesh->totface);
+ }
+
return dm;
}
-DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *UNUSED(me))
+static DerivedMesh *UNUSED_FUNCTION(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;
@@ -1684,7 +1814,9 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *UNUSED(me))
/* CustomData_merge(&em->edata, &dm->edgeData, CD_MASK_DERIVEDMESH,
CD_CALLOC, dm->numEdgeData); */
CustomData_merge(&em->fdata, &dm->faceData, CD_MASK_DERIVEDMESH,
- CD_CALLOC, dm->numFaceData);
+ CD_CALLOC, dm->numTessFaceData);
+ CustomData_merge(&em->fdata, &dm->faceData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, dm->numTessFaceData);
/* set eve->hash to vert index */
for(i = 0, eve = em->verts.first; eve; eve = eve->next, ++i)
@@ -1739,8 +1871,8 @@ 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);
- for(i = 0, efa = em->faces.first; i < dm->numFaceData;
+ index = dm->getTessFaceDataArray(dm, CD_POLYINDEX);
+ for(i = 0, efa = em->faces.first; i < dm->numTessFaceData;
i++, efa = efa->next, index++) {
MFace *mf = &mface[i];
@@ -1771,68 +1903,315 @@ DerivedMesh *CDDM_from_curve_customDB(Object *ob, ListBase *dispbase)
CDDerivedMesh *cddm;
MVert *allvert;
MEdge *alledge;
- MFace *allface;
- int totvert, totedge, totface;
+ MLoop *allloop;
+ MPoly *allpoly;
+ int totvert, totedge, totloop, totpoly;
if (nurbs_to_mdata_customdb(ob, dispbase, &allvert, &totvert, &alledge,
- &totedge, &allface, &totface) != 0) {
+ &totedge, &allloop, &allpoly, &totloop, &totpoly) != 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, 0, totloop, totpoly);
dm->deformedOnly = 1;
cddm = (CDDerivedMesh*)dm;
memcpy(cddm->mvert, allvert, totvert*sizeof(MVert));
memcpy(cddm->medge, alledge, totedge*sizeof(MEdge));
- memcpy(cddm->mface, allface, totface*sizeof(MFace));
+ memcpy(cddm->mloop, allloop, totloop*sizeof(MLoop));
+ memcpy(cddm->mpoly, allpoly, totpoly*sizeof(MPoly));
MEM_freeN(allvert);
MEM_freeN(alledge);
- MEM_freeN(allface);
+ MEM_freeN(allloop);
+ MEM_freeN(allpoly);
+
+ CDDM_calc_edges(dm);
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);
+
+ ME_MTEXFACE_CPY(texface, texpoly);
+
+ for (j=0; j<3; j++) {
+ l = l3[j];
+ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
+ copy_v2_v2(texface->uv[j], mloopuv->uv);
+ }
+ }
+
+ 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 *UNUSED(me), int use_mdisps, int use_tessface)
+{
+ BMesh *bm = em->bm;
+
+ DerivedMesh *dm = CDDM_new(bm->totvert,
+ bm->totedge,
+ use_tessface ? em->tottri : 0,
+ bm->totloop,
+ bm->totface);
+
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ 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(&bm->ldata, CD_MLOOPCOL);
+ int numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ int *index, add_orig;
+ int has_crease, has_edge_bweight, has_vert_bweight;
+ CustomDataMask mask;
+ unsigned int i, j;
+
+ has_edge_bweight = CustomData_has_layer(&bm->edata, CD_BWEIGHT);
+ has_vert_bweight = CustomData_has_layer(&bm->vdata, CD_BWEIGHT);
+ has_crease = CustomData_has_layer(&bm->edata, CD_CREASE);
+
+ dm->deformedOnly = 1;
+
+ /*don't add origindex layer if one already exists*/
+ add_orig = !CustomData_has_layer(&bm->pdata, CD_ORIGINDEX);
+
+ mask = use_mdisps ? CD_MASK_DERIVEDMESH|CD_MASK_MDISPS : CD_MASK_DERIVEDMESH;
+
+ /*don't process shapekeys, we only feed them through the modifier stack as needed,
+ e.g. for applying modifiers or the like*/
+ mask &= ~CD_MASK_SHAPEKEY;
+ CustomData_merge(&bm->vdata, &dm->vertData, mask,
+ CD_CALLOC, dm->numVertData);
+ CustomData_merge(&bm->edata, &dm->edgeData, mask,
+ CD_CALLOC, dm->numEdgeData);
+ CustomData_merge(&bm->ldata, &dm->loopData, mask,
+ CD_CALLOC, dm->numLoopData);
+ CustomData_merge(&bm->pdata, &dm->polyData, mask,
+ CD_CALLOC, dm->numPolyData);
+
+ /*add tesselation mface layers*/
+ if (use_tessface) {
+ CustomData_from_bmeshpoly(&dm->faceData, &dm->polyData, &dm->loopData, em->tottri);
+ }
+
+ index = dm->getVertDataArray(dm, CD_ORIGINDEX);
+
+ eve = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BM_iter_step(&iter), i++, index++) {
+ MVert *mv = &mvert[i];
+
+ copy_v3_v3(mv->co, eve->co);
+
+ BM_elem_index_set(eve, i); /* set_inline */
+
+ normal_float_to_short_v3(mv->no, eve->no);
+
+ mv->flag = BM_vert_flag_to_mflag(eve);
+
+ if (has_vert_bweight)
+ mv->bweight = (unsigned char)(BM_elem_float_data_get(&bm->vdata, eve, CD_BWEIGHT)*255.0f);
+
+ if (add_orig) *index = i;
+
+ CustomData_from_bmesh_block(&bm->vdata, &dm->vertData, eve->head.data, i);
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+
+ index = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
+ eed = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL);
+ for (i=0; eed; eed=BM_iter_step(&iter), i++, index++) {
+ MEdge *med = &medge[i];
+
+ BM_elem_index_set(eed, i); /* set_inline */
+
+ med->v1 = BM_elem_index_get(eed->v1);
+ med->v2 = BM_elem_index_get(eed->v2);
+
+ if (has_crease)
+ med->crease = (unsigned char)(BM_elem_float_data_get(&bm->edata, eed, CD_CREASE)*255.0f);
+ if (has_edge_bweight)
+ med->bweight = (unsigned char)(BM_elem_float_data_get(&bm->edata, eed, CD_BWEIGHT)*255.0f);
+
+ med->flag = BM_edge_flag_to_mflag(eed);
+
+ CustomData_from_bmesh_block(&bm->edata, &dm->edgeData, eed->head.data, i);
+ if (add_orig) *index = i;
+ }
+ bm->elem_index_dirty &= ~BM_EDGE;
+
+ /* avoid this where possiblem, takes extra memory */
+ if (use_tessface) {
+ int *polyindex;
+
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+
+ polyindex = dm->getTessFaceDataArray(dm, CD_POLYINDEX);
+ index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ for(i = 0; i < dm->numTessFaceData; i++, index++, polyindex++) {
+ MFace *mf = &mface[i];
+ BMLoop **l = em->looptris[i];
+ efa = l[0]->f;
+
+ mf->v1 = BM_elem_index_get(l[0]->v);
+ mf->v2 = BM_elem_index_get(l[1]->v);
+ mf->v3 = BM_elem_index_get(l[2]->v);
+ mf->v4 = 0;
+ mf->mat_nr = efa->mat_nr;
+ mf->flag = BM_face_flag_to_mflag(efa);
+
+ *index = add_orig ? BM_elem_index_get(efa) : *(int*)CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_ORIGINDEX);
+ *polyindex = BM_elem_index_get(efa);
+
+ 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 = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, NULL);
+ for (i=0; efa; i++, efa=BM_iter_step(&iter), index++) {
+ BMLoop *l;
+ MPoly *mp = &mpoly[i];
+
+ BM_elem_index_set(efa, i); /* set_inline */
+
+ mp->totloop = efa->len;
+ mp->flag = BM_face_flag_to_mflag(efa);
+ mp->loopstart = j;
+ mp->mat_nr = efa->mat_nr;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) {
+ mloop->v = BM_elem_index_get(l->v);
+ mloop->e = BM_elem_index_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;
+ }
+ bm->elem_index_dirty &= ~BM_FACE;
+
+ return dm;
+}
+
+static DerivedMesh *cddm_copy_ex(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 numTessFaces = source->numTessFaceData;
+ 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, numTessFaces,
+ numLoops, numPolys);
dm->deformedOnly = source->deformedOnly;
CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges);
- CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numFaces);
+ CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numTessFaces);
/* 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);
+ CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numTessFaces);
+
+ 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);
+
+ /* any callers that need tessface data can calculate it - campbell */
+#if 0
+ /* BMESH_TODO: Find out why this is necessary (or else find a way to remove
+ it). If it is necessary, add a comment explaining why. */
+ CDDM_recalc_tesselation((DerivedMesh *)cddm);
+#endif
return dm;
}
+DerivedMesh *CDDM_copy(DerivedMesh *source)
+{
+ return cddm_copy_ex(source, 0);
+}
+
+DerivedMesh *CDDM_copy_from_tessface(DerivedMesh *source)
+{
+ return cddm_copy_ex(source, 1);
+}
+
/* 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 numTessFaces,
+ int numLoops, int numPolys)
{
CDDerivedMesh *cddm = cdDM_create("CDDM_from_template dest");
DerivedMesh *dm = &cddm->dm;
@@ -1840,26 +2219,32 @@ 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, numTessFaces, 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->faceData, CD_MFACE, CD_CALLOC, NULL, numTessFaces);
+ 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);
if(!CustomData_get_layer(&dm->edgeData, CD_ORIGINDEX))
CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
if(!CustomData_get_layer(&dm->faceData, CD_ORIGINDEX))
- CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numFaces);
+ CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numTessFaces);
+ if(!CustomData_get_layer(&dm->faceData, CD_POLYINDEX))
+ CustomData_add_layer(&dm->faceData, CD_POLYINDEX, CD_CALLOC, NULL, numTessFaces);
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;
}
@@ -1892,9 +2277,79 @@ void CDDM_apply_vert_normals(DerivedMesh *dm, short (*vertNormals)[3])
copy_v3_v3_short(vert->no, vertNormals[i]);
}
+void CDDM_calc_normals_mapping(DerivedMesh *dm)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ float (*face_nors)[3] = NULL;
+
+ /* use this to skip calculating normals on original vert's, this may need to be changed */
+ const short only_face_normals = CustomData_is_referenced_layer(&dm->vertData, CD_MVERT);
+
+ if(dm->numVertData == 0) return;
+
+ /* now we skip calculating vertex normals for referenced layer,
+ * no need to duplicate verts.
+ * WATCH THIS, bmesh only change!,
+ * need to take care of the side effects here - campbell */
+#if 0
+ /* we don't want to overwrite any referenced layers */
+ cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
+#endif
+
+
+ if (dm->numTessFaceData == 0) {
+ /* No tesselation on this mesh yet, need to calculate one.
+ *
+ * Important not to update face normals from polys since it
+ * interfears with assigning the new normal layer in the following code.
+ */
+ CDDM_recalc_tesselation_ex(dm, FALSE);
+ }
+ else {
+ /* A tesselation already exists, it should always have a CD_POLYINDEX */
+ BLI_assert(CustomData_has_layer(&dm->faceData, CD_POLYINDEX));
+ CustomData_free_layers(&dm->faceData, CD_NORMAL, dm->numTessFaceData);
+ }
+
+
+ face_nors = MEM_mallocN(sizeof(float)*3*dm->numTessFaceData, "face_nors");
+
+ /* calculate face normals */
+ mesh_calc_normals_mapping_ex(cddm->mvert, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm),
+ dm->numLoopData, dm->numPolyData, NULL, cddm->mface, dm->numTessFaceData,
+ CustomData_get_layer(&dm->faceData, CD_POLYINDEX), face_nors,
+ only_face_normals);
+
+ CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_ASSIGN,
+ face_nors, dm->numTessFaceData);
+
+
+}
+
+/* bmesh note: this matches what we have in trunk */
void CDDM_calc_normals(DerivedMesh *dm)
{
CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ float (*poly_nors)[3];
+
+ if(dm->numVertData == 0) return;
+
+ /* we don't want to overwrite any referenced layers */
+ cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
+
+ /* fill in if it exists */
+ poly_nors = CustomData_get_layer(&dm->polyData, CD_NORMAL);
+ if (!poly_nors) {
+ poly_nors = CustomData_add_layer(&dm->polyData, CD_NORMAL, CD_CALLOC, NULL, dm->numPolyData);
+ }
+
+ mesh_calc_normals(cddm->mvert, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm),
+ dm->numLoopData, dm->numPolyData, poly_nors);
+}
+
+void CDDM_calc_normals_tessface(DerivedMesh *dm)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
float (*face_nors)[3];
if(dm->numVertData == 0) return;
@@ -1902,17 +2357,204 @@ void CDDM_calc_normals(DerivedMesh *dm)
/* we don't want to overwrite any referenced layers */
cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
- /* make a face normal layer if not present */
+ /* fill in if it exists */
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);
+ if (!face_nors) {
+ face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC, NULL, dm->numTessFaceData);
+ }
- /* calculate face normals */
- mesh_calc_normals(cddm->mvert, dm->numVertData, CDDM_get_faces(dm), dm->numFaceData, face_nors);
+ mesh_calc_normals_tessface(cddm->mvert, dm->numVertData,
+ cddm->mface, dm->numTessFaceData, face_nors);
}
-void CDDM_calc_edges(DerivedMesh *dm)
+#if 1
+/* 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 frees dm, and returns a new one.
+ *
+ * this is a really horribly written function. ger. - joeedh
+ *
+ * note, CDDM_recalc_tesselation has to run on the returned DM if you want to access tessfaces.
+ */
+DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ CDDerivedMesh *cddm2 = NULL;
+ MVert *mv, *mvert = NULL;
+ BLI_array_declare(mvert);
+ MEdge *med, *medge = NULL;
+ BLI_array_declare(medge);
+ MPoly *mp, *mpoly = NULL;
+ BLI_array_declare(mpoly);
+ MLoop *ml, *mloop = NULL;
+ BLI_array_declare(mloop);
+ EdgeHash *ehash = BLI_edgehash_new();
+ 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;
+
+ totloop = dm->numLoopData;
+ totpoly = dm->numPolyData;
+
+ 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");
+
+ /*fill newl with destination vertex indices*/
+ 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);
+ }
+ }
+
+ /*now link target vertices to destination indices*/
+ for (i=0; i<dm->numVertData; i++) {
+ if (vtargetmap[i] != -1) {
+ newv[i] = newv[vtargetmap[i]];
+ }
+ }
+
+ /*find-replace merged vertices with target vertices*/
+ ml = cddm->mloop;
+ c = 0;
+ for (i=0; i<totloop; i++, ml++) {
+ if (vtargetmap[ml->v] != -1) {
+ ml->v = vtargetmap[ml->v];
+ }
+ }
+
+ /*now go through and fix edges and faces*/
+ med = cddm->medge;
+ c = 0;
+ for (i=0; i<dm->numEdgeData; i++, med++) {
+
+ if (LIKELY(med->v1 != med->v2)) {
+ const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
+ const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
+ void **eh_p= BLI_edgehash_lookup_p(ehash, v1, v2);
+
+ if (eh_p) {
+ newe[i] = GET_INT_FROM_POINTER(*eh_p);
+ }
+ else {
+ BLI_array_append(olde, i);
+ newe[i] = c;
+ BLI_array_append(medge, *med);
+ BLI_edgehash_insert(ehash, v1, v2, SET_INT_IN_POINTER(c));
+ c++;
+ }
+ }
+ else {
+ newe[i] = -1;
+ }
+ }
+
+ 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++) {
+ med = cddm->medge + ml->e;
+ if (LIKELY(med->v1 != med->v2)) {
+ newl[j+mp->loopstart] = BLI_array_count(mloop);
+ BLI_array_append(oldl, j+mp->loopstart);
+ BLI_array_append(mloop, *ml);
+ c++;
+ }
+ }
+
+ if (UNLIKELY(c == 0)) {
+ continue;
+ }
+
+ mp2 = BLI_array_append_r(mpoly, *mp);
+ mp2->totloop = c;
+ mp2->loopstart = BLI_array_count(mloop) - c;
+
+ BLI_array_append(oldp, i);
+ }
+
+ /*create new cddm*/
+ cddm2 = (CDDerivedMesh*) CDDM_from_template((DerivedMesh*)cddm, BLI_array_count(mvert), BLI_array_count(medge), 0, BLI_array_count(mloop), BLI_array_count(mpoly));
+
+ /*update edge indices and copy customdata*/
+ med = medge;
+ for (i=0; i<cddm2->dm.numEdgeData; i++, med++) {
+ if (newv[med->v1] != -1)
+ med->v1 = newv[med->v1];
+ if (newv[med->v2] != -1)
+ med->v2 = newv[med->v2];
+
+ CustomData_copy_data(&dm->edgeData, &cddm2->dm.edgeData, olde[i], i, 1);
+ }
+
+ /*update loop indices and copy customdata*/
+ ml = mloop;
+ for (i=0; i<cddm2->dm.numLoopData; i++, ml++) {
+ if (newe[ml->e] != -1)
+ ml->e = newe[ml->e];
+ if (newv[ml->v] != -1)
+ ml->v = newv[ml->v];
+
+ CustomData_copy_data(&dm->loopData, &cddm2->dm.loopData, oldl[i], i, 1);
+ }
+
+ /*copy vertex customdata*/
+ mv = mvert;
+ for (i=0; i<cddm2->dm.numVertData; i++, mv++) {
+ CustomData_copy_data(&dm->vertData, &cddm2->dm.vertData, oldv[i], i, 1);
+ }
+
+ /*copy poly customdata*/
+ mp = mpoly;
+ for (i=0; i<cddm2->dm.numPolyData; i++, mp++) {
+ CustomData_copy_data(&dm->polyData, &cddm2->dm.polyData, oldp[i], i, 1);
+ }
+
+ /*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);
+
+ 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);
+ if (ehash)
+ BLI_edgehash_free(ehash, NULL);
+
+ /*free old derivedmesh*/
+ dm->needsFree = 1;
+ dm->release(dm);
+
+ return (DerivedMesh*)cddm2;
+}
+#endif
+
+void CDDM_calc_edges_tessface(DerivedMesh *dm)
{
CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
CustomData edgeData;
@@ -1920,7 +2562,7 @@ void CDDM_calc_edges(DerivedMesh *dm)
MFace *mf = cddm->mface;
MEdge *med;
EdgeHash *eh = BLI_edgehash_new();
- int i, *index, numEdges, maxFaces = dm->numFaceData;
+ int i, *index, numEdges, maxFaces = dm->numTessFaceData;
for (i = 0; i < maxFaces; i++, mf++) {
if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2))
@@ -1968,6 +2610,82 @@ void CDDM_calc_edges(DerivedMesh *dm)
BLI_edgehash_free(eh, NULL);
}
+/* warning, this uses existing edges but CDDM_calc_edges_tessface() doesn't */
+void CDDM_calc_edges(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, *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 = ME_POLY_LOOP_NEXT(cddm->mloop, mp, j)->v;
+ if (!BLI_edgehash_haskey(eh, v1, v2)) {
+ BLI_edgehash_insert(eh, v1, v2, NULL);
+ }
+ }
+ }
+
+ 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, &med->v1, &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 = ME_POLY_LOOP_NEXT(cddm->mloop, mp, j)->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)
@@ -1984,14 +2702,24 @@ void CDDM_lower_num_edges(DerivedMesh *dm, int numEdges)
dm->numEdgeData = numEdges;
}
-void CDDM_lower_num_faces(DerivedMesh *dm, int numFaces)
+void CDDM_lower_num_tessfaces(DerivedMesh *dm, int numTessFaces)
{
- if (numFaces < dm->numFaceData)
- CustomData_free_elem(&dm->faceData, numFaces, dm->numFaceData-numFaces);
+ if (numTessFaces < dm->numTessFaceData)
+ CustomData_free_elem(&dm->faceData, numTessFaces, dm->numTessFaceData-numTessFaces);
- dm->numFaceData = numFaces;
+ dm->numTessFaceData = numTessFaces;
}
+void CDDM_lower_num_polys(DerivedMesh *dm, int numPolys)
+{
+ if (numPolys < dm->numPolyData)
+ CustomData_free_elem(&dm->polyData, numPolys, dm->numPolyData-numPolys);
+
+ dm->numPolyData = numPolys;
+}
+
+/* mesh element access functions */
+
MVert *CDDM_get_vert(DerivedMesh *dm, int index)
{
return &((CDDerivedMesh*)dm)->mvert[index];
@@ -2002,11 +2730,23 @@ 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];
}
+MLoop *CDDM_get_loop(DerivedMesh *dm, int index)
+{
+ return &((CDDerivedMesh*)dm)->mloop[index];
+}
+
+MPoly *CDDM_get_poly(DerivedMesh *dm, int index)
+{
+ return &((CDDerivedMesh*)dm)->mpoly[index];
+}
+
+/* array access functions */
+
MVert *CDDM_get_verts(DerivedMesh *dm)
{
return ((CDDerivedMesh*)dm)->mvert;
@@ -2017,8 +2757,127 @@ 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;
}
+MLoop *CDDM_get_loops(DerivedMesh *dm)
+{
+ return ((CDDerivedMesh*)dm)->mloop;
+}
+
+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;
+ EdgeHash *eh = BLI_edgehash_new();
+ int i, totloop;
+
+ /*ensure we have all the edges we need*/
+ CDDM_calc_edges_tessface(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.numTessFaceData; 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.numTessFaceData;
+
+ if (totloop) {
+ MLoop *ml;
+ MPoly *mp;
+ int l, *polyindex;
+
+ cddm->mloop = MEM_callocN(sizeof(MLoop)*totloop, "cddm->mloop in CDDM_tessfaces_to_faces");
+ cddm->mpoly = MEM_callocN(sizeof(MPoly)*cddm->dm.numTessFaceData, "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.numTessFaceData);
+
+ polyindex = CustomData_get_layer(&cddm->dm.faceData, CD_POLYINDEX);
+
+ mf = cddm->mface;
+ mp = cddm->mpoly;
+ ml = cddm->mloop;
+ l = 0;
+ for (i=0; i<cddm->dm.numTessFaceData; 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++;
+ }
+
+ *polyindex = i;
+ }
+ }
+
+ BLI_edgehash_free(eh, NULL);
+}
+
+void CDDM_set_mvert(DerivedMesh *dm, MVert *mvert)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+
+ if (!CustomData_has_layer(&dm->vertData, CD_MVERT))
+ CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, mvert, dm->numVertData);
+
+ cddm->mvert = mvert;
+}
+
+void CDDM_set_medge(DerivedMesh *dm, MEdge *medge)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+
+ if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE))
+ CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, medge, dm->numEdgeData);
+
+ cddm->medge = medge;
+}
+
+void CDDM_set_mface(DerivedMesh *dm, MFace *mface)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+
+ if (!CustomData_has_layer(&dm->faceData, CD_MFACE))
+ CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, mface, dm->numTessFaceData);
+
+ cddm->mface = mface;
+}
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 1beaa59baad..e2d12c04bf2 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -35,6 +35,7 @@
#include "DNA_object_types.h"
#include "DNA_meshdata_types.h"
+#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_edgehash.h"
#include "BLI_utildefines.h"
@@ -930,8 +931,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. */
@@ -1043,9 +1044,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/collision.c b/source/blender/blenkernel/intern/collision.c
index 456c0c9fe3b..10a955760f0 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -42,6 +42,7 @@
#include "DNA_scene_types.h"
#include "DNA_meshdata_types.h"
+#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_edgehash.h"
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index ad89a9c959f..4f3fc40616b 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -77,8 +77,12 @@
#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"
+#include "BKE_tracking.h"
+#include "BKE_movieclip.h"
#include "BKE_tracking.h"
#include "BKE_movieclip.h"
@@ -421,7 +425,7 @@ static void contarget_get_mesh_mat (Object *ob, const char *substring, float mat
{
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];
@@ -437,7 +441,7 @@ static void contarget_get_mesh_mat (Object *ob, const char *substring, float mat
/* 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, FALSE, FALSE);
freeDM= 1;
}
else {
@@ -511,8 +515,6 @@ static void contarget_get_mesh_mat (Object *ob, const char *substring, float mat
/* 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 */
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index f840774222a..a4c1fd87009 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -44,6 +44,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_ID.h"
+#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_linklist.h"
#include "BLI_math.h"
@@ -54,9 +55,13 @@
#include "BKE_customdata_file.h"
#include "BKE_global.h"
#include "BKE_main.h"
-#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
@@ -440,6 +445,23 @@ static void layerSwap_mdisps(void *data, const int *ci)
}
}
+#if 1 /* BMESH_TODO: place holder function, dont actually interp */
+static void layerInterp_mdisps(void **sources, float *UNUSED(weights),
+ float *UNUSED(sub_weights), int UNUSED(count), void *dest)
+{
+ MDisps *d = dest;
+
+ /* happens when flipping normals of newly created mesh */
+ if(!d->totdisp) {
+ d->totdisp = ((MDisps*)sources[0])->totdisp;
+ }
+
+ if (!d->disps && d->totdisp)
+ d->disps = MEM_callocN(sizeof(float)*3*d->totdisp, "blank mdisps in layerInterp_mdisps");
+}
+
+#else // BMESH_TODO
+
static void layerInterp_mdisps(void **sources, float *UNUSED(weights),
float *sub_weights, int count, void *dest)
{
@@ -552,6 +574,7 @@ static void layerInterp_mdisps(void **sources, float *UNUSED(weights),
MEM_freeN(d->disps);
d->disps = disps;
}
+#endif // BMESH_TODO
static void layerCopy_mdisps(const void *source, void *dest, int count)
{
@@ -574,6 +597,10 @@ static void layerCopy_mdisps(const void *source, void *dest, int count)
static void layerValidate_mdisps(void *data, int sub_elements)
{
+#if 1 /*BMESH_TODO*/
+ (void)data;
+ (void)sub_elements;
+#else
MDisps *disps = data;
if(disps->disps) {
int corners = multires_mdisp_corners(disps);
@@ -584,6 +611,7 @@ static void layerValidate_mdisps(void *data, int sub_elements)
disps->disps = MEM_callocN(3*disps->totdisp*sizeof(float), "layerValidate_mdisps");
}
}
+#endif
}
static void layerFree_mdisps(void *data, int count, int UNUSED(size))
@@ -843,6 +871,77 @@ static void layerInterp_mloopuv(void **sources, float *weights,
}
}
+/* origspace is almost exact copy of mloopuv's, keep in sync */
+static void layerCopyValue_mloop_origspace(void *source, void *dest)
+{
+ OrigSpaceLoop *luv1 = source, *luv2 = dest;
+
+ copy_v2_v2(luv2->uv, luv1->uv);
+}
+
+static int layerEqual_mloop_origspace(void *data1, void *data2)
+{
+ OrigSpaceLoop *luv1 = data1, *luv2 = data2;
+
+ return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f;
+}
+
+static void layerMultiply_mloop_origspace(void *data, float fac)
+{
+ OrigSpaceLoop *luv = data;
+
+ mul_v2_fl(luv->uv, fac);
+}
+
+static void layerInitMinMax_mloop_origspace(void *vmin, void *vmax)
+{
+ OrigSpaceLoop *min = vmin, *max = vmax;
+
+ INIT_MINMAX2(min->uv, max->uv);
+}
+
+static void layerDoMinMax_mloop_origspace(void *data, void *vmin, void *vmax)
+{
+ OrigSpaceLoop *min = vmin, *max = vmax, *luv = data;
+
+ DO_MINMAX2(luv->uv, min->uv, max->uv);
+}
+
+static void layerAdd_mloop_origspace(void *data1, void *data2)
+{
+ OrigSpaceLoop *l1 = data1, *l2 = data2;
+
+ add_v2_v2(l1->uv, l2->uv);
+}
+
+static void layerInterp_mloop_origspace(void **sources, float *weights,
+ float *sub_weights, int count, void *dest)
+{
+ OrigSpaceLoop *mluv = dest;
+ float *uv= mluv->uv;
+ int i;
+
+ zero_v2(uv);
+
+ if (sub_weights) {
+ const float *sub_weight = sub_weights;
+ for(i = 0; i < count; i++) {
+ float weight = weights ? weights[i] : 1.0f;
+ OrigSpaceLoop *src = sources[i];
+ madd_v2_v2fl(uv, src->uv, (*sub_weight) * weight);
+ sub_weight++;
+ }
+ }
+ else {
+ for(i = 0; i < count; i++) {
+ float weight = weights ? weights[i] : 1;
+ OrigSpaceLoop *src = sources[i];
+ madd_v2_v2fl(uv, src->uv, weight);
+ }
+ }
+}
+/* --- end copy */
+
static void layerInterp_mcol(void **sources, float *weights,
float *sub_weights, int count, void *dest)
{
@@ -992,7 +1091,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
/* 8: CD_NORMAL */
/* 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},
/* 9: CD_POLYINDEX */
{sizeof(int), "MIntProperty", 1, NULL, NULL, NULL, NULL, NULL, NULL},
/* 10: CD_PROP_FLT */
@@ -1037,9 +1136,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 24: CD_RECAST */
{sizeof(MRecast), "MRecast", 1,"Recast",NULL,NULL,NULL,NULL}
-#ifdef USE_BMESH_FORWARD_COMPAT
- ,
/* BMESH ONLY */
+ ,
/* 25: CD_MPOLY */
{sizeof(MPoly), "MPoly", 1, "NGon Face", NULL, NULL, NULL, NULL, NULL},
/* 26: CD_MLOOP */
@@ -1052,16 +1150,21 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(float), "", 0, "BevelWeight", NULL, NULL, layerInterp_bweight},
/* 30: CD_CREASE */
{sizeof(float), "", 0, "SubSurfCrease", NULL, NULL, layerInterp_bweight},
- /* 31: CD_WEIGHT_MLOOPCOL */
+ /* 31: CD_ORIGSPACE_MLOOP */
+ {sizeof(OrigSpaceLoop), "OrigSpaceLoop", 1, "OS Loop", NULL, NULL, layerInterp_mloop_origspace, NULL, NULL,
+ layerEqual_mloop_origspace, layerMultiply_mloop_origspace, layerInitMinMax_mloop_origspace,
+ layerAdd_mloop_origspace, layerDoMinMax_mloop_origspace, layerCopyValue_mloop_origspace},
+ /* 32: CD_WEIGHT_MLOOPCOL */
{sizeof(MLoopCol), "MLoopCol", 1, "WeightLoopCol", NULL, NULL, layerInterp_mloopcol, NULL,
layerDefault_mloopcol, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol,
layerAdd_mloopcol, layerDoMinMax_mloopcol, layerCopyValue_mloopcol},
/* END BMESH ONLY */
-#endif /* USE_BMESH_FORWARD_COMPAT */
};
+/* note, numbers are from trunk and need updating for bmesh */
+
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 0-4 */ "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace",
/* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags",
@@ -1069,29 +1172,38 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 15-19 */ "CDMTexPoly", "CDMLoopUV", "CDMloopCol", "CDTangent", "CDMDisps",
/* 20-24 */"CDWeightMCol", "CDIDMCol", "CDTextureMCol", "CDClothOrco", "CDMRecast"
-#ifdef USE_BMESH_FORWARD_COMPAT
+/* BMESH ONLY */
,
/* 25-29 */ "CDMPoly", "CDMLoop", "CDShapeKeyIndex", "CDShapeKey", "CDBevelWeight",
- /* 30-31 */ "CDSubSurfCrease", "CDWeightLoopCol"
+ /* 30-32 */ "CDSubSurfCrease", "CDOrigSpaceLoop", "CDWeightLoopCol"
+/* END BMESH ONLY */
-#endif /* USE_BMESH_FORWARD_COMPAT */
};
+
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_RECAST;
+ 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_RECAST;
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_RECAST;
+ 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 | CD_MASK_RECAST;
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 | CD_MASK_RECAST;
-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_MCOL | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_CLOTH_ORCO |
+ CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_WEIGHT_MLOOPCOL |
+ CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_ORCO | CD_MASK_TANGENT |
+ CD_MASK_WEIGHT_MCOL | CD_MASK_NORMAL | CD_MASK_SHAPEKEY | CD_MASK_RECAST |
+ CD_MASK_ORIGINDEX | CD_MASK_POLYINDEX;
+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;
@@ -1140,6 +1252,7 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
{
/*const LayerTypeInfo *typeInfo;*/
CustomDataLayer *layer, *newlayer;
+ void *data;
int i, type, number = 0, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0, lastflag = 0;
for(i = 0; i < source->totlayer; ++i) {
@@ -1164,14 +1277,27 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
else if(!(mask & CD_TYPE_AS_MASK(type))) continue;
else if(number < CustomData_number_of_layers(dest, type)) continue;
+ switch (alloctype) {
+ case CD_ASSIGN:
+ case CD_REFERENCE:
+ case CD_DUPLICATE:
+ data = layer->data;
+ break;
+ default:
+ data = NULL;
+ break;
+ }
+
if((alloctype == CD_ASSIGN) && (lastflag & CD_FLAG_NOFREE))
newlayer = customData_add_layer__internal(dest, type, CD_REFERENCE,
- layer->data, totelem, layer->name);
+ data, totelem, layer->name);
else
newlayer = customData_add_layer__internal(dest, type, alloctype,
- layer->data, totelem, layer->name);
+ data, totelem, layer->name);
if(newlayer) {
+ newlayer->uid = layer->uid;
+
newlayer->active = lastactive;
newlayer->active_rnd = lastrender;
newlayer->active_clone = lastclone;
@@ -1473,7 +1599,14 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
{
const LayerTypeInfo *typeInfo= layerType_getInfo(type);
int size = typeInfo->size * totelem, flag = 0, index = data->totlayer;
- void *newlayerdata;
+ void *newlayerdata = NULL;
+
+ /* Passing a layerdata to copy from with an alloctype that won't copy is
+ most likely a bug */
+ BLI_assert(!layerdata ||
+ (alloctype == CD_ASSIGN) ||
+ (alloctype == CD_DUPLICATE) ||
+ (alloctype == CD_REFERENCE));
if (!typeInfo->defaultname && CustomData_has_layer(data, type))
return &data->layers[CustomData_get_layer_index(data, type)];
@@ -1481,13 +1614,13 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
if((alloctype == CD_ASSIGN) || (alloctype == CD_REFERENCE)) {
newlayerdata = layerdata;
}
- else {
+ else if (size > 0) {
newlayerdata = MEM_callocN(size, layerType_getName(type));
if(!newlayerdata)
return NULL;
}
- if (alloctype == CD_DUPLICATE) {
+ if (alloctype == CD_DUPLICATE && layerdata) {
if(typeInfo->copy)
typeInfo->copy(layerdata, newlayerdata, totelem);
else
@@ -2304,35 +2437,142 @@ 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);
+ for(i=0; i < fdata->totlayer; i++) {
+ if(fdata->layers[i].type == CD_MTFACE) {
+ CustomData_add_layer_named(pdata, CD_MTEXPOLY, CD_CALLOC, NULL, totpoly, fdata->layers[i].name);
+ CustomData_add_layer_named(ldata, CD_MLOOPUV, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ }
+ else if (fdata->layers[i].type == CD_MCOL) {
+ CustomData_add_layer_named(ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
}
- else if(fdata->layers[i].type == CD_MCOL)
- CustomData_add_layer(ldata, CD_MLOOPCOL, CD_CALLOC, &(fdata->layers[i].name), 0);
- }
+ else if (fdata->layers[i].type == CD_MDISPS) {
+ CustomData_add_layer_named(ldata, CD_MDISPS, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ }
+ }
}
+
void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, int total)
{
int i;
- for(i=0; i < pdata->totlayer; i++){
- if(pdata->layers[i].type == CD_MTEXPOLY)
- CustomData_add_layer(fdata, CD_MTFACE, CD_CALLOC, &(pdata->layers[i].name), total);
+ for(i=0; i < pdata->totlayer; i++) {
+ if (pdata->layers[i].type == CD_MTEXPOLY) {
+ CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, pdata->layers[i].name);
+ }
}
- 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);
+ for(i=0; i < ldata->totlayer; i++) {
+ if (ldata->layers[i].type == CD_MLOOPCOL) {
+ CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ }
+ else if (ldata->layers[i].type == CD_WEIGHT_MLOOPCOL) {
+ CustomData_add_layer_named(fdata, CD_WEIGHT_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ }
+ else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) {
+ CustomData_add_layer_named(fdata, CD_ORIGSPACE, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ }
}
}
+void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *pdata, CustomData *ldata)
+{
+ int act;
+
+ if (CustomData_has_layer(pdata, CD_MTEXPOLY)) {
+ act = CustomData_get_active_layer(pdata, CD_MTEXPOLY);
+ CustomData_set_layer_active(ldata, CD_MLOOPUV, act);
+ CustomData_set_layer_active(fdata, CD_MTFACE, act);
+
+ act = CustomData_get_render_layer(pdata, CD_MTEXPOLY);
+ CustomData_set_layer_render(ldata, CD_MLOOPUV, act);
+ CustomData_set_layer_render(fdata, CD_MTFACE, act);
+
+ act = CustomData_get_clone_layer(pdata, CD_MTEXPOLY);
+ CustomData_set_layer_clone(ldata, CD_MLOOPUV, act);
+ CustomData_set_layer_clone(fdata, CD_MTFACE, act);
+
+ act = CustomData_get_stencil_layer(pdata, CD_MTEXPOLY);
+ CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act);
+ CustomData_set_layer_stencil(fdata, CD_MTFACE, act);
+ }
+
+ if (CustomData_has_layer(ldata, CD_MLOOPCOL)) {
+ act = CustomData_get_active_layer(ldata, CD_MLOOPCOL);
+ CustomData_set_layer_active(fdata, CD_MCOL, act);
+
+ act = CustomData_get_render_layer(ldata, CD_MLOOPCOL);
+ CustomData_set_layer_render(fdata, CD_MCOL, act);
+
+ act = CustomData_get_clone_layer(ldata, CD_MLOOPCOL);
+ CustomData_set_layer_clone(fdata, CD_MCOL, act);
+
+ act = CustomData_get_stencil_layer(ldata, CD_MLOOPCOL);
+ CustomData_set_layer_stencil(fdata, CD_MCOL, act);
+ }
+}
void CustomData_bmesh_init_pool(CustomData *data, int allocsize)
{
- if(data->totlayer)data->pool = BLI_mempool_create(data->totsize, allocsize, allocsize, FALSE, FALSE);
+ /* Dispose old pools before calling here to avoid leaks */
+ BLI_assert(data->pool == NULL);
+
+ /* If there are no layers, no pool is needed just yet */
+ if (data->totlayer) {
+ data->pool = BLI_mempool_create(data->totsize, allocsize, allocsize, TRUE, FALSE);
+ }
+}
+
+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;
+ default: /* should never happen */
+ BLI_assert(!"invalid type given");
+ t = BM_VERTS_OF_MESH;
+ }
+
+ 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)
@@ -2352,7 +2592,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;
}
@@ -2363,7 +2605,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;
}
@@ -2444,6 +2686,73 @@ void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
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)
{
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index b14b9b43cf3..2a971c45232 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -432,6 +432,8 @@ void filldisplist(ListBase *dispbase, ListBase *to, int flipnormal)
totvert= 0;
nextcol= 0;
+ BLI_begin_edgefill();
+
dl= dispbase->first;
while(dl) {
@@ -890,7 +892,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispba
dm = tdm;
CDDM_apply_vert_coords(dm, vertCos);
- CDDM_calc_normals(dm);
+ CDDM_calc_normals_mapping(dm);
}
} else {
if (vertCos) {
@@ -903,7 +905,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispba
dm= CDDM_from_curve_customDB(ob, dispbase);
- CDDM_calc_normals(dm);
+ CDDM_calc_normals_mapping(dm);
}
if (vertCos) {
@@ -931,7 +933,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispba
dm = tdm;
CDDM_apply_vert_coords(dm, vertCos);
- CDDM_calc_normals(dm);
+ CDDM_calc_normals_mapping(dm);
MEM_freeN(vertCos);
} else {
displist_apply_allverts(dispbase, vertCos);
@@ -941,6 +943,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispba
}
if (derivedFinal) {
+ if (dm) DM_ensure_tessface(dm); /* needed for drawing */
(*derivedFinal) = dm;
}
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index cdfd5d3562b..9a8946ae61e 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -1227,6 +1227,7 @@ static int surface_usesAdjData(DynamicPaintSurface *surface)
static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int force_init)
{
PaintSurfaceData *sData = surface->data;
+ DerivedMesh *dm = surface->canvas->dm;
PaintAdjData *ad;
int *temp_data;
int neigh_points = 0;
@@ -1235,7 +1236,7 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
/* For vertex format, neighbours are connected by edges */
- neigh_points = 2*surface->canvas->dm->getNumEdges(surface->canvas->dm);
+ neigh_points = 2*dm->getNumEdges(dm);
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
neigh_points = sData->total_points*8;
@@ -1265,10 +1266,11 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
int n_pos;
/* For vertex format, count every vertex that is connected by an edge */
- int numOfEdges = surface->canvas->dm->getNumEdges(surface->canvas->dm);
- int numOfFaces = surface->canvas->dm->getNumFaces(surface->canvas->dm);
- struct MEdge *edge = surface->canvas->dm->getEdgeArray(surface->canvas->dm);
- struct MFace *face = surface->canvas->dm->getFaceArray(surface->canvas->dm);
+ int numOfEdges = dm->getNumEdges(dm);
+ int numOfPolys = dm->getNumPolys(dm);
+ struct MEdge *edge = dm->getEdgeArray(dm);
+ struct MPoly *mpoly = dm->getPolyArray(dm);
+ struct MLoop *mloop = dm->getLoopArray(dm);
/* count number of edges per vertex */
for (i=0; i<numOfEdges; i++) {
@@ -1281,12 +1283,11 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
/* also add number of vertices to temp_data
* to locate points on "mesh edge" */
- for (i=0; i<numOfFaces; i++) {
- temp_data[face[i].v1]++;
- temp_data[face[i].v2]++;
- temp_data[face[i].v3]++;
- if (face[i].v4)
- temp_data[face[i].v4]++;
+ for (i=0; i<numOfPolys; i++) {
+ int j=0;
+ for (; j<mpoly[i].totloop; j++) {
+ temp_data[mloop[mpoly[i].loopstart + j].v]++;
+ }
}
/* now check if total number of edges+faces for
@@ -1355,8 +1356,8 @@ void dynamicPaint_setInitialColor(DynamicPaintSurface *surface)
else if (surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) {
Tex *tex = surface->init_texture;
MTFace *tface;
- MFace *mface = dm->getFaceArray(dm);
- int numOfFaces = dm->getNumFaces(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
+ int numOfFaces = dm->getNumTessFaces(dm);
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
if (!tex) return;
@@ -1425,31 +1426,27 @@ void dynamicPaint_setInitialColor(DynamicPaintSurface *surface)
}
/* vertex color layer */
else if (surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) {
- MCol *col = CustomData_get_layer_named(&dm->faceData, CD_MCOL, surface->init_layername);
- if (!col) return;
/* for vertex surface, just copy colors from mcol */
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- MFace *mface = dm->getFaceArray(dm);
- int numOfFaces = dm->getNumFaces(dm);
+ MLoop *mloop = dm->getLoopArray(dm);
+ int numOfLoops = dm->getNumLoops(dm);
+ MCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername);
+ if (!col) return;
#pragma omp parallel for schedule(static)
- for (i=0; i<numOfFaces; i++) {
- int numOfVert = (mface[i].v4) ? 4 : 3;
- int j;
- for (j=0; j<numOfVert; j++) {
- unsigned int *vert = ((&mface[i].v1)+j);
-
- pPoint[*vert].color[0] = 1.0f/255.f*(float)col[i*4+j].b;
- pPoint[*vert].color[1] = 1.0f/255.f*(float)col[i*4+j].g;
- pPoint[*vert].color[2] = 1.0f/255.f*(float)col[i*4+j].r;
- pPoint[*vert].alpha = 1.0f/255.f*(float)col[i*4+j].a;
- }
+ for (i=0; i<numOfLoops; i++) {
+ pPoint[mloop[i].v].color[0] = 1.0f/255.f*(float)col[i].b;
+ pPoint[mloop[i].v].color[1] = 1.0f/255.f*(float)col[i].g;
+ pPoint[mloop[i].v].color[2] = 1.0f/255.f*(float)col[i].r;
+ pPoint[mloop[i].v].alpha = 1.0f/255.f*(float)col[i].a;
}
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
ImgSeqFormatData *f_data = (ImgSeqFormatData*)sData->format_data;
int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ MCol *col = CustomData_get_layer_named(&dm->faceData, CD_MCOL, surface->init_layername);
+ if (!col) return;
#pragma omp parallel for schedule(static)
for (i=0; i<sData->total_points; i++) {
@@ -1595,11 +1592,11 @@ static struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData
/* vertex color paint */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- MFace *mface = result->getFaceArray(result);
- int numOfFaces = result->getNumFaces(result);
int i;
PaintPoint* pPoint = (PaintPoint*)sData->type_data;
- MCol *col;
+ MLoopCol *col = NULL;
+ MLoop *mloop = CDDM_get_loops(result);
+ int totloop = result->numLoopData;
/* paint is stored on dry and wet layers, so mix final color first */
float *fcolor = MEM_callocN(sizeof(float)*sData->total_points*4, "Temp paint color");
@@ -1612,26 +1609,37 @@ static struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData
/* viewport preview */
if (surface->flags & MOD_DPAINT_PREVIEW) {
- /* Save preview results to weight layer, to be
+ MPoly *mp = CDDM_get_polys(result);
+ int totpoly = result->numPolyData;
+
+ /* XXX We have to create a CD_WEIGHT_MCOL, else it might sigsev
+ * (after a SubSurf mod, eg)... */
+ if(!result->getTessFaceDataArray(result, CD_WEIGHT_MCOL)) {
+ int numFaces = result->getNumTessFaces(result);
+ CustomData_add_layer(&result->faceData, CD_WEIGHT_MCOL, CD_CALLOC, NULL, numFaces);
+ }
+
+ /* Save preview results to weight layer to be
* able to share same drawing methods */
- col = result->getFaceDataArray(result, CD_WEIGHT_MCOL);
- if (!col) col = CustomData_add_layer(&result->faceData, CD_WEIGHT_MCOL, CD_CALLOC, NULL, numOfFaces);
+ col = CustomData_get_layer(&result->loopData, CD_WEIGHT_MLOOPCOL);
+ if (!col) col = CustomData_add_layer(&result->loopData, CD_WEIGHT_MLOOPCOL, CD_CALLOC, NULL, totloop);
if (col) {
#pragma omp parallel for schedule(static)
- for (i=0; i<numOfFaces; i++) {
- int j = (mface[i].v4) ? 4 : 3;
- Material *material = give_current_material(ob, mface[i].mat_nr+1);
+ for (i=0; i<totpoly; i++) {
+ int j=0;
+ Material *material = give_current_material(ob, mp[i].mat_nr+1);
- while (j--) {
- int index = *((&mface[i].v1)+j);
+ for (; j<mp[i].totloop; j++) {
+ int l_index = mp[i].loopstart + j;
+ int v_index = mloop[l_index].v;
if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) {
float c[3];
- index *= 4;
+ v_index *= 4;
/* Apply material color as base vertex color for preview */
- col[i*4+j].a = 255;
+ col[l_index].a = 255;
if (material) {
c[0] = material->r;
c[1] = material->g;
@@ -1643,17 +1651,17 @@ static struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData
c[2] = 0.65f;
}
/* mix surface color */
- interp_v3_v3v3(c, c, &fcolor[index], fcolor[index+3]);
+ interp_v3_v3v3(c, c, &fcolor[v_index], fcolor[v_index+3]);
- col[i*4+j].r = FTOCHAR(c[2]);
- col[i*4+j].g = FTOCHAR(c[1]);
- col[i*4+j].b = FTOCHAR(c[0]);
+ col[l_index].r = FTOCHAR(c[2]);
+ col[l_index].g = FTOCHAR(c[1]);
+ col[l_index].b = FTOCHAR(c[0]);
}
else {
- col[i*4+j].a = 255;
- col[i*4+j].r =
- col[i*4+j].g =
- col[i*4+j].b = FTOCHAR(pPoint[index].wetness);
+ col[l_index].a = 255;
+ col[l_index].r =
+ col[l_index].g =
+ col[l_index].b = FTOCHAR(pPoint[v_index].wetness);
}
}
}
@@ -1664,46 +1672,38 @@ static struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData
/* save layer data to output layer */
/* paint layer */
- col = CustomData_get_layer_named(&result->faceData, CD_MCOL, surface->output_name);
+ col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
/* if output layer is lost from a constructive modifier, re-add it */
if (!col && dynamicPaint_outputLayerExists(surface, ob, 0))
- col = CustomData_add_layer_named(&result->faceData, CD_MCOL, CD_CALLOC, NULL, numOfFaces, surface->output_name);
+ col = CustomData_add_layer_named(&result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
/* apply color */
if (col) {
#pragma omp parallel for schedule(static)
- for (i=0; i<numOfFaces; i++) {
- int j = (mface[i].v4) ? 4 : 3;
- while (j--) {
- int index = *((&mface[i].v1)+j);
- index *= 4;
-
- col[i*4+j].a = FTOCHAR(fcolor[index+3]);
- col[i*4+j].r = FTOCHAR(fcolor[index+2]);
- col[i*4+j].g = FTOCHAR(fcolor[index+1]);
- col[i*4+j].b = FTOCHAR(fcolor[index]);
- }
+ for (i=0; i<totloop; i++) {
+ int index = mloop[i].v*4;
+ col[i].a = FTOCHAR(fcolor[index+3]);
+ col[i].r = FTOCHAR(fcolor[index+2]);
+ col[i].g = FTOCHAR(fcolor[index+1]);
+ col[i].b = FTOCHAR(fcolor[index]);
}
}
MEM_freeN(fcolor);
/* wet layer */
- col = CustomData_get_layer_named(&result->faceData, CD_MCOL, surface->output_name2);
+ col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name2);
/* if output layer is lost from a constructive modifier, re-add it */
if (!col && dynamicPaint_outputLayerExists(surface, ob, 1))
- col = CustomData_add_layer_named(&result->faceData, CD_MCOL, CD_CALLOC, NULL, numOfFaces, surface->output_name2);
+ col = CustomData_add_layer_named(&result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
/* apply color */
if (col) {
#pragma omp parallel for schedule(static)
- for (i=0; i<numOfFaces; i++) {
- int j = (mface[i].v4) ? 4 : 3;
- while (j--) {
- int index = *((&mface[i].v1)+j);
- col[i*4+j].a = 255;
- col[i*4+j].r =
- col[i*4+j].g =
- col[i*4+j].b = FTOCHAR(pPoint[index].wetness);
- }
+ for (i=0; i<totloop; i++) {
+ int index = mloop[i].v;
+ col[i].a = 255;
+ col[i].r =
+ col[i].g =
+ col[i].b = FTOCHAR(pPoint[index].wetness);
}
}
}
@@ -1712,9 +1712,10 @@ static struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData
int defgrp_index = defgroup_name_index(ob, surface->output_name);
MDeformVert *dvert = result->getVertDataArray(result, CD_MDEFORMVERT);
float *weight = (float*)sData->type_data;
+
/* viewport preview */
if (surface->flags & MOD_DPAINT_PREVIEW) {
- /* Save preview results to weight layer, to be
+ /* Save preview results to weight layer to be
* able to share same drawing methods */
DM_update_weight_mcol(ob, result, 0, weight, 0, NULL);
}
@@ -1873,6 +1874,10 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene
/* Modifier call. Processes dynamic paint modifier step. */
struct DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
{
+ /* For now generate tessfaces in every case
+ * XXX - move/remove when most of dpaint functions are converted to use bmesh types */
+ DM_ensure_tessface(dm);
+
/* Update canvas data for a new frame */
dynamicPaint_frameUpdate(pmd, scene, ob, dm);
@@ -1945,8 +1950,8 @@ static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh
* TODO: Implement something more accurate / optimized?
*/
{
- int numOfFaces = dm->getNumFaces(dm);
- MFace *mface = dm->getFaceArray(dm);
+ int numOfFaces = dm->getNumTessFaces(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
MTFace *tface = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname);
/* Get closest edge to that subpixel on UV map */
@@ -2112,8 +2117,8 @@ int dynamicPaint_createUVSurface(DynamicPaintSurface *surface)
if (!dm) return setError(canvas, "Canvas mesh not updated.");
if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ) return setError(canvas, "Can't bake non-\"image sequence\" formats.");
- numOfFaces = dm->getNumFaces(dm);
- mface = dm->getFaceArray(dm);
+ numOfFaces = dm->getNumTessFaces(dm);
+ mface = dm->getTessFaceArray(dm);
/* get uv map */
CustomData_validate_layer_name(&dm->faceData, CD_MTFACE, surface->uvlayer_name, uvname);
@@ -2708,7 +2713,7 @@ static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats)
void dynamicPaint_doMaterialTex(BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb, const float volume_co[3], const float surface_co[3], int faceIndex, short isQuad, DerivedMesh *orcoDm)
{
Material *mat = bMats->mat;
- MFace *mface = orcoDm->getFaceArray(orcoDm);
+ MFace *mface = orcoDm->getTessFaceArray(orcoDm);
/* If no material defined, use the one assigned to the mesh face */
if (mat == NULL) {
@@ -3147,7 +3152,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
dm = CDDM_copy(brush->dm);
mvert = dm->getVertArray(dm);
- mface = dm->getFaceArray(dm);
+ mface = dm->getTessFaceArray(dm);
numOfVerts = dm->getNumVerts(dm);
/* Transform collider vertices to global space
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index cae60c22627..ee06600dab6 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -29,6 +29,10 @@
* \ingroup bke
*/
+#include <string.h>
+#include <limits.h>
+#include <math.h>
+
#include "GL/glew.h"
#include "BLI_utildefines.h"
@@ -55,24 +59,312 @@
#include "GPU_extensions.h"
#include "GPU_material.h"
-#include <string.h>
-#include <limits.h>
-#include <math.h>
+/* bmesh */
+#include "BKE_tessmesh.h"
+#include "BLI_array.h"
+#include "BLI_scanfill.h"
+
+#include "bmesh.h"
+/* end bmesh */
extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */
+
+BMEditMesh *BMEdit_Create(BMesh *bm, int do_tesselate)
+{
+ BMEditMesh *tm = MEM_callocN(sizeof(BMEditMesh), __func__);
+
+ tm->bm = bm;
+ if (do_tesselate) {
+ BMEdit_RecalcTesselation(tm);
+ }
+
+ return tm;
+}
+
+BMEditMesh *BMEdit_Copy(BMEditMesh *tm)
+{
+ BMEditMesh *tm2 = MEM_callocN(sizeof(BMEditMesh), __func__);
+ *tm2 = *tm;
+
+ tm2->derivedCage = tm2->derivedFinal = NULL;
+
+ tm2->bm = BM_mesh_copy(tm->bm);
+
+ /*The tesselation is NOT calculated on the copy here,
+ because currently all the callers of this function use
+ it to make a backup copy of the BMEditMesh to restore
+ it in the case of errors in an operation. For perf
+ reasons, in that case it makes more sense to do the
+ tesselation only when/if that copy ends up getting
+ used.*/
+ tm2->looptris = NULL;
+
+ tm2->vert_index = NULL;
+ tm2->edge_index = NULL;
+ tm2->face_index = NULL;
+
+ return tm2;
+}
+
+static void BMEdit_RecalcTesselation_intern(BMEditMesh *tm)
+{
+ /* use this to avoid locking pthread for _every_ polygon
+ * and calling the fill function */
+#define USE_TESSFACE_SPEEDUP
+
+ BMesh *bm = tm->bm;
+ BMLoop *(*looptris)[3]= NULL;
+ BLI_array_declare(looptris);
+ BMIter iter, liter;
+ BMFace *f;
+ BMLoop *l;
+ int i = 0, j;
+
+#if 0
+ /* note, we could be clever and re-use this array but would need to ensure
+ * its realloced at some point, for now just free it */
+ if (tm->looptris) MEM_freeN(tm->looptris);
+
+ /* Use tm->tottri when set, this means no reallocs while transforming,
+ * (unless scanfill fails), otherwise... */
+ /* allocate the length of totfaces, avoid many small reallocs,
+ * if all faces are tri's it will be correct, quads == 2x allocs */
+ BLI_array_reserve(looptris, (tm->tottri && tm->tottri < bm->totface * 3) ? tm->tottri : bm->totface);
+#else
+
+ /* this means no reallocs for quad dominant models, for */
+ if ( (tm->looptris != NULL) &&
+ (tm->tottri != 0) &&
+ /* (totrti <= bm->totface * 2) would be fine for all quads,
+ * but incase there are some ngons, still re-use the array */
+ (tm->tottri <= bm->totface * 3))
+ {
+ looptris = tm->looptris;
+ }
+ else {
+ if (tm->looptris) MEM_freeN(tm->looptris);
+ BLI_array_reserve(looptris, bm->totface);
+ }
+
+#endif
+
+ f = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, NULL);
+ for ( ; f; f=BM_iter_step(&iter)) {
+ /*don't consider two-edged faces*/
+ if (f->len < 3) {
+ /* do nothing */
+ }
+
+#ifdef USE_TESSFACE_SPEEDUP
+
+ /* no need to ensure the loop order, we know its ok */
+
+ else if (f->len == 3) {
+ BLI_array_growone(looptris);
+ l = BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (j=0; l; l=BM_iter_step(&liter), j++) {
+ looptris[i][j] = l;
+ }
+ i += 1;
+ }
+ else if (f->len == 4) {
+ BMLoop *ltmp[4];
+ BLI_array_growitems(looptris, 2);
+
+ l = BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (j=0; l; l=BM_iter_step(&liter), j++) {
+ ltmp[j] = l;
+ }
+
+ looptris[i][0] = ltmp[0];
+ looptris[i][1] = ltmp[1];
+ looptris[i][2] = ltmp[2];
+ i += 1;
+
+ looptris[i][0] = ltmp[0];
+ looptris[i][1] = ltmp[2];
+ looptris[i][2] = ltmp[3];
+ i += 1;
+ }
+
+#endif /* USE_TESSFACE_SPEEDUP */
+
+ else {
+ EditVert *v, *lastv=NULL, *firstv=NULL;
+ EditEdge *e;
+ EditFace *efa;
+ int totfilltri;
+
+ BLI_begin_edgefill();
+ /*scanfill time*/
+ l = BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (j=0; l; l=BM_iter_step(&liter), j++) {
+ /*mark order*/
+ BM_elem_index_set(l, j); /* set_loop */
+
+ 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);
+
+ totfilltri = BLI_edgefill(2);
+ BLI_array_growitems(looptris, totfilltri);
+
+ for (efa = fillfacebase.first; efa; efa=efa->next) {
+ BMLoop *l1= efa->v1->tmp.p;
+ BMLoop *l2= efa->v2->tmp.p;
+ BMLoop *l3= efa->v3->tmp.p;
+
+ if (BM_elem_index_get(l1) > BM_elem_index_get(l2)) { SWAP(BMLoop*, l1, l2); }
+ if (BM_elem_index_get(l2) > BM_elem_index_get(l3)) { SWAP(BMLoop*, l2, l3); }
+ if (BM_elem_index_get(l1) > BM_elem_index_get(l2)) { SWAP(BMLoop*, l1, l2); }
+
+ looptris[i][0] = l1;
+ looptris[i][1] = l2;
+ looptris[i][2] = l3;
+ i += 1;
+ }
+
+ BLI_end_edgefill();
+ }
+ }
+
+ tm->tottri = i;
+ tm->looptris = looptris;
+
+#undef USE_TESSFACE_SPEEDUP
+
+}
+
+void BMEdit_RecalcTesselation(BMEditMesh *em)
+{
+ BMEdit_RecalcTesselation_intern(em);
+
+ /* commented because editbmesh_build_data() ensures we get tessfaces */
+#if 0
+ if (em->derivedFinal && em->derivedFinal == em->derivedCage) {
+ if (em->derivedFinal->recalcTesselation)
+ em->derivedFinal->recalcTesselation(em->derivedFinal);
+ }
+ else if (em->derivedFinal) {
+ if (em->derivedCage->recalcTesselation)
+ em->derivedCage->recalcTesselation(em->derivedCage);
+ if (em->derivedFinal->recalcTesselation)
+ em->derivedFinal->recalcTesselation(em->derivedFinal);
+ }
+#endif
+}
+
+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;
+ }
+
+ 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);
+
+ if (em->bm)
+ BM_mesh_free(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 (*polyNos)[3];
+
+ /* private variables, for number of verts/edges/faces
+ * within the above hash/table members*/
+ int tv, te, tf;
+} EditDerivedBMesh;
+
+static void emDM_calcNormals(DerivedMesh *UNUSED(dm))
+{
+ /* Nothing to do: normals are already calculated and stored on the
+ BMVerts and BMFaces */
+}
+
+static void emDM_recalcTesselation(DerivedMesh *UNUSED(dm))
+{
+ /* do nothing */
+}
+
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;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMVert *eve;
+ BMIter iter;
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);
+ eve = BM_iter_new(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; i++, eve=BM_iter_step(&iter)) {
+ if (bmdm->vertexCos) {
+ func(userData, i, bmdm->vertexCos[i], bmdm->vertexNos[i], NULL);
}
else {
func(userData, i, eve->co, eve->no, NULL);
@@ -84,20 +376,24 @@ static void emDM_foreachMappedEdge(
void (*func)(void *userData, int index, float *v0co, float *v1co),
void *userData)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditEdge *eed;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEdge *eed;
+ BMIter iter;
int i;
- if (emdm->vertexCos) {
- EditVert *eve;
+ if (bmdm->vertexCos) {
+
+ BM_mesh_elem_index_ensure(bmdm->tc->bm, BM_VERT);
- 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]);
+ eed = BM_iter_new(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for (i=0; eed; i++,eed=BM_iter_step(&iter))
+ func(userData, i,
+ bmdm->vertexCos[BM_elem_index_get(eed->v1)],
+ bmdm->vertexCos[BM_elem_index_get(eed->v2)]);
}
else {
- for (i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next)
+ eed = BM_iter_new(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for (i=0; eed; i++,eed=BM_iter_step(&iter))
func(userData, i, eed->v1->co, eed->v2->co);
}
}
@@ -107,28 +403,29 @@ static void emDM_drawMappedEdges(
int (*setDrawOptions)(void *userData, int index),
void *userData)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditEdge *eed;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEdge *eed;
+ BMIter iter;
int i;
- if (emdm->vertexCos) {
- EditVert *eve;
+ if (bmdm->vertexCos) {
- for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
- eve->tmp.l = (intptr_t) i++;
+ BM_mesh_elem_index_ensure(bmdm->tc->bm, BM_VERT);
glBegin(GL_LINES);
- for (i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
+ eed = BM_iter_new(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for (i=0; eed; i++,eed=BM_iter_step(&iter)) {
if (!setDrawOptions || setDrawOptions(userData, i)) {
- glVertex3fv(emdm->vertexCos[(int) eed->v1->tmp.l]);
- glVertex3fv(emdm->vertexCos[(int) eed->v2->tmp.l]);
+ glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v1)]);
+ glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v2)]);
}
}
glEnd();
}
else {
glBegin(GL_LINES);
- for (i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
+ eed = BM_iter_new(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for (i=0; eed; i++,eed=BM_iter_step(&iter)) {
if (!setDrawOptions || setDrawOptions(userData, i)) {
glVertex3fv(eed->v1->co);
glVertex3fv(eed->v2->co);
@@ -151,30 +448,31 @@ static void emDM_drawMappedEdgesInterp(
void (*setDrawInterpOptions)(void *userData, int index, float t),
void *userData)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditEdge *eed;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEdge *eed;
+ BMIter iter;
int i;
- if (emdm->vertexCos) {
- EditVert *eve;
+ if (bmdm->vertexCos) {
- for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
- eve->tmp.l = (intptr_t) i++;
+ BM_mesh_elem_index_ensure(bmdm->tc->bm, BM_VERT);
glBegin(GL_LINES);
- for (i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
+ eed = BM_iter_new(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for (i=0; eed; i++,eed=BM_iter_step(&iter)) {
if (!setDrawOptions || setDrawOptions(userData, i)) {
setDrawInterpOptions(userData, i, 0.0);
- glVertex3fv(emdm->vertexCos[(int) eed->v1->tmp.l]);
+ glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v1)]);
setDrawInterpOptions(userData, i, 1.0);
- glVertex3fv(emdm->vertexCos[(int) eed->v2->tmp.l]);
+ glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v2)]);
}
}
glEnd();
}
else {
glBegin(GL_LINES);
- for (i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
+ eed = BM_iter_new(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for (i=0; eed; i++,eed=BM_iter_step(&iter)) {
if (!setDrawOptions || setDrawOptions(userData, i)) {
setDrawInterpOptions(userData, i, 0.0);
glVertex3fv(eed->v1->co);
@@ -188,57 +486,69 @@ static void emDM_drawMappedEdgesInterp(
static void emDM_drawUVEdges(DerivedMesh *dm)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditFace *efa;
- MTFace *tf;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEditMesh *em = bmdm->tc;
+ BMFace *efa;
+ BMIter iter;
glBegin(GL_LINES);
- for (efa= emdm->em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&emdm->em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BMIter liter;
+ BMLoop *l;
+ MLoopUV *lastluv = NULL, *firstluv = NULL;
- if (tf && !(efa->h)) {
- glVertex2fv(tf->uv[0]);
- glVertex2fv(tf->uv[1]);
+ if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
+ continue;
- glVertex2fv(tf->uv[1]);
- glVertex2fv(tf->uv[2]);
+ 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 (!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]);
+ 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 emDM__calcFaceCent(EditFace *efa, float cent[3], float (*vertexCos)[3])
+static void emDM__calcFaceCent(BMesh *bm, BMFace *efa, float cent[3], float (*vertexCos)[3])
{
+ BMIter iter;
+ BMLoop *l;
+ int tot = 0;
+
+ zero_v3(cent);
+
+ /*simple (and stupid) median (average) based method :/ */
+
if (vertexCos) {
- copy_v3_v3(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]);
+ l = BM_iter_new(&iter, bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BM_iter_step(&iter)) {
+ add_v3_v3(cent, vertexCos[BM_elem_index_get(l->v)]);
+ tot++;
+ }
}
else {
- copy_v3_v3(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);
+ l = BM_iter_new(&iter, bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BM_iter_step(&iter)) {
+ add_v3_v3(cent, l->v->co);
+ tot++;
+ }
}
- if (efa->v4) {
- mul_v3_fl(cent, 0.25f);
- }
- else {
- mul_v3_fl(cent, 0.33333333333f);
- }
+ if (tot==0) return;
+ mul_v3_fl(cent, 1.0f/(float)tot);
}
static void emDM_foreachMappedFaceCenter(
@@ -246,24 +556,28 @@ static void emDM_foreachMappedFaceCenter(
void (*func)(void *userData, int index, float *co, float *no),
void *userData)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditVert *eve;
- EditFace *efa;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ float (*polyNos)[3] = NULL;
+ BMFace *efa;
+ BMIter iter;
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++;
+ /* ensure for face center calculation */
+ if (bmdm->vertexCos) {
+ BM_mesh_elem_index_ensure(bmdm->tc->bm, BM_VERT);
+ polyNos = bmdm->polyNos;
+
+ BLI_assert(polyNos != NULL);
}
- 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);
+ efa = BM_iter_new(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL);
+ for (i=0; efa; efa=BM_iter_step(&iter), i++) {
+ emDM__calcFaceCent(bmdm->tc->bm, efa, cent, bmdm->vertexCos);
+ func(userData, i, cent, polyNos ? polyNos[i] : efa->no);
}
}
-/* note, material function is ignored for now. */
static void emDM_drawMappedFaces(
DerivedMesh *dm,
int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r),
@@ -271,8 +585,11 @@ static void emDM_drawMappedFaces(
int (*compareDrawOptions)(void *userData, int cur_index, int next_index),
void *userData, int UNUSED(useColors))
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditFace *efa;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMFace *efa;
+ struct BMLoop *(*looptris)[3]= bmdm->tc->looptris;
+ const int tottri= bmdm->tc->tottri;
+ const int lasttri= tottri - 1; /* compare agasint this a lot */
int i, draw, flush;
const int skip_normals= !glIsEnabled(GL_LIGHTING); /* could be passed as an arg */
@@ -285,21 +602,25 @@ static void emDM_drawMappedFaces(
/* currently unused -- each original face is handled separately */
(void)compareDrawOptions;
- if (emdm->vertexCos) {
+ if (bmdm->vertexCos) {
/* add direct access */
- float (*vertexCos)[3]= emdm->vertexCos;
- float (*vertexNos)[3]= emdm->vertexNos;
- float (*faceNos)[3]= emdm->faceNos;
- EditVert *eve;
+ float (*vertexCos)[3]= bmdm->vertexCos;
+ float (*vertexNos)[3]= bmdm->vertexNos;
+ float (*polyNos)[3]= bmdm->polyNos;
+ // int *triPolyMap= bmdm->triPolyMap;
- for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
- eve->tmp.l = (intptr_t) i++;
+ BM_mesh_elem_index_ensure(bmdm->tc->bm, BM_VERT | BM_FACE);
- 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);
+ for (i=0; i < tottri; i++) {
+ BMLoop **l = looptris[i];
+ int drawSmooth;
+
+ efa = l[0]->f;
+ drawSmooth= BM_elem_flag_test(efa, BM_ELEM_SMOOTH);
+
+ draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BM_elem_index_get(efa), &drawSmooth);
if (draw) {
- const GLenum poly_type= efa->v4 ? GL_QUADS:GL_TRIANGLES;
+ const GLenum poly_type= GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
if (draw==2) { /* enabled with stipple */
if (poly_prev != GL_ZERO) glEnd();
@@ -312,49 +633,43 @@ static void emDM_drawMappedFaces(
if (skip_normals) {
if (poly_type != poly_prev) {
if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev= poly_type));
+ glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
}
- glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
- if (poly_type == GL_QUADS) glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
+ glVertex3fv(vertexCos[BM_elem_index_get(l[0]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(l[1]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(l[2]->v)]);
}
else {
const GLenum shade_type= drawSmooth ? GL_SMOOTH : GL_FLAT;
if (shade_type != shade_prev) {
if (poly_prev != GL_ZERO) glEnd();
glShadeModel((shade_prev= shade_type)); /* same as below but switch shading */
- glBegin((poly_prev= poly_type));
+ glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
}
- else if (poly_type != poly_prev) {
+ if (poly_type != poly_prev) {
if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev= poly_type));
+ glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
}
if (!drawSmooth) {
- glNormal3fv(faceNos[i]);
- glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
- if (poly_type == GL_QUADS) glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
+ glNormal3fv(polyNos[BM_elem_index_get(efa)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(l[0]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(l[1]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(l[2]->v)]);
}
else {
- glNormal3fv(vertexNos[(int) efa->v1->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
- glNormal3fv(vertexNos[(int) efa->v2->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
- glNormal3fv(vertexNos[(int) efa->v3->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
- if (poly_type == GL_QUADS) {
- glNormal3fv(vertexNos[(int) efa->v4->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
- }
+ glNormal3fv(vertexNos[BM_elem_index_get(l[0]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(l[0]->v)]);
+ glNormal3fv(vertexNos[BM_elem_index_get(l[1]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(l[1]->v)]);
+ glNormal3fv(vertexNos[BM_elem_index_get(l[2]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(l[2]->v)]);
}
}
flush= (draw==2);
- if (!skip_normals && !flush && efa->next)
- flush|= efa->mat_nr != efa->next->mat_nr;
+ if (!skip_normals && !flush && (i != lasttri))
+ flush|= efa->mat_nr != looptris[i + 1][0]->f->mat_nr; /* TODO, make this neater */
if (flush) {
glEnd();
@@ -366,11 +681,18 @@ static void emDM_drawMappedFaces(
}
}
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);
+ BM_mesh_elem_index_ensure(bmdm->tc->bm, BM_FACE);
+
+ for (i=0; i < tottri; i++) {
+ BMLoop **l = looptris[i];
+ int drawSmooth;
+
+ efa = l[0]->f;
+ drawSmooth= BM_elem_flag_test(efa, BM_ELEM_SMOOTH);
+
+ draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BM_elem_index_get(efa), &drawSmooth);
if (draw) {
- const GLenum poly_type= efa->v4 ? GL_QUADS:GL_TRIANGLES;
+ const GLenum poly_type= GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
if (draw==2) { /* enabled with stipple */
if (poly_prev != GL_ZERO) glEnd();
@@ -383,49 +705,44 @@ static void emDM_drawMappedFaces(
if (skip_normals) {
if (poly_type != poly_prev) {
if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev= poly_type));
+ glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
}
- glVertex3fv(efa->v1->co);
- glVertex3fv(efa->v2->co);
- glVertex3fv(efa->v3->co);
- if (poly_type == GL_QUADS) glVertex3fv(efa->v4->co);
+ glVertex3fv(l[0]->v->co);
+ glVertex3fv(l[1]->v->co);
+ glVertex3fv(l[2]->v->co);
}
else {
const GLenum shade_type= drawSmooth ? GL_SMOOTH : GL_FLAT;
if (shade_type != shade_prev) {
if (poly_prev != GL_ZERO) glEnd();
glShadeModel((shade_prev= shade_type)); /* same as below but switch shading */
- glBegin((poly_prev= poly_type));
+ glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
}
- else if (poly_type != poly_prev) {
+ if (poly_type != poly_prev) {
if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev= poly_type));
+ glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
}
if (!drawSmooth) {
- glNormal3fv(efa->n);
- glVertex3fv(efa->v1->co);
- glVertex3fv(efa->v2->co);
- glVertex3fv(efa->v3->co);
- if (poly_type == GL_QUADS) glVertex3fv(efa->v4->co);
+ glNormal3fv(efa->no);
+ glVertex3fv(l[0]->v->co);
+ glVertex3fv(l[1]->v->co);
+ glVertex3fv(l[2]->v->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 (poly_type == GL_QUADS) {
- glNormal3fv(efa->v4->no);
- glVertex3fv(efa->v4->co);
- }
+ 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);
}
}
flush= (draw==2);
- if (!skip_normals && !flush && efa->next)
- flush|= efa->mat_nr != efa->next->mat_nr;
+ if (!skip_normals && !flush && (i != lasttri)) {
+ flush|= efa->mat_nr != looptris[i + 1][0]->f->mat_nr; /* TODO, make this neater */
+ }
if (flush) {
glEnd();
@@ -441,187 +758,211 @@ static void emDM_drawMappedFaces(
if (poly_prev != GL_ZERO) glEnd();
}
+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 emDM_drawFacesTex_common(
DerivedMesh *dm,
- int (*drawParams)(MTFace *tface, int has_mcol, int matnr),
+ int (*drawParams)(MTFace *tface, int has_vcol, int matnr),
int (*drawParamsMapped)(void *userData, int index),
int (*compareDrawOptions)(void *userData, int cur_index, int next_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;
+ 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;
+ 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);
(void) compareDrawOptions;
+ 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);
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+
if (vertexCos) {
- EditVert *eve;
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ glBegin(GL_TRIANGLES);
+ for (i=0; i<em->tottri; i++) {
+ BMLoop **ls = em->looptris[i];
+ MTexPoly *tp= has_uv ? CustomData_bmesh_get(&bm->pdata, ls[0]->f->head.data, CD_MTEXPOLY) : NULL;
+ MTFace mtf = {{{0}}};
+ /*unsigned char *cp= NULL;*/ /*UNUSED*/
+ int drawSmooth= BM_elem_flag_test(ls[0]->f, BM_ELEM_SMOOTH);
+ int flag;
- for (i=0,eve=em->verts.first; eve; eve= eve->next)
- eve->tmp.l = (intptr_t) i++;
+ efa = ls[0]->f;
- 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 (has_uv) {
+ ME_MTEXFACE_CPY(&mtf, tp);
+ }
if (drawParams)
- flag= drawParams(tf, (mcol != NULL), efa->mat_nr);
+ flag= drawParams(&mtf, has_vcol, efa->mat_nr);
else if (drawParamsMapped)
- flag= drawParamsMapped(userData, i);
+ flag= drawParamsMapped(userData, BM_elem_index_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 (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]);
+ glNormal3fv(bmdm->polyNos[BM_elem_index_get(efa)]);
- if (tf) glTexCoord2fv(tf->uv[0]);
- if (cp) glColor3ub(cp[3], cp[2], cp[1]);
- glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
+ bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
- if (tf) glTexCoord2fv(tf->uv[1]);
- if (cp) glColor3ub(cp[7], cp[6], cp[5]);
- glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
+ glTexCoord2fv(luv[0]->uv);
+ glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
+ glVertex3fv(vertexCos[BM_elem_index_get(ls[0]->v)]);
- if (tf) glTexCoord2fv(tf->uv[2]);
- if (cp) glColor3ub(cp[11], cp[10], cp[9]);
- glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
+ glTexCoord2fv(luv[1]->uv);
+ glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
+ glVertex3fv(vertexCos[BM_elem_index_get(ls[1]->v)]);
- 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]);
- }
+ glTexCoord2fv(luv[2]->uv);
+ glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
+ glVertex3fv(vertexCos[BM_elem_index_get(ls[2]->v)]);
}
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]);
- }
+ 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[BM_elem_index_get(ls[0]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(ls[0]->v)]);
+
+ glTexCoord2fv(luv[1]->uv);
+ glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
+ glNormal3fv(vertexNos[BM_elem_index_get(ls[1]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(ls[1]->v)]);
+
+ glTexCoord2fv(luv[2]->uv);
+ glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
+ glNormal3fv(vertexNos[BM_elem_index_get(ls[2]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(ls[2]->v)]);
}
- glEnd();
}
}
+ 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);
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ for (i=0; i<em->tottri; i++) {
+ BMLoop **ls = em->looptris[i];
+ MTexPoly *tp= has_uv ? CustomData_bmesh_get(&bm->pdata, ls[0]->f->head.data, CD_MTEXPOLY) : NULL;
+ MTFace mtf = {{{0}}};
+ /*unsigned char *cp= NULL;*/ /*UNUSED*/
+ int drawSmooth= BM_elem_flag_test(ls[0]->f, BM_ELEM_SMOOTH);
int flag;
+ efa = ls[0]->f;
+
+ if (has_uv) {
+ ME_MTEXFACE_CPY(&mtf, tp);
+ }
+
if (drawParams)
- flag= drawParams(tf, (mcol != NULL), efa->mat_nr);
+ flag= drawParams(&mtf, has_vcol, efa->mat_nr);
else if (drawParamsMapped)
- flag= drawParamsMapped(userData, i);
+ flag= drawParamsMapped(userData, BM_elem_index_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 (mcol) {
- if (flag==1) {
- cp= (unsigned char*)mcol;
- }
- }
- else {
- glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
- }
-
- glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
+ glBegin(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);
- }
+ 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 {
- 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);
- }
+ 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();
}
}
}
+
+ glShadeModel(GL_FLAT);
}
static void emDM_drawFacesTex(
DerivedMesh *dm,
- int (*setDrawOptions)(MTFace *tface, int has_mcol, int matnr),
+ int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr),
int (*compareDrawOptions)(void *userData, int cur_index, int next_index),
void *userData)
{
@@ -643,54 +984,56 @@ static void emDM_drawMappedFacesGLSL(
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= {{{0}}};
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMesh *bm= bmdm->tc->bm;
+ BMEditMesh *em = bmdm->tc;
+ float (*vertexCos)[3]= bmdm->vertexCos;
+ float (*vertexNos)[3]= bmdm->vertexNos;
+ BMFace *efa;
+ BMLoop **ltri;
+ DMVertexAttribs attribs;
GPUVertexAttribs gattribs;
- /* int tfoffset; */ /* UNUSED */
- int i, b, matnr, new_matnr, dodraw /* , layer */ /* UNUSED */;
+
+ int i, b, matnr, new_matnr, dodraw;
dodraw = 0;
matnr = -1;
- /* layer = CustomData_get_layer_index(&em->fdata, CD_MTFACE); */ /* UNUSED */
- /* tfoffset = (layer == -1)? -1: em->fdata.layers[layer].offset; */ /* UNUSED */
+ memset(&attribs, 0, sizeof(attribs));
/* always use smooth shading even for flat faces, else vertex colors wont interpolate */
glShadeModel(GL_SMOOTH);
+ BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
- for (i=0,eve=em->verts.first; eve; eve= eve->next)
- eve->tmp.l = (intptr_t) i++;
-
-#define PASSATTRIB(efa, eve, vert) { \
+#define PASSATTRIB(loop, eve, vert) { \
if (attribs.totorco) { \
- float *orco = attribs.orco.array[eve->tmp.l]; \
+ float *orco = attribs.orco.array[BM_elem_index_get(eve)]; \
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]); \
+ MLoopUV *_luv = CustomData_bmesh_get_n(&bm->ldata, loop->head.data, CD_MLOOPUV, b);\
+ glVertexAttrib2fvARB(attribs.tface[b].glIndex, _luv->uv); \
} \
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); \
+ MLoopCol *_cp = CustomData_bmesh_get_n(&bm->ldata, loop->head.data, CD_MLOOPCOL, b);\
+ 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); \
+ glVertexAttrib3fvARB(attribs.tang.glIndex, tang); \
} \
-}
+ }
+
+
+ for (i=0, ltri=em->looptris[0]; i<em->tottri; i++, ltri += 3) {
+ int drawSmooth;
- for (i=0,efa= em->faces.first; efa; i++,efa= efa->next) {
- int drawSmooth= (efa->flag & ME_SMOOTH);
+ efa = ltri[0]->f;
+ drawSmooth= BM_elem_flag_test(efa, BM_ELEM_SMOOTH);
- if (setDrawOptions && !setDrawOptions(userData, i))
+ if (setDrawOptions && !setDrawOptions(userData, BM_elem_index_get(efa)))
continue;
new_matnr = efa->mat_nr + 1;
@@ -701,70 +1044,52 @@ static void emDM_drawMappedFacesGLSL(
}
if (dodraw) {
- glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
+ glBegin(GL_TRIANGLES);
if (!drawSmooth) {
- if (vertexCos) glNormal3fv(emdm->faceNos[i]);
- else glNormal3fv(efa->n);
+ if (vertexCos) glNormal3fv(bmdm->polyNos[BM_elem_index_get(efa)]);
+ else glNormal3fv(efa->no);
- PASSATTRIB(efa, efa->v1, 0);
- if (vertexCos) glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
- else glVertex3fv(efa->v1->co);
+ PASSATTRIB(ltri[0], ltri[0]->v, 0);
+ if (vertexCos) glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
+ else glVertex3fv(ltri[0]->v->co);
- PASSATTRIB(efa, efa->v2, 1);
- if (vertexCos) glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
- else glVertex3fv(efa->v2->co);
+ PASSATTRIB(ltri[1], ltri[1]->v, 1);
+ if (vertexCos) glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
+ else glVertex3fv(ltri[1]->v->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);
- }
+ PASSATTRIB(ltri[2], ltri[2]->v, 2);
+ if (vertexCos) glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
+ else glVertex3fv(ltri[2]->v->co);
}
else {
- PASSATTRIB(efa, efa->v1, 0);
+ PASSATTRIB(ltri[0], ltri[0]->v, 0);
if (vertexCos) {
- glNormal3fv(vertexNos[(int) efa->v1->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
+ glNormal3fv(vertexNos[BM_elem_index_get(ltri[0]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
}
else {
- glNormal3fv(efa->v1->no);
- glVertex3fv(efa->v1->co);
+ glNormal3fv(ltri[0]->v->no);
+ glVertex3fv(ltri[0]->v->co);
}
- PASSATTRIB(efa, efa->v2, 1);
+ PASSATTRIB(ltri[1], ltri[1]->v, 1);
if (vertexCos) {
- glNormal3fv(vertexNos[(int) efa->v2->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
+ glNormal3fv(vertexNos[BM_elem_index_get(ltri[1]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
}
else {
- glNormal3fv(efa->v2->no);
- glVertex3fv(efa->v2->co);
+ glNormal3fv(ltri[1]->v->no);
+ glVertex3fv(ltri[1]->v->co);
}
- PASSATTRIB(efa, efa->v3, 2);
+ PASSATTRIB(ltri[2], ltri[2]->v, 2);
if (vertexCos) {
- glNormal3fv(vertexNos[(int) efa->v3->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
+ glNormal3fv(vertexNos[BM_elem_index_get(ltri[2]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
}
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);
- }
+ glNormal3fv(ltri[2]->v->no);
+ glVertex3fv(ltri[2]->v->co);
}
}
glEnd();
@@ -785,12 +1110,13 @@ static void emDM_drawMappedFacesMat(
void (*setMaterial)(void *userData, int, void *attribs),
int (*setFace)(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;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMesh *bm= bmdm->tc->bm;
+ BMEditMesh *em = bmdm->tc;
+ float (*vertexCos)[3]= bmdm->vertexCos;
+ float (*vertexNos)[3]= bmdm->vertexNos;
+ BMFace *efa;
+ BMLoop **ltri;
DMVertexAttribs attribs= {{{0}}};
GPUVertexAttribs gattribs;
int i, b, matnr, new_matnr;
@@ -800,29 +1126,22 @@ static void emDM_drawMappedFacesMat(
/* 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++;
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
-#define PASSATTRIB(efa, eve, vert) { \
+#define PASSATTRIB(loop, eve, vert) { \
if (attribs.totorco) { \
- float *orco = attribs.orco.array[eve->tmp.l]; \
- if (attribs.orco.glTexco) \
- glTexCoord3fv(orco); \
- else \
- glVertexAttrib3fvARB(attribs.orco.glIndex, orco); \
+ float *orco = attribs.orco.array[BM_elem_index_get(eve)]; \
+ glVertexAttrib3fvARB(attribs.orco.glIndex, orco); \
} \
for (b = 0; b < attribs.tottface; b++) { \
- MTFace *_tf = (MTFace*)((char*)efa->data + attribs.tface[b].emOffset); \
- if (attribs.tface[b].glTexco) \
- glTexCoord2fv(_tf->uv[vert]); \
- else \
- glVertexAttrib2fvARB(attribs.tface[b].glIndex, _tf->uv[vert]); \
+ MLoopUV *_luv = CustomData_bmesh_get_n(&bm->ldata, loop->head.data, CD_MLOOPUV, b);\
+ glVertexAttrib2fvARB(attribs.tface[b].glIndex, _luv->uv); \
} \
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); \
+ MLoopCol *_cp = CustomData_bmesh_get_n(&bm->ldata, loop->head.data, CD_MLOOPCOL, b);\
+ 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]; \
@@ -830,11 +1149,14 @@ static void emDM_drawMappedFacesMat(
} \
}
- for (i=0,efa= em->faces.first; efa; i++,efa= efa->next) {
- int drawSmooth= (efa->flag & ME_SMOOTH);
+ for (i=0, ltri=em->looptris[0]; i<em->tottri; i++, ltri += 3) {
+ int drawSmooth;
+
+ efa = ltri[0]->f;
+ drawSmooth = BM_elem_flag_test(efa, BM_ELEM_SMOOTH);
/* face hiding */
- if (setFace && !setFace(userData, i))
+ if (setFace && !setFace(userData, BM_elem_index_get(efa)))
continue;
/* material */
@@ -845,70 +1167,53 @@ static void emDM_drawMappedFacesMat(
}
/* face */
- glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
+ glBegin(GL_TRIANGLES);
if (!drawSmooth) {
- if (vertexCos) glNormal3fv(emdm->faceNos[i]);
- else glNormal3fv(efa->n);
+ if (vertexCos) glNormal3fv(bmdm->polyNos[BM_elem_index_get(efa)]);
+ else glNormal3fv(efa->no);
- PASSATTRIB(efa, efa->v1, 0);
- if (vertexCos) glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
- else glVertex3fv(efa->v1->co);
+ PASSATTRIB(ltri[0], ltri[0]->v, 0);
+ if (vertexCos) glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
+ else glVertex3fv(ltri[0]->v->co);
- PASSATTRIB(efa, efa->v2, 1);
- if (vertexCos) glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
- else glVertex3fv(efa->v2->co);
+ PASSATTRIB(ltri[1], ltri[1]->v, 1);
+ if (vertexCos) glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
+ else glVertex3fv(ltri[1]->v->co);
- PASSATTRIB(efa, efa->v3, 2);
- if (vertexCos) glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
- else glVertex3fv(efa->v3->co);
+ PASSATTRIB(ltri[2], ltri[2]->v, 2);
+ if (vertexCos) glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
+ else glVertex3fv(ltri[2]->v->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);
+ PASSATTRIB(ltri[0], ltri[0]->v, 0);
if (vertexCos) {
- glNormal3fv(vertexNos[(int) efa->v1->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
+ glNormal3fv(vertexNos[BM_elem_index_get(ltri[0]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
}
else {
- glNormal3fv(efa->v1->no);
- glVertex3fv(efa->v1->co);
+ glNormal3fv(ltri[0]->v->no);
+ glVertex3fv(ltri[0]->v->co);
}
- PASSATTRIB(efa, efa->v2, 1);
+ PASSATTRIB(ltri[1], ltri[1]->v, 1);
if (vertexCos) {
- glNormal3fv(vertexNos[(int) efa->v2->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
+ glNormal3fv(vertexNos[BM_elem_index_get(ltri[1]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
}
else {
- glNormal3fv(efa->v2->no);
- glVertex3fv(efa->v2->co);
+ glNormal3fv(ltri[1]->v->no);
+ glVertex3fv(ltri[1]->v->co);
}
- PASSATTRIB(efa, efa->v3, 2);
+ PASSATTRIB(ltri[2], ltri[2]->v, 2);
if (vertexCos) {
- glNormal3fv(vertexNos[(int) efa->v3->tmp.l]);
- glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
+ glNormal3fv(vertexNos[BM_elem_index_get(ltri[2]->v)]);
+ glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
}
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);
- }
+ glNormal3fv(ltri[2]->v->no);
+ glVertex3fv(ltri[2]->v->co);
}
}
glEnd();
@@ -918,14 +1223,16 @@ static void emDM_drawMappedFacesMat(
static void emDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditVert *eve;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMVert *eve;
+ BMIter iter;
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);
+ if (bmdm->tc->bm->totvert) {
+ eve = BM_iter_new(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BM_iter_step(&iter), i++) {
+ if (bmdm->vertexCos) {
+ DO_MINMAX(bmdm->vertexCos[i], min_r, max_r);
}
else {
DO_MINMAX(eve->co, min_r, max_r);
@@ -938,238 +1245,271 @@ static void emDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
}
static int emDM_getNumVerts(DerivedMesh *dm)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
- return BLI_countlist(&emdm->em->verts);
+ return bmdm->tc->bm->totvert;
}
static int emDM_getNumEdges(DerivedMesh *dm)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
- return BLI_countlist(&emdm->em->edges);
+ return bmdm->tc->bm->totedge;
}
-static int emDM_getNumFaces(DerivedMesh *dm)
+static int emDM_getNumTessFaces(DerivedMesh *dm)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
- return BLI_countlist(&emdm->em->faces);
+ return bmdm->tc->tottri;
}
-static void emDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3])
+static int emDM_getNumLoops(DerivedMesh *dm)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditVert *eve;
- int i;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
- 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);
- }
- }
+ return bmdm->tc->bm->totloop;
}
-static void emDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
+static int emDM_getNumPolys(DerivedMesh *dm)
{
- EditVert *ev = ((EditMeshDerivedMesh *)dm)->em->verts.first;
- int i;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
- for (i = 0; i < index; ++i) ev = ev->next;
+ return bmdm->tc->bm->totface;
+}
+static int bmvert_to_mvert(BMesh *bm, BMVert *ev, MVert *vert_r)
+{
copy_v3_v3(vert_r->co, ev->co);
normal_float_to_short_v3(vert_r->no, ev->no);
- /* TODO what to do with vert_r->flag? */
- vert_r->bweight = (unsigned char) (ev->bweight*255.0f);
+ vert_r->flag = BM_vert_flag_to_mflag(ev);
+
+ if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
+ vert_r->bweight = (unsigned char) (BM_elem_float_data_get(&bm->vdata, ev, CD_BWEIGHT)*255.0f);
+ }
+
+ return 1;
+}
+
+static void emDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMVert *ev;
+
+ if (index < 0 || index >= bmdm->tv) {
+ printf("error in emDM_getVert.\n");
+ return;
+ }
+
+ // ev = EDBM_get_vert_for_index(bmdm->tc, index);
+ ev = BM_vert_at_index(bmdm->tc->bm, index); /* warning, does list loop, _not_ ideal */
+
+ bmvert_to_mvert(bmdm->tc->bm, ev, vert_r);
}
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;
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMesh *bm = bmdm->tc->bm;
+ BMEdge *e;
- for (i = 0; i < index; ++i) ee = ee->next;
+ if (index < 0 || index >= bmdm->te) {
+ printf("error in emDM_getEdge.\n");
+ return;
+ }
- 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 (ee->freestyle) edge_r->flag |= ME_FREESTYLE_EDGE;
-#if 0
- /* this needs setup of f2 field */
- if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
-#endif
+ // e = EDBM_get_edge_for_index(bmdm->tc, index);
+ e = BM_edge_at_index(bmdm->tc->bm, index); /* warning, does list loop, _not_ ideal */
- /* 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;
- }
+ if (CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
+ edge_r->bweight = (unsigned char) (BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT)*255.0f);
+ }
+
+ if (CustomData_has_layer(&bm->edata, CD_CREASE)) {
+ edge_r->crease = (unsigned char) (BM_elem_float_data_get(&bm->edata, e, CD_CREASE)*255.0f);
}
+
+ edge_r->flag = BM_edge_flag_to_mflag(e);
+
+ edge_r->v1 = BM_elem_index_get(e->v1);
+ edge_r->v2 = BM_elem_index_get(e->v2);
}
-static void emDM_getFace(DerivedMesh *dm, int index, MFace *face_r)
+static void emDM_getTessFace(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;
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMFace *ef;
+ BMLoop **l;
- for (i = 0; i < index; ++i) ef = ef->next;
+ if (index < 0 || index >= bmdm->tf) {
+ printf("error in emDM_getTessFace.\n");
+ return;
+ }
- face_r->mat_nr = ef->mat_nr;
- face_r->flag = ef->flag;
+ l = bmdm->tc->looptris[index];
- /* 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;
+ ef = l[0]->f;
- 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;
- }
- }
+ face_r->mat_nr = (unsigned char) ef->mat_nr;
+ face_r->flag = BM_face_flag_to_mflag(ef);
- test_index_face(face_r, NULL, 0, ef->v4?4:3);
+ face_r->v1 = BM_elem_index_get(l[0]->v);
+ face_r->v2 = BM_elem_index_get(l[1]->v);
+ face_r->v3 = BM_elem_index_get(l[2]->v);
+ face_r->v4 = 0;
+
+ test_index_face(face_r, NULL, 0, 3);
}
static void emDM_copyVertArray(DerivedMesh *dm, MVert *vert_r)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditVert *ev = emdm->em->verts.first;
- int i;
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMVert *ev;
+ BMIter iter;
- 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);
+ ev = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for ( ; ev; ev = BM_iter_step(&iter), ++vert_r) {
+ copy_v3_v3(vert_r->co, ev->co);
normal_float_to_short_v3(vert_r->no, ev->no);
- /* TODO what to do with vert_r->flag? */
- vert_r->flag = 0;
- vert_r->bweight = (unsigned char) (ev->bweight*255.0f);
+ vert_r->flag = BM_vert_flag_to_mflag(ev);
+
+ if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
+ vert_r->bweight = (unsigned char) (BM_elem_float_data_get(&bm->vdata, ev, CD_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;
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMEdge *ee;
+ BMIter iter;
+ int has_bweight = CustomData_has_layer(&bm->edata, CD_BWEIGHT);
+ int has_crease = CustomData_has_layer(&bm->edata, CD_CREASE);
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ ee = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; ee; ee=BM_iter_step(&iter), edge_r++) {
+ if (has_bweight) {
+ edge_r->bweight = (unsigned char) (BM_elem_float_data_get(&bm->edata, ee, CD_BWEIGHT)*255.0f);
+ }
- /* 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 (ee->freestyle) edge_r->flag |= ME_FREESTYLE_EDGE;
-#if 0
- /* this needs setup of f2 field */
- if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
-#endif
+ if (has_crease) {
+ edge_r->crease = (unsigned char) (BM_elem_float_data_get(&bm->edata, ee, CD_CREASE)*255.0f);
+ }
- edge_r->v1 = (int)ee->v1->tmp.l;
- edge_r->v2 = (int)ee->v2->tmp.l;
+ edge_r->flag = BM_edge_flag_to_mflag(ee);
+
+ edge_r->v1 = BM_elem_index_get(ee->v1);
+ edge_r->v2 = BM_elem_index_get(ee->v2);
}
}
-static void emDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
+static void emDM_copyTessFaceArray(DerivedMesh *dm, MFace *face_r)
{
- EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
- EditFace *ef = em->faces.first;
- EditVert *ev;
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMesh *bm = bmdm->tc->bm;
+ BMFace *ef;
+ BMLoop **l;
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;
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ for (i=0; i<bmdm->tc->tottri; i++, face_r++) {
+ l = bmdm->tc->looptris[i];
+ ef = l[0]->f;
+
+ face_r->mat_nr = (unsigned char) ef->mat_nr;
+
+ face_r->flag = BM_face_flag_to_mflag(ef);
+
+ face_r->v1 = BM_elem_index_get(l[0]->v);
+ face_r->v2 = BM_elem_index_get(l[1]->v);
+ face_r->v3 = BM_elem_index_get(l[2]->v);
+ face_r->v4 = 0;
+
+ test_index_face(face_r, NULL, 0, 3);
+ }
+}
+
- for ( ; ef; ef = ef->next, ++face_r) {
- face_r->mat_nr = ef->mat_nr;
- face_r->flag = ef->flag;
+static void emDM_copyLoopArray(DerivedMesh *dm, MLoop *loop_r)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMesh *bm = bmdm->tc->bm;
+ BMIter iter, liter;
+ BMFace *f;
+ BMLoop *l;
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT | BM_EDGE);
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ loop_r->v = BM_elem_index_get(l->v);
+ loop_r->e = BM_elem_index_get(l->e);
+ loop_r++;
+ }
+ }
+}
+
+static void emDM_copyPolyArray(DerivedMesh *dm, MPoly *poly_r)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMesh *bm = bmdm->tc->bm;
+ BMIter iter;
+ BMFace *f;
+ int i;
- 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;
+ i = 0;
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ poly_r->flag = BM_face_flag_to_mflag(f);
+ poly_r->loopstart = i;
+ poly_r->totloop = f->len;
+ poly_r->mat_nr = f->mat_nr;
- test_index_face(face_r, NULL, 0, ef->v4?4:3);
+ poly_r++;
+ i += f->len;
}
}
-static void *emDM_getFaceDataArray(DerivedMesh *dm, int type)
+static void *emDM_getTessFaceDataArray(DerivedMesh *dm, int type)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
- EditMesh *em= emdm->em;
- EditFace *efa;
- char *data, *emdata;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMesh *bm= bmdm->tc->bm;
+ BMFace *efa;
+ char *data, *bmdata;
void *datalayer;
- int index, size;
+ int index /*, offset*/ /*UNUSED */, size, i;
- datalayer = DM_get_face_data_layer(dm, type);
+ datalayer = DM_get_tessface_data_layer(dm, type);
if (datalayer)
return datalayer;
- /* layers are store per face for editmesh, we convert to a temporary
+ /* 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(&em->fdata, type);
+ index = CustomData_get_layer_index(&bm->pdata, type);
if (index != -1) {
- /* int offset = em->fdata.layers[index].offset; */ /* UNUSED */
+ /* offset = bm->pdata.layers[index].offset; */ /* UNUSED */
size = CustomData_sizeof(type);
- DM_add_face_layer(dm, type, CD_CALLOC, NULL);
+ 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_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);
+ 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);
}
}
}
@@ -1177,120 +1517,188 @@ static void *emDM_getFaceDataArray(DerivedMesh *dm, int type)
return datalayer;
}
+static void emDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3])
+{
+ EditDerivedBMesh *emdm= (EditDerivedBMesh*) dm;
+ BMVert *eve;
+ BMIter iter;
+ int i;
+
+ i= 0;
+ BM_ITER(eve, &iter, emdm->tc->bm, BM_VERTS_OF_MESH, NULL) {
+ if (emdm->vertexCos) {
+ copy_v3_v3(cos_r[i], emdm->vertexCos[i]);
+ }
+ else {
+ copy_v3_v3(cos_r[i], eve->co);
+ }
+
+ i++;
+ }
+}
+
static void emDM_release(DerivedMesh *dm)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh *)dm;
if (DM_release(dm)) {
- if (emdm->vertexCos) {
- MEM_freeN(emdm->vertexCos);
- MEM_freeN(emdm->vertexNos);
- MEM_freeN(emdm->faceNos);
+ if (bmdm->vertexCos) {
+ MEM_freeN(bmdm->vertexCos);
+ MEM_freeN(bmdm->vertexNos);
+ MEM_freeN(bmdm->polyNos);
}
- MEM_freeN(emdm);
+ MEM_freeN(bmdm);
}
}
-DerivedMesh *editmesh_get_derived(
- EditMesh *em,
- float (*vertexCos)[3])
+static CustomData *bmDm_getVertDataLayout(DerivedMesh *dm)
{
- EditMeshDerivedMesh *emdm = MEM_callocN(sizeof(*emdm), "emdm");
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
+
+ return &bmdm->tc->bm->vdata;
+}
- DM_init(&emdm->dm, DM_TYPE_EDITMESH, BLI_countlist(&em->verts),
- BLI_countlist(&em->edges), BLI_countlist(&em->faces));
+static CustomData *bmDm_getEdgeDataLayout(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
- emdm->dm.getMinMax = emDM_getMinMax;
+ return &bmdm->tc->bm->edata;
+}
- emdm->dm.getNumVerts = emDM_getNumVerts;
- emdm->dm.getNumEdges = emDM_getNumEdges;
- emdm->dm.getNumFaces = emDM_getNumFaces;
+static CustomData *bmDm_getTessFaceDataLayout(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
- emdm->dm.getVertCos = emDM_getVertCos;
+ return &bmdm->dm.faceData;
+}
- 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;
+static CustomData *bmDm_getLoopDataLayout(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
- emdm->dm.foreachMappedVert = emDM_foreachMappedVert;
- emdm->dm.foreachMappedEdge = emDM_foreachMappedEdge;
- emdm->dm.foreachMappedFaceCenter = emDM_foreachMappedFaceCenter;
+ return &bmdm->tc->bm->ldata;
+}
- 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.drawMappedFacesMat = emDM_drawMappedFacesMat;
- emdm->dm.drawUVEdges = emDM_drawUVEdges;
+static CustomData *bmDm_getPolyDataLayout(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
- emdm->dm.release = emDM_release;
+ return &bmdm->tc->bm->pdata;
+}
- emdm->em = em;
- emdm->vertexCos = vertexCos;
- if (CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
- EditVert *eve;
+DerivedMesh *getEditDerivedBMesh(
+ BMEditMesh *em,
+ Object *UNUSED(ob),
+ float (*vertexCos)[3])
+{
+ EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), __func__);
+ BMesh *bm = em->bm;
+
+ bmdm->tc = em;
+
+ DM_init((DerivedMesh*)bmdm, DM_TYPE_EDITBMESH, em->bm->totvert,
+ em->bm->totedge, em->tottri, em->bm->totloop, em->bm->totface);
+
+ CustomData_from_bmeshpoly(&bmdm->dm.faceData, &em->bm->pdata, &em->bm->ldata, 0);
+
+ bmdm->dm.getVertCos = emDM_getVertCos;
+ bmdm->dm.getMinMax = emDM_getMinMax;
+
+ bmdm->dm.getVertDataLayout = bmDm_getVertDataLayout;
+ bmdm->dm.getEdgeDataLayout = bmDm_getEdgeDataLayout;
+ bmdm->dm.getTessFaceDataLayout = bmDm_getTessFaceDataLayout;
+ bmdm->dm.getLoopDataLayout = bmDm_getLoopDataLayout;
+ bmdm->dm.getPolyDataLayout = bmDm_getPolyDataLayout;
+
+ bmdm->dm.getNumVerts = emDM_getNumVerts;
+ bmdm->dm.getNumEdges = emDM_getNumEdges;
+ bmdm->dm.getNumTessFaces = emDM_getNumTessFaces;
+ bmdm->dm.getNumLoops = emDM_getNumLoops;
+ bmdm->dm.getNumPolys = emDM_getNumPolys;
+
+ bmdm->dm.getVert = emDM_getVert;
+ bmdm->dm.getEdge = emDM_getEdge;
+ bmdm->dm.getTessFace = emDM_getTessFace;
+ bmdm->dm.copyVertArray = emDM_copyVertArray;
+ bmdm->dm.copyEdgeArray = emDM_copyEdgeArray;
+ bmdm->dm.copyTessFaceArray = emDM_copyTessFaceArray;
+ bmdm->dm.copyLoopArray = emDM_copyLoopArray;
+ bmdm->dm.copyPolyArray = emDM_copyPolyArray;
+
+ bmdm->dm.getTessFaceDataArray = emDM_getTessFaceDataArray;
+
+ bmdm->dm.calcNormals = emDM_calcNormals;
+ bmdm->dm.recalcTesselation = emDM_recalcTesselation;
+
+ bmdm->dm.foreachMappedVert = emDM_foreachMappedVert;
+ bmdm->dm.foreachMappedEdge = emDM_foreachMappedEdge;
+ bmdm->dm.foreachMappedFaceCenter = emDM_foreachMappedFaceCenter;
+
+ bmdm->dm.drawEdges = emDM_drawEdges;
+ bmdm->dm.drawMappedEdges = emDM_drawMappedEdges;
+ bmdm->dm.drawMappedEdgesInterp = emDM_drawMappedEdgesInterp;
+ bmdm->dm.drawMappedFaces = emDM_drawMappedFaces;
+ bmdm->dm.drawMappedFacesTex = emDM_drawMappedFacesTex;
+ bmdm->dm.drawMappedFacesGLSL = emDM_drawMappedFacesGLSL;
+ bmdm->dm.drawMappedFacesMat = emDM_drawMappedFacesMat;
+ bmdm->dm.drawFacesTex = emDM_drawFacesTex;
+ bmdm->dm.drawFacesGLSL = emDM_drawFacesGLSL;
+ bmdm->dm.drawUVEdges = emDM_drawUVEdges;
+
+ bmdm->dm.release = emDM_release;
+
+ bmdm->vertexCos = vertexCos;
+
+ if (CustomData_has_layer(&bm->vdata, CD_MDEFORMVERT)) {
+ BMIter iter;
+ BMVert *eve;
int i;
- DM_add_vert_layer(&emdm->dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
+ DM_add_vert_layer(&bmdm->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));
+ eve = BM_iter_new(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BM_iter_step(&iter), i++)
+ DM_set_vert_data(&bmdm->dm, i, CD_MDEFORMVERT,
+ CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_MDEFORMVERT));
}
if (vertexCos) {
- EditVert *eve;
- EditFace *efa;
- int totface = BLI_countlist(&em->faces);
+ BMFace *efa;
+ BMVert *eve;
+ BMIter fiter;
+ BMIter viter;
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");
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
- 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];
+ bmdm->vertexNos = MEM_callocN(sizeof(*bmdm->vertexNos) * bm->totvert, "bmdm_vno");
+ bmdm->polyNos = MEM_mallocN(sizeof(*bmdm->polyNos)*bm->totface, "bmdm_pno");
- if (efa->v4) {
- float *v4 = vertexCos[(int) efa->v4->tmp.l];
+ i = 0;
+ BM_ITER(efa, &fiter, bm, BM_FACES_OF_MESH, NULL) {
+ BM_elem_index_set(efa, i); /* set_inline */
+ BM_face_normal_update_vcos(bm, efa, bmdm->polyNos[i], vertexCos);
+ i++;
+ }
+ bm->elem_index_dirty &= ~BM_FACE;
- normal_quad_v3( no,v1, v2, v3, v4);
- add_v3_v3(emdm->vertexNos[(int) efa->v4->tmp.l], no);
+ eve=BM_iter_new(&viter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BM_iter_step(&viter), i++) {
+ float *no = bmdm->vertexNos[i];
+ BM_ITER(efa, &fiter, bm, BM_FACES_OF_VERT, eve) {
+ add_v3_v3(no, bmdm->polyNos[BM_elem_index_get(efa)]);
}
- 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.0f) {
- normalize_v3_v3(no, vertexCos[i]);
+ if (normalize_v3(no)==0.0) {
+ copy_v3_v3(no, vertexCos[i]);
+ normalize_v3(no);
}
}
}
- return (DerivedMesh*) emdm;
+ return (DerivedMesh*) bmdm;
}
-
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index dcb8533d7a1..69d860bfb08 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -553,7 +553,7 @@ int closest_point_on_surface(SurfaceModifierData *surmd, const float co[3], floa
}
if(surface_vel) {
- MFace *mface = CDDM_get_face(surmd->dm, nearest.index);
+ MFace *mface = CDDM_get_tessface(surmd->dm, nearest.index);
copy_v3_v3(surface_vel, surmd->v[mface->v1].co);
add_v3_v3(surface_vel, surmd->v[mface->v2].co);
diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c
index cdb2b194b43..587fe75031f 100644
--- a/source/blender/blenkernel/intern/fluidsim.c
+++ b/source/blender/blenkernel/intern/fluidsim.c
@@ -85,9 +85,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/image.c b/source/blender/blenkernel/intern/image.c
index 0a80e8a3d56..f848ee3a676 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -382,6 +382,25 @@ void make_local_image(struct Image *ima)
}
}
}
+
+ if(me->mtpoly) {
+ MTexPoly *mtpoly;
+ int a, i;
+
+ for(i=0; i<me->pdata.totlayer; i++) {
+ if(me->pdata.layers[i].type == CD_MTEXPOLY) {
+ mtpoly= (MTexPoly*)me->pdata.layers[i].data;
+
+ for(a=0; a<me->totpoly; a++, mtpoly++) {
+ if(mtpoly->tpage == ima) {
+ if(me->id.lib) is_lib= TRUE;
+ else is_local= TRUE;
+ }
+ }
+ }
+ }
+ }
+
}
if(is_local && is_lib == FALSE) {
@@ -443,6 +462,28 @@ void make_local_image(struct Image *ima)
}
}
}
+
+ if(me->mtpoly) {
+ MTexPoly *mtpoly;
+ int a, i;
+
+ for(i=0; i<me->pdata.totlayer; i++) {
+ if(me->pdata.layers[i].type == CD_MTEXPOLY) {
+ mtpoly= (MTexPoly*)me->pdata.layers[i].data;
+
+ for(a=0; a<me->totpoly; a++, mtpoly++) {
+ if(mtpoly->tpage == ima) {
+ mtpoly->tpage = ima_new;
+ if(ima_new->id.us == 0) {
+ mtpoly->tpage->id.us= 1;
+ }
+ id_lib_extern((ID*)ima_new);
+ }
+ }
+ }
+ }
+ }
+
me= me->id.next;
}
}
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index b2385a5cdb8..84af6200f94 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -56,6 +56,7 @@
#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 "BKE_deform.h"
@@ -92,6 +93,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
@@ -114,6 +129,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) {
@@ -172,6 +189,34 @@ 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);
+
+ keyn->adt = NULL;
+
+ 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)
{
@@ -495,18 +540,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) {
copy_v3_v3(co[a], eve->co);
+ a++;
+ }
*freedata= (char*)co;
return (char*)co;
@@ -1000,8 +1048,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, defgrp_index= 0;
/* no vgroup string set? */
@@ -1013,8 +1062,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;
@@ -1033,8 +1082,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 = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BM_iter_step(&iter), i++) {
+ dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
if(dvert) {
weights[i]= defvert_find_weight(dvert, defgrp_index);
@@ -1451,7 +1501,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/library.c b/source/blender/blenkernel/intern/library.c
index d7985914f25..f9c52f3c2ba 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -820,7 +820,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 f9f02751d82..05c90bf4d0c 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -41,6 +41,7 @@
#include "DNA_key_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_ipo_types.h"
+#include "DNA_customdata_types.h"
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
@@ -48,9 +49,11 @@
#include "BLI_editVert.h"
#include "BLI_math.h"
#include "BLI_edgehash.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,24 +67,290 @@
#include "BKE_curve.h"
/* -- */
#include "BKE_object.h"
+#include "BKE_tessmesh.h"
+#include "BLI_edgehash.h"
-#ifdef USE_BMESH_FORWARD_COMPAT
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+#include "BLI_math.h"
#include "BLI_array.h"
-#endif
+#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,
+};
-EditMesh *BKE_mesh_get_editmesh(Mesh *me)
+static const char *cmpcode_to_str(int code)
{
- return me->edit_mesh;
+ 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:
+ return "CustomData Layer Count Mismatch";
+ default:
+ return "Mesh Comparison Code Unknown";
+ }
}
-void BKE_mesh_end_editmesh(Mesh *UNUSED(me), EditMesh *UNUSED(em))
+/*thresh is threshold for comparing vertices, uvs, vertex colors,
+ weights, etc.*/
+static 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;
}
+/*used for testing. returns an error string the two meshes don't match*/
+const char *mesh_cmp(Mesh *me1, Mesh *me2, float thresh)
+{
+ 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 mesh_update_customdata_pointers(Mesh *me)
+static void mesh_ensure_tesselation_customdata(Mesh *me)
{
+ const int tottex_original = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
+ const int totcol_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
+
+ const int tottex_tessface = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ const int totcol_tessface = CustomData_number_of_layers(&me->fdata, CD_MCOL);
+
+ if (tottex_tessface != tottex_original ||
+ totcol_tessface != totcol_original )
+ {
+ BKE_mesh_tessface_clear(me);
+
+ CustomData_from_bmeshpoly(&me->fdata, &me->pdata, &me->ldata, me->totface);
+
+ /* note: this warning may be un-called for if we are inirializing the mesh for the
+ * first time from bmesh, rather then giving a warning about this we could be smarter
+ * and check if there was any data to begin with, for now just print the warning with
+ * some info to help troubleshoot whats going on - campbell */
+ printf("%s: warning! Tesselation uvs or vcol data got out of sync, "
+ "had to reset!\n CD_MTFACE: %d != CD_MTEXPOLY: %d || CD_MCOL: %d != CD_MLOOPCOL: %d\n",
+ __func__, tottex_tessface, tottex_original, totcol_tessface, totcol_original);
+ }
+}
+
+/* this ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or
+ * mloopcol and mcol) have the same relative active/render/clone/mask indices.
+ *
+ * note that for undo mesh data we want to skip 'ensure_tess_cd' call since
+ * we dont want to store memory for tessface when its only used for older
+ * versions of the mesh. - campbell*/
+static void mesh_update_linked_customdata(Mesh *me, const short do_ensure_tess_cd)
+{
+ if (me->edit_btmesh)
+ BMEdit_UpdateLinkedCustomData(me->edit_btmesh);
+
+ if (do_ensure_tess_cd) {
+ mesh_ensure_tesselation_customdata(me);
+ }
+
+ CustomData_bmesh_update_active_layers(&me->fdata, &me->pdata, &me->ldata);
+}
+
+void mesh_update_customdata_pointers(Mesh *me, const short do_ensure_tess_cd)
+{
+ mesh_update_linked_customdata(me, do_ensure_tess_cd);
+
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);
@@ -91,6 +360,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
@@ -118,14 +394,17 @@ 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);
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;
@@ -135,7 +414,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)
@@ -194,6 +473,7 @@ Mesh *copy_mesh(Mesh *me)
{
Mesh *men;
MTFace *tface;
+ MTexPoly *txface;
int a, i;
men= copy_libblock(&me->id);
@@ -207,7 +487,9 @@ 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);
- mesh_update_customdata_pointers(men);
+ 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, TRUE);
/* ensure indirect linked data becomes lib-extern */
for(i=0; i<me->fdata.totlayer; i++) {
@@ -220,8 +502,18 @@ Mesh *copy_mesh(Mesh *me)
}
}
+ 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->edit_mesh= NULL;
+ men->edit_btmesh= NULL;
men->bb= MEM_dupallocN(men->bb);
@@ -231,21 +523,49 @@ Mesh *copy_mesh(Mesh *me)
return men;
}
+BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob)
+{
+ BMesh *bm;
+
+ bm = BM_mesh_create(ob, bm_mesh_allocsize_default);
+
+ BMO_op_callf(bm, "mesh_to_bmesh mesh=%p object=%p set_shapekey=%i", me, ob, 1);
+
+ return bm;
+}
+
static void expand_local_mesh(Mesh *me)
{
id_lib_extern((ID *)me->texcomesh);
- if(me->mtface) {
- MTFace *tface;
+ if(me->mtface || me->mtpoly) {
int a, i;
+ for(i=0; i<me->pdata.totlayer; i++) {
+ if(me->pdata.layers[i].type == CD_MTEXPOLY) {
+ 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) {
+ if(txface->tpage) {
+ id_lib_extern((ID *)txface->tpage);
+ }
+ }
+ }
+ }
+ }
+
for(i=0; i<me->fdata.totlayer; i++) {
if(me->fdata.layers[i].type == CD_MTFACE) {
- tface= (MTFace*)me->fdata.layers[i].data;
+ MTFace *tface= (MTFace*)me->fdata.layers[i].data;
for(a=0; a<me->totface; a++, tface++) {
+ /* special case: ima always local immediately */
if(tface->tpage) {
- id_lib_extern((ID *)tface->tpage);
+ if(tface->tpage) {
+ id_lib_extern((ID *)tface->tpage);
+ }
}
}
}
@@ -555,6 +875,10 @@ static int vergedgesort(const void *v1, const void *v2)
return 0;
}
+
+/* TODO: remove after bmesh merge */
+#if 0
+
static void mfaces_strip_loose(MFace *mface, int *totface)
{
int a,b;
@@ -571,14 +895,20 @@ static void mfaces_strip_loose(MFace *mface, int *totface)
*totface= b;
}
+#endif
+
/* Create edges based on known verts and faces */
-static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, int UNUSED(totvert), int totface,
+static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, MLoop *allloop,
+ MPoly *allpoly, int UNUSED(totvert), int totface, int UNUSED(totloop), int totpoly,
int old, MEdge **alledge, int *_totedge)
{
+ MPoly *mpoly;
+ MLoop *mloop;
MFace *mface;
MEdge *medge;
+ EdgeHash *hash = BLI_edgehash_new();
struct edgesort *edsort, *ed;
- int a, totedge=0, final=0;
+ int a, b, totedge=0, final=0;
/* we put all edges in array, sort them, and detect doubles that way */
@@ -650,6 +980,26 @@ static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, int UNUSED(
medge->flag |= ME_EDGERENDER;
MEM_freeN(edsort);
+
+ /*set edge members of mloops*/
+ medge= *alledge;
+ for (a=0; a<*_totedge; a++, medge++) {
+ BLI_edgehash_insert(hash, medge->v1, medge->v2, SET_INT_IN_POINTER(a));
+ }
+
+ mpoly = allpoly;
+ for (a=0; a<totpoly; a++, mpoly++) {
+ mloop = allloop + mpoly->loopstart;
+ for (b=0; b<mpoly->totloop; b++) {
+ int v1, v2;
+
+ v1 = mloop[b].v;
+ v2 = ME_POLY_LOOP_NEXT(mloop, mpoly, b)->v;
+ mloop[b].e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(hash, v1, v2));
+ }
+ }
+
+ BLI_edgehash_free(hash, NULL);
}
void make_edges(Mesh *me, int old)
@@ -657,7 +1007,7 @@ void make_edges(Mesh *me, int old)
MEdge *medge;
int totedge=0;
- make_edges_mdata(me->mvert, me->mface, me->totvert, me->totface, old, &medge, &totedge);
+ make_edges_mdata(me->mvert, me->mface, me->mloop, me->mpoly, me->totvert, me->totface, me->totloop, me->totpoly, old, &medge, &totedge);
if(totedge==0) {
/* flag that mesh has edges */
me->medge = medge;
@@ -753,29 +1103,42 @@ void mball_to_mesh(ListBase *lb, Mesh *me)
}
make_edges(me, 0); // all edges
- }
+
+
+ /* BMESH_TODO - low priority, should make polygons instead */
+ convert_mfaces_to_mpolys(me);
+
+ mesh_update_customdata_pointers(me, TRUE);
+ }
}
/* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */
/* return non-zero on error */
int nurbs_to_mdata(Object *ob, MVert **allvert, int *totvert,
- MEdge **alledge, int *totedge, MFace **allface, int *totface)
+ MEdge **alledge, int *totedge, MLoop **allloop, MPoly **allpoly,
+ int *totloop, int *totpoly)
{
return nurbs_to_mdata_customdb(ob, &ob->disp,
- allvert, totvert, alledge, totedge, allface, totface);
+ allvert, totvert, alledge, totedge, allloop, allpoly, totloop, totpoly);
}
+/* BMESH: this doesn't calculate all edges from polygons,
+ * only free standing edges are calculated */
+
/* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */
/* use specified dispbase */
int nurbs_to_mdata_customdb(Object *ob, ListBase *dispbase, MVert **allvert, int *_totvert,
- MEdge **alledge, int *_totedge, MFace **allface, int *_totface)
+ MEdge **alledge, int *_totedge, MLoop **allloop, MPoly **allpoly,
+ int *_totloop, int *_totpoly)
{
DispList *dl;
Curve *cu;
MVert *mvert;
- MFace *mface;
+ MPoly *mpoly;
+ MLoop *mloop;
+ MEdge *medge;
float *data;
- int a, b, ofs, vertcount, startvert, totvert=0, totvlak=0;
+ int a, b, ofs, vertcount, startvert, totvert=0, totedge=0, totloop=0, totvlak=0;
int p1, p2, p3, p4, *index;
int conv_polys= 0;
@@ -789,21 +1152,27 @@ int nurbs_to_mdata_customdb(Object *ob, ListBase *dispbase, MVert **allvert, int
while(dl) {
if(dl->type==DL_SEGM) {
totvert+= dl->parts*dl->nr;
- totvlak+= dl->parts*(dl->nr-1);
+ totedge+= dl->parts*(dl->nr-1);
}
else if(dl->type==DL_POLY) {
if(conv_polys) {
totvert+= dl->parts*dl->nr;
- totvlak+= dl->parts*dl->nr;
+ totedge+= dl->parts*dl->nr;
}
}
else if(dl->type==DL_SURF) {
+ int tot;
totvert+= dl->parts*dl->nr;
- totvlak+= (dl->parts-1+((dl->flag & DL_CYCL_V)==2))*(dl->nr-1+(dl->flag & DL_CYCL_U));
+ tot = (dl->parts-1+((dl->flag & DL_CYCL_V)==2))*(dl->nr-1+(dl->flag & DL_CYCL_U));
+ totvlak += tot;
+ totloop += tot * 4;
}
else if(dl->type==DL_INDEX3) {
+ int tot;
totvert+= dl->nr;
- totvlak+= dl->parts;
+ tot = dl->parts;
+ totvlak+= tot;
+ totloop += tot * 3;
}
dl= dl->next;
}
@@ -814,9 +1183,11 @@ int nurbs_to_mdata_customdb(Object *ob, ListBase *dispbase, MVert **allvert, int
return -1;
}
- *allvert= mvert= MEM_callocN(sizeof (MVert) * totvert, "nurbs_init mvert");
- *allface= mface= MEM_callocN(sizeof (MFace) * totvlak, "nurbs_init mface");
-
+ *allvert = mvert = MEM_callocN(sizeof(MVert) * totvert, "nurbs_init mvert");
+ *alledge = medge = MEM_callocN(sizeof(MEdge) * totedge, "nurbs_init medge");
+ *allloop = mloop = MEM_callocN(sizeof(MLoop) * totvlak * 4, "nurbs_init mloop"); // totloop
+ *allpoly = mpoly = MEM_callocN(sizeof(MPoly) * totvlak, "nurbs_init mloop");
+
/* verts and faces */
vertcount= 0;
@@ -838,10 +1209,11 @@ int nurbs_to_mdata_customdb(Object *ob, ListBase *dispbase, MVert **allvert, int
for(a=0; a<dl->parts; a++) {
ofs= a*dl->nr;
for(b=1; b<dl->nr; b++) {
- mface->v1= startvert+ofs+b-1;
- mface->v2= startvert+ofs+b;
- if(smooth) mface->flag |= ME_SMOOTH;
- mface++;
+ medge->v1= startvert+ofs+b-1;
+ medge->v2= startvert+ofs+b;
+ medge->flag = ME_LOOSEEDGE|ME_EDGERENDER;
+
+ medge++;
}
}
@@ -861,11 +1233,11 @@ int nurbs_to_mdata_customdb(Object *ob, ListBase *dispbase, MVert **allvert, int
for(a=0; a<dl->parts; a++) {
ofs= a*dl->nr;
for(b=0; b<dl->nr; b++) {
- mface->v1= startvert+ofs+b;
- if(b==dl->nr-1) mface->v2= startvert+ofs;
- else mface->v2= startvert+ofs+b+1;
- if(smooth) mface->flag |= ME_SMOOTH;
- mface++;
+ medge->v1= startvert+ofs+b;
+ if(b==dl->nr-1) medge->v2= startvert+ofs;
+ else medge->v2= startvert+ofs+b+1;
+ medge->flag = ME_LOOSEEDGE|ME_EDGERENDER;
+ medge++;
}
}
}
@@ -884,15 +1256,16 @@ int nurbs_to_mdata_customdb(Object *ob, ListBase *dispbase, MVert **allvert, int
a= dl->parts;
index= dl->index;
while(a--) {
- mface->v1= startvert+index[0];
- mface->v2= startvert+index[2];
- mface->v3= startvert+index[1];
- mface->v4= 0;
- mface->mat_nr= dl->col;
- test_index_face(mface, NULL, 0, 3);
-
- if(smooth) mface->flag |= ME_SMOOTH;
- mface++;
+ mloop[0].v = startvert+index[0];
+ mloop[1].v = startvert+index[2];
+ mloop[2].v = startvert+index[1];
+ mpoly->loopstart = (int)(mloop - (*allloop));
+ mpoly->totloop = 3;
+ mpoly->mat_nr = dl->col;
+
+ if(smooth) mpoly->flag |= ME_SMOOTH;
+ mpoly++;
+ mloop+= 3;
index+= 3;
}
@@ -933,15 +1306,17 @@ int nurbs_to_mdata_customdb(Object *ob, ListBase *dispbase, MVert **allvert, int
}
for(; b<dl->nr; b++) {
- mface->v1= p1;
- mface->v2= p3;
- mface->v3= p4;
- mface->v4= p2;
- mface->mat_nr= dl->col;
- test_index_face(mface, NULL, 0, 4);
-
- if(smooth) mface->flag |= ME_SMOOTH;
- mface++;
+ mloop[0].v= p1;
+ mloop[1].v= p3;
+ mloop[2].v= p4;
+ mloop[3].v= p2;
+ mpoly->loopstart = (int)(mloop - (*allloop));
+ mpoly->totloop = 4;
+ mpoly->mat_nr = dl->col;
+
+ if(smooth) mpoly->flag |= ME_SMOOTH;
+ mpoly++;
+ mloop+= 4;
p4= p3;
p3++;
@@ -954,12 +1329,17 @@ int nurbs_to_mdata_customdb(Object *ob, ListBase *dispbase, MVert **allvert, int
dl= dl->next;
}
-
+
+ *_totpoly= totvlak;
+ *_totloop= totloop;
+ *_totedge= totedge;
*_totvert= totvert;
- *_totface= totvlak;
- make_edges_mdata(*allvert, *allface, totvert, totvlak, 0, alledge, _totedge);
+ /* not uded for bmesh */
+#if 0
+ make_edges_mdata(*allvert, *allface, *allloop, *allpoly, totvert, totvlak, *_totloop, *_totpoly, 0, alledge, _totedge);
mfaces_strip_loose(*allface, _totface);
+#endif
return 0;
}
@@ -974,13 +1354,14 @@ void nurbs_to_mesh(Object *ob)
Curve *cu;
MVert *allvert= NULL;
MEdge *alledge= NULL;
- MFace *allface= NULL;
- int totvert, totedge, totface;
+ MLoop *allloop = NULL;
+ MPoly *allpoly = NULL;
+ int totvert, totedge, totloop, totpoly;
cu= ob->data;
if (dm == NULL) {
- if (nurbs_to_mdata (ob, &allvert, &totvert, &alledge, &totedge, &allface, &totface) != 0) {
+ if (nurbs_to_mdata (ob, &allvert, &totvert, &alledge, &totedge, &allloop, &allpoly, &totloop, &totpoly) != 0) {
/* Error initializing */
return;
}
@@ -988,17 +1369,21 @@ void nurbs_to_mesh(Object *ob)
/* make mesh */
me= add_mesh("Mesh");
me->totvert= totvert;
- me->totface= totface;
me->totedge= totedge;
+ me->totloop = totloop;
+ me->totpoly = totpoly;
me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, allvert, me->totvert);
me->medge= CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, alledge, me->totedge);
- me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, allface, me->totface);
+ me->mloop= CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, allloop, me->totloop);
+ me->mpoly= CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly);
- mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+ mesh_calc_normals(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL);
+
+ BKE_mesh_calc_edges(me, TRUE);
} else {
me= add_mesh("Mesh");
- DM_to_mesh(dm, me);
+ DM_to_mesh(dm, me, ob);
}
me->totcol= cu->totcol;
@@ -1059,10 +1444,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;
@@ -1225,10 +1610,16 @@ void mesh_to_curve(Scene *scene, Object *ob)
void mesh_delete_material_index(Mesh *me, short index)
{
- MFace *mf;
int i;
- for (i=0, mf=me->mface; i<me->totface; i++, mf++) {
+ for (i=0; i<me->totpoly; i++) {
+ MPoly *mp = &((MPoly*) me->mpoly)[i];
+ if (mp->mat_nr && mp->mat_nr>=index)
+ mp->mat_nr--;
+ }
+
+ for (i=0; i<me->totface; i++) {
+ MFace *mf = &((MFace*) me->mface)[i];
if (mf->mat_nr && mf->mat_nr>=index)
mf->mat_nr--;
}
@@ -1239,6 +1630,16 @@ void mesh_set_smooth_flag(Object *meshOb, int enableSmooth)
Mesh *me = meshOb->data;
int i;
+ for (i=0; i<me->totpoly; i++) {
+ MPoly *mp = &((MPoly*) me->mpoly)[i];
+
+ if (enableSmooth) {
+ mp->flag |= ME_SMOOTH;
+ } else {
+ mp->flag &= ~ME_SMOOTH;
+ }
+ }
+
for (i=0; i<me->totface; i++) {
MFace *mf = &((MFace*) me->mface)[i];
@@ -1250,7 +1651,139 @@ void mesh_set_smooth_flag(Object *meshOb, int enableSmooth)
}
}
-void mesh_calc_normals(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float (*faceNors_r)[3])
+void mesh_calc_normals_mapping(MVert *mverts, int numVerts,
+ MLoop *mloop, MPoly *mpolys, int numLoops, int numPolys, float (*polyNors_r)[3],
+ MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3])
+{
+ mesh_calc_normals_mapping_ex(mverts, numVerts, mloop, mpolys,
+ numLoops, numPolys, polyNors_r, mfaces, numFaces,
+ origIndexFace, faceNors_r, TRUE);
+}
+
+void mesh_calc_normals_mapping_ex(MVert *mverts, int numVerts,
+ MLoop *mloop, MPoly *mpolys,
+ int numLoops, int numPolys, float (*polyNors_r)[3],
+ MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3],
+ const short only_face_normals)
+{
+ float (*pnors)[3] = polyNors_r, (*fnors)[3] = faceNors_r;
+ int i;
+ MFace *mf;
+ MPoly *mp;
+
+ if (numPolys == 0) {
+ return;
+ }
+
+ /* if we are not calculating verts and no verts were passes thene we have nothign to do */
+ if ((only_face_normals == TRUE) && (polyNors_r == NULL) && (faceNors_r == NULL)) {
+ printf("%s: called with nothing to do\n", __func__);
+ return;
+ }
+
+ if (!pnors) pnors = MEM_callocN(sizeof(float) * 3 * numPolys, "poly_nors mesh.c");
+ /* if (!fnors) fnors = MEM_callocN(sizeof(float) * 3 * numFaces, "face nors mesh.c"); */ /* NO NEED TO ALLOC YET */
+
+
+ if (only_face_normals == FALSE) {
+ /* vertex normals are optional, they require some extra calculations,
+ * so make them optional */
+ mesh_calc_normals(mverts, numVerts, mloop, mpolys, numLoops, numPolys, pnors);
+ }
+ else {
+ /* only calc poly normals */
+ mp = mpolys;
+ for (i=0; i<numPolys; i++, mp++) {
+ mesh_calc_poly_normal(mp, mloop+mp->loopstart, mverts, pnors[i]);
+ }
+ }
+
+ if ( origIndexFace &&
+ /* fnors==faceNors_r */ /* NO NEED TO ALLOC YET */
+ fnors != NULL &&
+ numFaces)
+ {
+ mf = mfaces;
+ for (i=0; i<numFaces; i++, mf++, origIndexFace++) {
+ if (*origIndexFace < numPolys) {
+ copy_v3_v3(fnors[i], pnors[*origIndexFace]);
+ } else {
+ /*eek, we're not corrusponding to polys*/
+ printf("error in mesh_calc_normals; tesselation face indices are incorrect. normals may look bad.\n");
+ }
+ }
+ }
+
+ if (pnors != polyNors_r) MEM_freeN(pnors);
+ /* if (fnors != faceNors_r) MEM_freeN(fnors); */ /* NO NEED TO ALLOC YET */
+
+ fnors = pnors = NULL;
+
+}
+
+void mesh_calc_normals(MVert *mverts, int numVerts, MLoop *mloop, MPoly *mpolys,
+ int UNUSED(numLoops), int numPolys, float (*polyNors_r)[3])
+{
+ float (*pnors)[3] = polyNors_r;
+
+ float (*tnorms)[3], (*edgevecbuf)[3]= NULL;
+ float **vertcos = NULL, **vertnos = NULL;
+ BLI_array_declare(vertcos);
+ BLI_array_declare(vertnos);
+ BLI_array_declare(edgevecbuf);
+
+ int i, j;
+ MPoly *mp;
+ MLoop *ml;
+
+ if (!pnors) pnors = MEM_callocN(sizeof(float) * 3 * numPolys, "poly_nors mesh.c");
+
+ /*first go through and calculate normals for all the polys*/
+ tnorms = MEM_callocN(sizeof(float)*3*numVerts, "tnorms mesh.c");
+
+ mp = mpolys;
+ for (i=0; i<numPolys; i++, mp++) {
+ mesh_calc_poly_normal(mp, mloop+mp->loopstart, mverts, pnors[i]);
+ ml = mloop + mp->loopstart;
+
+ BLI_array_empty(vertcos);
+ BLI_array_empty(vertnos);
+ BLI_array_growitems(vertcos, mp->totloop);
+ BLI_array_growitems(vertnos, mp->totloop);
+
+ for (j=0; j < mp->totloop; j++) {
+ int vindex = ml[j].v;
+ vertcos[j] = mverts[vindex].co;
+ vertnos[j] = tnorms[vindex];
+ }
+
+ BLI_array_empty(edgevecbuf);
+ BLI_array_growitems(edgevecbuf, mp->totloop);
+
+ accumulate_vertex_normals_poly(vertnos, pnors[i], vertcos, edgevecbuf, mp->totloop);
+ }
+
+ BLI_array_free(vertcos);
+ BLI_array_free(vertnos);
+ BLI_array_free(edgevecbuf);
+
+ /* following Mesh convention; we use vertex coordinate itself for normal in this case */
+ for(i=0; i<numVerts; i++) {
+ MVert *mv= &mverts[i];
+ float *no= tnorms[i];
+
+ if(normalize_v3(no) == 0.0f)
+ normalize_v3_v3(no, mv->co);
+
+ normal_float_to_short_v3(mv->no, no);
+ }
+
+ MEM_freeN(tnorms);
+
+ if (pnors != polyNors_r) MEM_freeN(pnors);
+}
+
+void mesh_calc_normals_tessface(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float (*faceNors_r)[3])
{
float (*tnorms)[3]= MEM_callocN(numVerts*sizeof(*tnorms), "tnorms");
float (*fnors)[3]= (faceNors_r)? faceNors_r: MEM_callocN(sizeof(*fnors)*numFaces, "meshnormals");
@@ -1288,6 +1821,154 @@ void mesh_calc_normals(MVert *mverts, int numVerts, MFace *mfaces, int numFaces,
MEM_freeN(fnors);
}
+
+static 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;
+
+ mf = me->mface + findex;
+
+ 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);
+
+ ME_MTEXFACE_CPY(texpoly, texface);
+
+ mloopuv = CustomData_get_n(&me->ldata, CD_MLOOPUV, loopstart, i);
+ copy_v2_v2(mloopuv->uv, texface->uv[0]); mloopuv++;
+ copy_v2_v2(mloopuv->uv, texface->uv[1]); mloopuv++;
+ copy_v2_v2(mloopuv->uv, texface->uv[2]); mloopuv++;
+
+ if (mf->v4) {
+ copy_v2_v2(mloopuv->uv, texface->uv[3]); mloopuv++;
+ }
+ }
+
+ for(i=0; i < numCol; i++){
+ 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++;
+ }
+ }
+
+ if (CustomData_has_layer(&me->fdata, CD_MDISPS)) {
+ MDisps *ld = CustomData_get(&me->ldata, loopstart, CD_MDISPS);
+ MDisps *fd = CustomData_get(&me->fdata, findex, CD_MDISPS);
+ float (*disps)[3] = fd->disps;
+ int i, tot = mf->v4 ? 4 : 3;
+ int side, corners;
+
+ corners = multires_mdisp_corners(fd);
+
+ if (corners == 0) {
+ /* Empty MDisp layers appear in at least one of the sintel.blend files.
+ Not sure why this happens, but it seems fine to just ignore them here.
+ If corners==0 for a non-empty layer though, something went wrong. */
+ BLI_assert(fd->totdisp == 0);
+ }
+ else {
+ side = sqrt(fd->totdisp / corners);
+
+ for (i=0; i<tot; i++, disps += side*side, ld++) {
+ ld->totdisp = side*side;
+
+ if (ld->disps)
+ MEM_freeN(ld->disps);
+
+ ld->disps = MEM_callocN(sizeof(float)*3*side*side, "converted loop mdisps");
+ if (fd->disps) {
+ memcpy(ld->disps, disps, sizeof(float)*3*side*side);
+ }
+ }
+ }
+ }
+}
+
+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);
+ }
+
+ /* note, we dont convert FGons at all, these are not even real ngons,
+ * they have their own UV's, colors etc - its more an editing feature. */
+
+ mesh_update_customdata_pointers(mesh, TRUE);
+
+ BLI_edgehash_free(eh, NULL);
+}
+
float (*mesh_getVertexCos(Mesh *me, int *numVerts_r))[3]
{
int i, numVerts = me->totvert;
@@ -1300,21 +1981,26 @@ float (*mesh_getVertexCos(Mesh *me, int *numVerts_r))[3]
return cos;
}
-UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned int totface, unsigned int totvert, int selected, float *limit)
+
+/* ngon version wip, based on EDBM_make_uv_vert_map */
+/* this replaces the non bmesh function (in trunk) which takes MTFace's, if we ever need it back we could
+ * but for now this replaces it because its unused. */
+
+UvVertMap *make_uv_vert_map(struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv, unsigned int totpoly, unsigned int totvert, int selected, float *limit)
{
UvVertMap *vmap;
UvMapVert *buf;
- MFace *mf;
+ MPoly *mp;
unsigned int a;
int i, totuv, nverts;
totuv = 0;
/* generate UvMapVert array */
- mf= mface;
- for(a=0; a<totface; a++, mf++)
- if(!selected || (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL)))
- totuv += (mf->v4)? 4: 3;
+ mp= mpoly;
+ for(a=0; a<totpoly; a++, mp++)
+ if(!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL)))
+ totuv += mp->totloop;
if(totuv==0)
return NULL;
@@ -1331,17 +2017,17 @@ UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned
return NULL;
}
- mf= mface;
- for(a=0; a<totface; a++, mf++) {
- if(!selected || (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL))) {
- nverts= (mf->v4)? 4: 3;
+ mp= mpoly;
+ for(a=0; a<totpoly; a++, mp++) {
+ if(!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) {
+ nverts= mp->totloop;
for(i=0; i<nverts; i++) {
buf->tfindex= i;
buf->f= a;
buf->separate = 0;
- buf->next= vmap->vert[*(&mf->v1 + i)];
- vmap->vert[*(&mf->v1 + i)]= buf;
+ buf->next= vmap->vert[mloop[mp->loopstart + i].v];
+ vmap->vert[mloop[mp->loopstart + i].v]= buf;
buf++;
}
}
@@ -1359,14 +2045,14 @@ UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned
v->next= newvlist;
newvlist= v;
- uv= tface[v->f].uv[v->tfindex];
+ uv= mloopuv[mpoly[v->f].loopstart + v->tfindex].uv;
lastv= NULL;
iterv= vlist;
while(iterv) {
next= iterv->next;
- uv2= tface[iterv->f].uv[iterv->tfindex];
+ uv2= mloopuv[mpoly[iterv->f].loopstart + iterv->tfindex].uv;
sub_v2_v2v2(uvdiff, uv2, uv);
@@ -1406,6 +2092,32 @@ void free_uv_vert_map(UvVertMap *vmap)
}
/* Generates a map where the key is the vertex and the value is a list
+ of polys that use that vertex as a corner. The lists are allocated
+ from one memory pool. */
+void create_vert_poly_map(ListBase **map, IndexNode **mem,
+ MPoly *mpoly, MLoop *mloop,
+ const int totvert, const int totpoly, const int totloop)
+{
+ int i,j;
+ IndexNode *node = NULL;
+ MPoly *mp;
+ MLoop *ml;
+
+ (*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert face map");
+ (*mem) = MEM_callocN(sizeof(IndexNode) * totloop, "vert poly map mem");
+ node = *mem;
+
+ /* Find the users */
+ for(i = 0, mp = mpoly; i < totpoly; ++i, ++mp){
+ ml = &mloop[mp->loopstart];
+ for(j = 0; j < mp->totloop; ++j, ++node, ++ml) {
+ node->index = i;
+ BLI_addtail(&(*map)[ml->v], node);
+ }
+ }
+}
+
+/* Generates a map where the key is the vertex and the value is a list
of faces that use that vertex as a corner. The lists are allocated
from one memory pool. */
void create_vert_face_map(ListBase **map, IndexNode **mem, const MFace *mface, const int totvert, const int totface)
@@ -1447,8 +2159,6 @@ void create_vert_edge_map(ListBase **map, IndexNode **mem, const MEdge *medge, c
}
}
-#ifdef USE_BMESH_FORWARD_COMPAT
-
void mesh_loops_to_mface_corners(CustomData *fdata, CustomData *ldata,
CustomData *pdata, int lindex[4], int findex,
const int polyindex,
@@ -1457,7 +2167,8 @@ void mesh_loops_to_mface_corners(CustomData *fdata, CustomData *ldata,
/* cache values to avoid lookups every time */
const int numTex, /* CustomData_number_of_layers(pdata, CD_MTEXPOLY) */
const int numCol, /* CustomData_number_of_layers(ldata, CD_MLOOPCOL) */
- const int hasWCol /* CustomData_has_layer(ldata, CD_WEIGHT_MLOOPCOL) */
+ const int hasWCol, /* CustomData_has_layer(ldata, CD_WEIGHT_MLOOPCOL) */
+ const int hasOrigSpace /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */
)
{
MTFace *texface;
@@ -1470,18 +2181,12 @@ void mesh_loops_to_mface_corners(CustomData *fdata, CustomData *ldata,
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;
+
+ ME_MTEXFACE_CPY(texface, texpoly);
for (j=0; j < mf_len; 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];
+ copy_v2_v2(texface->uv[j], mloopuv->uv);
}
}
@@ -1508,8 +2213,300 @@ void mesh_loops_to_mface_corners(CustomData *fdata, CustomData *ldata,
mcol[j].a = mloopcol->a;
}
}
+
+ if (hasOrigSpace) {
+ OrigSpaceFace *of = CustomData_get(fdata, findex, CD_ORIGSPACE);
+ OrigSpaceLoop *lof;
+
+ for (j=0; j < mf_len; j++) {
+ lof = CustomData_get(ldata, lindex[j], CD_ORIGSPACE_MLOOP);
+ of->uv[j][0] = lof->uv[0];
+ of->uv[j][1] = lof->uv[1];
+ }
+ }
}
+/*
+ this function recreates a tesselation.
+ returns number of tesselation faces.
+ */
+int mesh_recalcTesselation(CustomData *fdata,
+ CustomData *ldata, CustomData *pdata,
+ MVert *mvert, int totface, int UNUSED(totloop),
+ int totpoly,
+ /* when teseelating to recalcilate normals after
+ * we can skip copying here */
+ const int do_face_nor_cpy)
+{
+
+ /* use this to avoid locking pthread for _every_ polygon
+ * and calling the fill function */
+
+#define USE_TESSFACE_SPEEDUP
+#define USE_TESSFACE_QUADS // NEEDS FURTHER TESTING
+
+#define TESSFACE_SCANFILL (1<<0)
+#define TESSFACE_IS_QUAD (1<<1)
+
+ MPoly *mp, *mpoly;
+ MLoop *ml, *mloop;
+ MFace *mface = NULL, *mf;
+ BLI_array_declare(mface);
+ EditVert *v, *lastv, *firstv;
+ EditFace *f;
+ int *mface_orig_index = NULL;
+ BLI_array_declare(mface_orig_index);
+ int *mface_to_poly_map = NULL;
+ BLI_array_declare(mface_to_poly_map);
+ int lindex[4]; /* only ever use 3 in this case */
+ int *poly_orig_index;
+ int poly_index, j, mface_index;
+
+ const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
+ const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
+ const int hasWCol = CustomData_has_layer(ldata, CD_WEIGHT_MLOOPCOL);
+ const int hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
+
+ mpoly = CustomData_get_layer(pdata, CD_MPOLY);
+ mloop = CustomData_get_layer(ldata, CD_MLOOP);
+
+ /* allocate the length of totfaces, avoid many small reallocs,
+ * if all faces are tri's it will be correct, quads == 2x allocs */
+ BLI_array_reserve(mface_to_poly_map, totpoly);
+ BLI_array_reserve(mface, totpoly);
+
+ mface_index = 0;
+ mp = mpoly;
+ poly_orig_index = CustomData_get_layer(pdata, CD_ORIGINDEX);
+ for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) {
+ if (mp->totloop < 3) {
+ /* do nothing */
+ }
+
+#ifdef USE_TESSFACE_SPEEDUP
+
+#define ML_TO_MF(i1, i2, i3) \
+ BLI_array_growone(mface_to_poly_map); \
+ BLI_array_growone(mface); \
+ mface_to_poly_map[mface_index] = poly_index; \
+ mf= &mface[mface_index]; \
+ /* set loop indices, transformed to vert indices later */ \
+ mf->v1 = mp->loopstart + i1; \
+ mf->v2 = mp->loopstart + i2; \
+ mf->v3 = mp->loopstart + i3; \
+ mf->v4 = 0; \
+ mf->mat_nr = mp->mat_nr; \
+ mf->flag = mp->flag; \
+ if (poly_orig_index) { \
+ BLI_array_append(mface_orig_index, \
+ poly_orig_index[poly_index]); \
+ } \
+
+/* ALMOST IDENTICAL TO DEFINE ABOVE (see EXCEPTION) */
+#define ML_TO_MF_QUAD() \
+ BLI_array_growone(mface_to_poly_map); \
+ BLI_array_growone(mface); \
+ mface_to_poly_map[mface_index] = poly_index; \
+ mf= &mface[mface_index]; \
+ /* set loop indices, transformed to vert indices later */ \
+ mf->v1 = mp->loopstart + 0; /* EXCEPTION */ \
+ mf->v2 = mp->loopstart + 1; /* EXCEPTION */ \
+ mf->v3 = mp->loopstart + 2; /* EXCEPTION */ \
+ mf->v4 = mp->loopstart + 3; /* EXCEPTION */ \
+ mf->mat_nr = mp->mat_nr; \
+ mf->flag = mp->flag; \
+ if (poly_orig_index) { \
+ BLI_array_append(mface_orig_index, \
+ poly_orig_index[poly_index]); \
+ } \
+ mf->edcode |= TESSFACE_IS_QUAD; /* EXCEPTION */ \
+
+
+ else if (mp->totloop == 3) {
+ ml = mloop + mp->loopstart;
+ ML_TO_MF(0, 1, 2)
+ mface_index++;
+ }
+ else if (mp->totloop == 4) {
+#ifdef USE_TESSFACE_QUADS
+ ml = mloop + mp->loopstart;
+ ML_TO_MF_QUAD()
+ mface_index++;
+#else
+ ml = mloop + mp->loopstart;
+ ML_TO_MF(0, 1, 2)
+ mface_index++;
+ ML_TO_MF(0, 2, 3)
+ mface_index++;
+#endif
+ }
+#endif /* USE_TESSFACE_SPEEDUP */
+ else {
+ int totfilltri;
+
+ ml = mloop + mp->loopstart;
+
+ BLI_begin_edgefill();
+ firstv = NULL;
+ lastv = NULL;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ v = BLI_addfillvert(mvert[ml->v].co);
+
+ v->keyindex = mp->loopstart + j;
+
+ if (lastv)
+ BLI_addfilledge(lastv, v);
+
+ if (!firstv)
+ firstv = v;
+ lastv = v;
+ }
+ BLI_addfilledge(lastv, firstv);
+
+ totfilltri = BLI_edgefill(2);
+ if (totfilltri) {
+ BLI_array_growitems(mface_to_poly_map, totfilltri);
+ BLI_array_growitems(mface, totfilltri);
+ if (poly_orig_index) {
+ BLI_array_growitems(mface_orig_index, totfilltri);
+ }
+
+ for (f = fillfacebase.first; f; f = f->next, mf++) {
+ mface_to_poly_map[mface_index] = poly_index;
+ mf= &mface[mface_index];
+
+ /* set loop indices, transformed to vert indices later */
+ mf->v1 = f->v1->keyindex;
+ mf->v2 = f->v2->keyindex;
+ mf->v3 = f->v3->keyindex;
+ mf->v4 = 0;
+
+ mf->mat_nr = mp->mat_nr;
+ mf->flag = mp->flag;
+
+#ifdef USE_TESSFACE_SPEEDUP
+ mf->edcode |= TESSFACE_SCANFILL; /* tag for sorting loop indicies */
+#endif
+
+ if (poly_orig_index) {
+ mface_orig_index[mface_index] = poly_orig_index[poly_index];
+ }
+
+ mface_index++;
+ }
+ }
+
+ BLI_end_edgefill();
+ }
+ }
+
+ CustomData_free(fdata, totface);
+ memset(fdata, 0, sizeof(CustomData));
+ totface = mface_index;
+
+
+ /* note essential but without this we store over-alloc'd memory in the CustomData layers */
+ if (LIKELY((MEM_allocN_len(mface) / sizeof(*mface)) != totface)) {
+ mface = MEM_reallocN(mface, sizeof(*mface) * totface);
+ mface_to_poly_map = MEM_reallocN(mface_to_poly_map, sizeof(*mface_to_poly_map) * totface);
+ if (mface_orig_index) {
+ mface_orig_index = MEM_reallocN(mface_orig_index, sizeof(*mface_orig_index) * totface);
+ }
+ }
+
+ CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface);
+
+ /* CD_POLYINDEX will contain an array of indices from tessfaces to the polygons
+ * they are directly tesselated from */
+ CustomData_add_layer(fdata, CD_POLYINDEX, CD_ASSIGN, mface_to_poly_map, totface);
+ if (mface_orig_index) {
+ /* If polys had a CD_ORIGINDEX layer, then the tesselated faces will get this
+ * layer as well, pointing to polys from the original mesh (not the polys
+ * that just got tesselated) */
+ CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_orig_index, totface);
+ }
+
+ CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
+
+ if (do_face_nor_cpy) {
+ /* If polys have a normals layer, copying that to faces can help
+ * avoid the need to recalculate normals later */
+ if (CustomData_has_layer(pdata, CD_NORMAL)) {
+ float (*pnors)[3] = CustomData_get_layer(pdata, CD_NORMAL);
+ float (*fnors)[3] = CustomData_add_layer(fdata, CD_NORMAL, CD_CALLOC, NULL, totface);
+ for (mface_index = 0; mface_index < totface; mface_index++) {
+ copy_v3_v3(fnors[mface_index], pnors[mface_to_poly_map[mface_index]]);
+ }
+ }
+ }
+
+ mf = mface;
+ for (mface_index=0; mface_index < totface; mface_index++, mf++) {
+
+#ifdef USE_TESSFACE_QUADS
+ const int mf_len = mf->edcode & TESSFACE_IS_QUAD ? 4 : 3;
+#endif
+
+#ifdef USE_TESSFACE_SPEEDUP
+ /* skip sorting when not using ngons */
+ if (UNLIKELY(mf->edcode & TESSFACE_SCANFILL))
+#endif
+ {
+ /* 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);
+ }
+
+ /* end abusing the edcode */
+#if defined(USE_TESSFACE_QUADS) || defined(USE_TESSFACE_SPEEDUP)
+ mf->edcode = 0;
+#endif
+
+
+ lindex[0] = mf->v1;
+ lindex[1] = mf->v2;
+ lindex[2] = mf->v3;
+#ifdef USE_TESSFACE_QUADS
+ if (mf_len == 4) lindex[3] = mf->v4;
+#endif
+
+ /*transform loop indices to vert indices*/
+ mf->v1 = mloop[mf->v1].v;
+ mf->v2 = mloop[mf->v2].v;
+ mf->v3 = mloop[mf->v3].v;
+#ifdef USE_TESSFACE_QUADS
+ if (mf_len == 4) mf->v4 = mloop[mf->v4].v;
+#endif
+
+ mesh_loops_to_mface_corners(fdata, ldata, pdata,
+ lindex, mface_index, mface_to_poly_map[mface_index],
+#ifdef USE_TESSFACE_QUADS
+ mf_len,
+#else
+ 3,
+#endif
+ numTex, numCol, hasWCol, hasOrigSpace);
+
+
+#ifdef USE_TESSFACE_QUADS
+ test_index_face(mf, fdata, mface_index, mf_len);
+#endif
+
+ }
+
+ return totface;
+
+#undef USE_TESSFACE_SPEEDUP
+
+}
+
+
+#ifdef USE_BMESH_SAVE_AS_COMPAT
/*
* this function recreates a tesselation.
@@ -1531,6 +2528,7 @@ int mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
const int hasWCol = CustomData_has_layer(ldata, CD_WEIGHT_MLOOPCOL);
+ const int hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
mpoly = CustomData_get_layer(pdata, CD_MPOLY);
mloop = CustomData_get_layer(ldata, CD_MLOOP);
@@ -1588,7 +2586,7 @@ int mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
mesh_loops_to_mface_corners(fdata, ldata, pdata,
lindex, k, i, 3,
- numTex, numCol, hasWCol);
+ numTex, numCol, hasWCol, hasOrigSpace);
test_index_face(mf, fdata, k, 3);
}
else {
@@ -1608,7 +2606,7 @@ int mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
mesh_loops_to_mface_corners(fdata, ldata, pdata,
lindex, k, i, 4,
- numTex, numCol, hasWCol);
+ numTex, numCol, hasWCol, hasOrigSpace);
test_index_face(mf, fdata, k, 4);
}
@@ -1620,10 +2618,261 @@ int mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
return k;
}
+#endif /* USE_BMESH_SAVE_AS_COMPAT */
+
+/*
+ * 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[3])
+{
+
+ MVert *v1, *v2, *v3;
+ double u[3], v[3], w[3];
+ double n[3] = {0.0, 0.0, 0.0}, l;
+ int i;
+
+ 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[3])
+{
+ if (mpoly->totloop > 4) {
+ mesh_calc_ngon_normal(mpoly, loopstart, mvarray, no);
+ }
+ else if (mpoly->totloop == 3){
+ normal_tri_v3(no,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co
+ );
+ }
+ else if (mpoly->totloop == 4) {
+ normal_quad_v3(no,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co,
+ mvarray[loopstart[3].v].co
+ );
+ }
+ else { /* horrible, two sided face! */
+ no[0] = 0.0;
+ no[1] = 0.0;
+ no[2] = 1.0;
+ }
+}
+/* duplicate of function above _but_ takes coords rather then mverts */
+static void mesh_calc_ngon_normal_coords(MPoly *mpoly, MLoop *loopstart,
+ const float (*vertex_coords)[3], float normal[3])
+{
+
+ const float *v1, *v2, *v3;
+ double u[3], v[3], w[3];
+ double n[3] = {0.0, 0.0, 0.0}, l;
+ int i;
+
+ for(i = 0; i < mpoly->totloop; i++){
+ v1 = (const float *)(vertex_coords + loopstart[i].v);
+ v2 = (const float *)(vertex_coords + loopstart[(i+1)%mpoly->totloop].v);
+ v3 = (const float *)(vertex_coords + loopstart[(i+2)%mpoly->totloop].v);
+
+ VECCOPY(u, v1);
+ VECCOPY(v, v2);
+ VECCOPY(w, v3);
+
+ /*this fixes some weird numerical error*/
+ if (i==0) {
+ u[0] += 0.0001f;
+ u[1] += 0.0001f;
+ u[2] += 0.0001f;
+ }
+
+ 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_coords(MPoly *mpoly, MLoop *loopstart,
+ const float (*vertex_coords)[3], float no[3])
+{
+ if (mpoly->totloop > 4) {
+ mesh_calc_ngon_normal_coords(mpoly, loopstart, vertex_coords, no);
+ }
+ else if (mpoly->totloop == 3){
+ normal_tri_v3(no,
+ vertex_coords[loopstart[0].v],
+ vertex_coords[loopstart[1].v],
+ vertex_coords[loopstart[2].v]
+ );
+ }
+ else if (mpoly->totloop == 4) {
+ normal_quad_v3(no,
+ vertex_coords[loopstart[0].v],
+ vertex_coords[loopstart[1].v],
+ vertex_coords[loopstart[2].v],
+ vertex_coords[loopstart[3].v]
+ );
+ }
+ else { /* horrible, two sided face! */
+ no[0] = 0.0;
+ no[1] = 0.0;
+ no[2] = 1.0;
+ }
+}
+
+static void mesh_calc_ngon_center(MPoly *mpoly, MLoop *loopstart,
+ MVert *mvert, float cent[3])
+{
+ const float w= 1.0f / (float)mpoly->totloop;
+ int i;
+
+ zero_v3(cent);
+
+ for (i = 0; i < mpoly->totloop; i++) {
+ madd_v3_v3fl(cent, mvert[(loopstart++)->v].co, w);
+ }
+}
+
+void mesh_calc_poly_center(MPoly *mpoly, MLoop *loopstart,
+ MVert *mvarray, float cent[3])
+{
+ if (mpoly->totloop == 3) {
+ cent_tri_v3(cent,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co
+ );
+ }
+ else if (mpoly->totloop == 4) {
+ cent_quad_v3(cent,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co,
+ mvarray[loopstart[3].v].co
+ );
+ }
+ else {
+ mesh_calc_ngon_center(mpoly, loopstart, mvarray, cent);
+ }
+}
+
+/* note, passing polynormal is only a speedup so we can skip calculating it */
+float mesh_calc_poly_area(MPoly *mpoly, MLoop *loopstart,
+ MVert *mvarray, float polynormal[3])
+{
+ if (mpoly->totloop == 3) {
+ return area_tri_v3(mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co
+ );
+ }
+ else if (mpoly->totloop == 4) {
+ return area_quad_v3(mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co,
+ mvarray[loopstart[3].v].co
+ );
+ }
+ else {
+ int i;
+ float area, polynorm_local[3], (*vertexcos)[3];
+ float *no= polynormal ? polynormal : polynorm_local;
+ BLI_array_fixedstack_declare(vertexcos, BM_NGON_STACK_SIZE, mpoly->totloop, __func__);
-#endif /* USE_BMESH_FORWARD_COMPAT */
+ /* pack vertex cos into an array for area_poly_v3 */
+ for (i = 0; i < mpoly->totloop; i++) {
+ copy_v3_v3(vertexcos[i], mvarray[(loopstart++)->v].co);
+ }
+ /* need normal for area_poly_v3 as well */
+ if (polynormal == NULL) {
+ mesh_calc_poly_normal(mpoly, loopstart, mvarray, no);
+ }
+ /* finally calculate the area */
+ area = area_poly_v3(mpoly->totloop, vertexcos, no);
+
+ BLI_array_fixedstack_free(vertexcos);
+
+ return area;
+ }
+}
/* basic vertex data functions */
int minmax_mesh(Mesh *me, float min[3], float max[3])
@@ -1687,15 +2936,45 @@ void mesh_translate(Mesh *me, float offset[3], int do_keys)
void BKE_mesh_ensure_navmesh(Mesh *me)
{
- if (!CustomData_has_layer(&me->fdata, CD_RECAST)) {
+ if (!CustomData_has_layer(&me->pdata, CD_RECAST)) {
int i;
- int numFaces = me->totface;
+ int numFaces = me->totpoly;
int* recastData;
- CustomData_add_layer_named(&me->fdata, CD_RECAST, CD_CALLOC, NULL, numFaces, "recastData");
- recastData = (int*)CustomData_get_layer(&me->fdata, CD_RECAST);
+ CustomData_add_layer_named(&me->pdata, CD_RECAST, CD_CALLOC, NULL, numFaces, "recastData");
+ recastData = (int*)CustomData_get_layer(&me->pdata, CD_RECAST);
for (i=0; i<numFaces; i++) {
recastData[i] = i+1;
}
- CustomData_add_layer_named(&me->fdata, CD_RECAST, CD_REFERENCE, recastData, numFaces, "recastData");
+ CustomData_add_layer_named(&me->pdata, CD_RECAST, CD_REFERENCE, recastData, numFaces, "recastData");
+ }
+}
+
+void BKE_mesh_tessface_calc(Mesh *mesh)
+{
+ mesh->totface = mesh_recalcTesselation(&mesh->fdata, &mesh->ldata, &mesh->pdata,
+ mesh->mvert,
+ mesh->totface, mesh->totloop, mesh->totpoly,
+ /* calc normals right after, dont copy from polys here */
+ FALSE);
+
+ mesh_update_customdata_pointers(mesh, TRUE);
+}
+
+void BKE_mesh_tessface_ensure(Mesh *mesh)
+{
+ if (mesh->totpoly && mesh->totface == 0) {
+ BKE_mesh_tessface_calc(mesh);
}
}
+
+void BKE_mesh_tessface_clear(Mesh *mesh)
+{
+ CustomData_free(&mesh->fdata, mesh->totface);
+
+ mesh->mface = NULL;
+ mesh->mtface = NULL;
+ mesh->mcol = NULL;
+ mesh->totface = 0;
+
+ memset(&mesh->fdata, 0, sizeof(&mesh->fdata));
+}
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index ed9b63fe98d..92f7f959f8a 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -451,11 +451,11 @@ 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),
- dm->getVertDataArray(dm, CD_MDEFORMVERT),
- TRUE, FALSE);
+ dm->getVertArray(dm), dm->getNumVerts(dm),
+ dm->getEdgeArray(dm), dm->getNumEdges(dm),
+ dm->getTessFaceArray(dm), dm->getNumTessFaces(dm),
+ dm->getVertDataArray(dm, CD_MDEFORMVERT),
+ TRUE, FALSE);
}
void BKE_mesh_calc_edges(Mesh *mesh, int update)
@@ -466,6 +466,7 @@ void BKE_mesh_calc_edges(Mesh *mesh, int update)
MEdge *med, *med_orig;
EdgeHash *eh = BLI_edgehash_new();
int i, totedge, totface = mesh->totface;
+ int med_index;
if(mesh->totedge==0)
update= 0;
@@ -478,20 +479,37 @@ void BKE_mesh_calc_edges(Mesh *mesh, int update)
BLI_edgehash_insert(eh, med->v1, med->v2, med);
}
- for (i = 0; i < totface; i++, mf++) {
- if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2))
- BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL);
- if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3))
- BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL);
-
- if (mf->v4) {
- if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4))
- BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL);
- if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1))
- BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL);
- } else {
- if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1))
- BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL);
+ if(mesh->totpoly) {
+ /* mesh loops (bmesh only) */
+ MPoly *mp= mesh->mpoly;
+ for(i=0; i < mesh->totpoly; i++, mp++) {
+ MLoop *l= &mesh->mloop[mp->loopstart];
+ int j, l_prev= (l + (mp->totloop-1))->v;
+ for (j=0; j < mp->totloop; j++, l++) {
+ if (!BLI_edgehash_haskey(eh, l_prev, l->v)) {
+ BLI_edgehash_insert(eh, l_prev, l->v, NULL);
+ }
+ l_prev= l->v;
+ }
+ }
+ }
+ else {
+ /* regular faces (note, we could remove this for bmesh - campbell) */
+ for (i = 0; i < totface; i++, mf++) {
+ if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2))
+ BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL);
+ if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3))
+ BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL);
+
+ if (mf->v4) {
+ if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4))
+ BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL);
+ if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1))
+ BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL);
+ } else {
+ if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1))
+ BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL);
+ }
}
}
@@ -512,9 +530,29 @@ void BKE_mesh_calc_edges(Mesh *mesh, int update)
BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2);
med->flag = ME_EDGEDRAW|ME_EDGERENDER|SELECT; /* select for newly created meshes which are selected [#25595] */
}
+
+ /* store the new edge index in the hash value */
+ BLI_edgehashIterator_setValue(ehi, SET_INT_IN_POINTER(i));
}
BLI_edgehashIterator_free(ehi);
+ if (mesh->totpoly) {
+ /* second pass, iterate through all loops again and assign
+ the newly created edges to them. */
+ MPoly *mp= mesh->mpoly;
+ for(i=0; i < mesh->totpoly; i++, mp++) {
+ MLoop *l= &mesh->mloop[mp->loopstart];
+ MLoop *l_prev= (l + (mp->totloop-1));
+ int j;
+ for (j=0; j < mp->totloop; j++, l++) {
+ /* lookup hashed edge index */
+ med_index = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, l_prev->v, l->v));
+ l_prev->e = med_index;
+ l_prev= l;
+ }
+ }
+ }
+
/* free old CustomData and assign new one */
CustomData_free(&mesh->edata, mesh->totedge);
mesh->edata = edata;
diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c
new file mode 100644
index 00000000000..2fdf0e0bb70
--- /dev/null
+++ b/source/blender/blenkernel/intern/modifiers_bmesh.c
@@ -0,0 +1,171 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 by the Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/blenkernel/intern/modifiers_bmesh.c
+ * \ingroup bke
+ */
+
+#include "BLI_math.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_object_types.h"
+
+#include "BLI_array.h"
+
+#include "BKE_bmesh.h"
+#include "BKE_tessmesh.h"
+
+/* main function for copying DerivedMesh data into BMesh */
+void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm)
+{
+ MVert *mv, *mvert;
+ MEdge *me, *medge;
+ MPoly *mpoly, *mp;
+ MLoop *mloop, *ml;
+ BMVert *v, **vtable, **verts = NULL;
+ BMEdge *e, **etable, **edges = NULL;
+ BMFace *f;
+ BMIter liter;
+ BLI_array_declare(verts);
+ BLI_array_declare(edges);
+ int i, j, k, totvert, totedge, totface;
+
+ /*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);
+
+ totvert = dm->getNumVerts(dm);
+ totedge = dm->getNumEdges(dm);
+ totface = dm->getNumPolys(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_vert_create(bm, mv->co, NULL);
+ normal_short_to_float_v3(v->no, mv->no);
+ v->head.hflag = BM_vert_flag_from_mflag(mv->flag);
+
+ 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_edge_create(bm, vtable[me->v1], vtable[me->v2], NULL, FALSE);
+
+ e->head.hflag = BM_edge_flag_from_mflag(me->flag);
+
+ CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->head.data);
+ etable[i] = e;
+ }
+ MEM_freeN(medge);
+
+ /*do faces*/
+ mpoly = mp = dm->getPolyArray(dm);
+ mloop = dm->getLoopArray(dm);
+ for (i = 0; i < dm->numPolyData; i++, mp++) {
+ BMLoop *l;
+
+ BLI_array_empty(verts);
+ BLI_array_empty(edges);
+
+ BLI_array_growitems(verts, mp->totloop);
+ BLI_array_growitems(edges, mp->totloop);
+
+ ml = mloop + mp->loopstart;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+
+ verts[j] = vtable[ml->v];
+ edges[j] = etable[ml->e];
+ }
+
+ f = BM_face_create_ngon(bm, verts[0], verts[1], edges, mp->totloop, FALSE);
+
+ if (!f)
+ continue;
+
+ f->head.hflag = BM_face_flag_from_mflag(mp->flag);
+ f->mat_nr = mp->mat_nr;
+
+ l = BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, f);
+ k = mp->loopstart;
+
+ for (j = 0; l; l = BM_iter_step(&liter), k++) {
+ CustomData_to_bmesh_block(&dm->loopData, &bm->ldata, k, &l->head.data);
+ }
+
+ CustomData_to_bmesh_block(&dm->polyData, &bm->pdata, i, &f->head.data);
+ }
+
+ MEM_freeN(vtable);
+ MEM_freeN(etable);
+
+ BLI_array_free(verts);
+ BLI_array_free(edges);
+}
+
+/* converts a cddm to a BMEditMesh. if existing is non-NULL, the
+ * new geometry will be put in there.*/
+BMEditMesh *DM_to_editbmesh(Object *ob, DerivedMesh *dm, BMEditMesh *existing, int do_tesselate)
+{
+ BMEditMesh *em = existing;
+ BMesh *bm;
+
+ if (em) bm = em->bm;
+ else bm = BM_mesh_create(ob, bm_mesh_allocsize_default);
+
+ DM_to_bmesh_ex(dm, bm);
+
+ if (!em) {
+ em = BMEdit_Create(bm, do_tesselate);
+ }
+ else {
+ if (do_tesselate) {
+ BMEdit_RecalcTesselation(em);
+ }
+ }
+
+ return em;
+}
+
+BMesh *DM_to_bmesh(Object *ob, DerivedMesh *dm)
+{
+ BMesh *bm;
+
+ bm = BM_mesh_create(ob, bm_mesh_allocsize_default);
+
+ DM_to_bmesh_ex(dm, bm);
+
+ return bm;
+}
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 3fb49d508cd..1f154e17492 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -53,6 +53,7 @@
#include "BKE_paint.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
+#include "BKE_tessmesh.h"
#include "BKE_object.h"
@@ -67,7 +68,7 @@ static const int multires_grid_tot[] = {0, 4, 9, 25, 81, 289, 1089, 4225, 16641,
static const int multires_side_tot[] = {0, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025, 2049, 4097};
static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert);
-static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int add, DMGridData **oldGridData, int totlvl);
+static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm2, int invert, int add, DMGridData **oldGridData, int totlvl);
DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob)
{
@@ -180,7 +181,7 @@ void multires_force_external_reload(Object *ob)
{
Mesh *me = get_mesh(ob);
- CustomData_external_reload(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
+ CustomData_external_reload(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
multires_force_update(ob);
}
@@ -256,26 +257,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;
-
- 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;
+ MDisps *mdisp, *md;
+ int i, j, totlvl= 0;
- 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;
+ mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS);
+ 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;
}
}
@@ -288,10 +294,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);
@@ -303,27 +309,23 @@ 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];
}
}
}
-static void multires_reallocate_mdisps(Mesh *me, MDisps *mdisps, int lvl)
+static void multires_reallocate_mdisps(int totloop, 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 < totloop; ++i) {
+ int totdisp = multires_grid_tot[lvl];
float (*disps)[3] = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
if(mdisps[i].disps)
@@ -388,44 +390,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; */ /*UNUSED*/
int nsize = multires_side_tot[lvl];
int hsize = multires_side_tot[mmd->totlvl];
- int i;
+ int i, j;
- 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++) {
+ MDisps *mdisp= &mdisps[me->mpoly[i].loopstart+j];
+ 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);
}
}
@@ -441,8 +442,8 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int dire
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);
@@ -597,7 +598,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
cddm->release(cddm);
/* calc disps */
- multiresModifier_disp_run(dispdm, me, 1, 0, origdm->getGridData(origdm), totlvl);
+ multiresModifier_disp_run(dispdm, me, NULL, 1, 0, origdm->getGridData(origdm), totlvl);
origdm->release(origdm);
dispdm->release(dispdm);
@@ -614,9 +615,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 */
@@ -661,10 +662,10 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
ccgSubSurf_updateLevels(ss, lvl, NULL, 0);
/* reallocate displacements */
- multires_reallocate_mdisps(me, mdisps, totlvl);
+ multires_reallocate_mdisps(me->totloop, mdisps, totlvl);
/* compute displacements */
- multiresModifier_disp_run(highdm, me, 1, 0, subGridData, totlvl);
+ multiresModifier_disp_run(highdm, me, NULL, 1, 0, subGridData, totlvl);
/* free */
highdm->release(highdm);
@@ -674,7 +675,7 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
}
else {
/* only reallocate, nothing to upsample */
- multires_reallocate_mdisps(me, mdisps, totlvl);
+ multires_reallocate_mdisps(me->totloop, mdisps, totlvl);
}
multires_set_tot_level(ob, mmd, totlvl);
@@ -685,7 +686,7 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updat
multires_subdivide(mmd, ob, mmd->totlvl+1, updateblock, simple);
}
-static void grid_tangent(int gridSize, int index, int x, int y, int axis, DMGridData **gridData, float t[3])
+void grid_tangent(int gridSize, int index, int x, int y, int axis, DMGridData **gridData, float t[3])
{
if(axis == 0) {
if(x == gridSize - 1) {
@@ -709,18 +710,30 @@ static void grid_tangent(int gridSize, int index, int x, int y, int axis, DMGrid
}
}
-static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int add, DMGridData **oldGridData, int totlvl)
+static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm2, int invert, int add, DMGridData **oldGridData, int totlvl)
{
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;
+ int totloop, totpoly;
+
+ /*this happens in the dm made by bmesh_set_mdisps_space*/
+ if (dm2 && CustomData_has_layer(&dm2->loopData, CD_MDISPS)) {
+ mpoly = CustomData_get_layer(&dm2->polyData, CD_MPOLY);
+ mdisps = CustomData_get_layer(&dm2->loopData, CD_MDISPS);
+ totloop = dm2->numLoopData;
+ totpoly = dm2->numPolyData;
+ } else {
+ totloop = me->totloop;
+ totpoly = me->totpoly;
+ }
+
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;
}
@@ -734,23 +747,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(totloop*gridSize*gridSize >= CCG_OMP_LIMIT)
+
+ for(i = 0; i < totpoly; ++i) {
+ const int numVerts = mpoly[i].totloop;
+ int S, x, y, gIndex = gridOffset[i];
- for(S = 0; S < numVerts; ++S, ++gIndex) {
+ for(S = 0; S < numVerts; ++S, ++gIndex, ++k) {
+ MDisps *mdisp = &mdisps[mpoly[i].loopstart+S];
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(totloop, mdisps, totlvl);
+ }
+
+ dispgrid = mdisp->disps;
for(y = 0; y < gridSize; y++) {
for(x = 0; x < gridSize; x++) {
@@ -813,8 +831,8 @@ static void multiresModifier_update(DerivedMesh *dm)
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;
@@ -871,7 +889,7 @@ static void multiresModifier_update(DerivedMesh *dm)
ccgSubSurf_updateLevels(ss, lvl, NULL, 0);
/* add to displacements */
- multiresModifier_disp_run(highdm, me, 1, 1, subGridData, mmd->totlvl);
+ multiresModifier_disp_run(highdm, me, NULL, 1, 1, subGridData, mmd->totlvl);
/* free */
highdm->release(highdm);
@@ -889,13 +907,136 @@ static void multiresModifier_update(DerivedMesh *dm)
subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv);
cddm->release(cddm);
- multiresModifier_disp_run(dm, me, 1, 0, subdm->getGridData(subdm), mmd->totlvl);
+ multiresModifier_disp_run(dm, me, NULL, 1, 0, subdm->getGridData(subdm), mmd->totlvl);
subdm->release(subdm);
}
}
}
+
+void multires_set_space(DerivedMesh *dm, Object *ob, int from, int to)
+{
+ DerivedMesh *ccgdm = NULL, *subsurf = NULL;
+ DMGridData **gridData, **subGridData=NULL;
+ MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
+ MDisps *mdisps;
+ MultiresModifierData *mmd = get_multires_modifier(NULL, ob, 1);
+ int *gridOffset, totlvl;
+ int i, k, numGrids, gridSize, dGridSize, dSkip;
+
+ if (!mmd)
+ return;
+
+ mdisps = CustomData_get_layer(&dm->loopData, CD_MDISPS);
+
+ if(!mdisps) {
+ goto cleanup;
+ }
+
+ totlvl = mmd->totlvl;
+ ccgdm = multires_dm_create_local(ob, dm, totlvl, totlvl, mmd->simple);
+
+ subsurf = subsurf_dm_create_local(ob, dm, totlvl,
+ mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges, mmd->flags & eMultiresModifierFlag_PlainUv);
+
+ numGrids = subsurf->getNumGrids(subsurf);
+ gridSize = subsurf->getGridSize(subsurf);
+ gridData = subsurf->getGridData(subsurf);
+
+ subGridData = MEM_callocN(sizeof(DMGridData*)*numGrids, "subGridData*");
+
+ for(i = 0; i < numGrids; i++) {
+ subGridData[i] = MEM_callocN(sizeof(DMGridData)*gridSize*gridSize, "subGridData");
+ memcpy(subGridData[i], gridData[i], sizeof(DMGridData)*gridSize*gridSize);
+ }
+
+ /*numGrids = ccgdm->dm->getNumGrids((DerivedMesh*)ccgdm);*/ /*UNUSED*/
+ gridSize = ccgdm->getGridSize((DerivedMesh*)ccgdm);
+ gridData = ccgdm->getGridData((DerivedMesh*)ccgdm);
+ gridOffset = ccgdm->getGridOffset((DerivedMesh*)ccgdm);
+
+ dGridSize = multires_side_tot[totlvl];
+ dSkip = (dGridSize-1)/(gridSize-1);
+
+ k = 0; /*current loop/mdisp index within the mloop array*/
+
+ //#pragma omp parallel for private(i) if(dm->numLoopData*gridSize*gridSize >= CCG_OMP_LIMIT)
+
+ for(i = 0; i < dm->numPolyData; ++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[mpoly[i].loopstart+S];
+ /* DMGridData *grid = gridData[gIndex]; */ /* UNUSED */
+ DMGridData *subgrid = subGridData[gIndex];
+ float (*dispgrid)[3] = NULL;
+
+ /* when adding new faces in edit mode, need to allocate disps */
+ if(!mdisp->disps) {
+ mdisp->totdisp = gridSize*gridSize;
+ mdisp->disps = MEM_callocN(sizeof(float)*3*mdisp->totdisp, "disp in multires_set_space");
+ }
+
+ dispgrid = mdisp->disps;
+
+ for(y = 0; y < gridSize; y++) {
+ for(x = 0; x < gridSize; x++) {
+ float *data = dispgrid[dGridSize*y*dSkip + x*dSkip];
+ float *no = subgrid[x + y*gridSize].no;
+ float *co = subgrid[x + y*gridSize].co;
+ float mat[3][3], tx[3], ty[3], dco[3];
+
+ /* construct tangent space matrix */
+ grid_tangent(gridSize, gIndex, x, y, 0, subGridData, tx);
+ normalize_v3(tx);
+
+ grid_tangent(gridSize, gIndex, x, y, 1, subGridData, ty);
+ normalize_v3(ty);
+ column_vectors_to_mat3(mat, tx, ty, no);
+
+ /* convert to absolute coordinates in space */
+ if (from == MULTIRES_SPACE_TANGENT) {
+ mul_v3_m3v3(dco, mat, data);
+ add_v3_v3(dco, co);
+ } else if (from == MULTIRES_SPACE_OBJECT) {
+ add_v3_v3v3(dco, co, data);
+ } else if (from == MULTIRES_SPACE_ABSOLUTE) {
+ copy_v3_v3(dco, data);
+ }
+
+ column_vectors_to_mat3(mat, tx, ty, no);
+
+ /*now, convert to desired displacement type*/
+ if (to == MULTIRES_SPACE_TANGENT) {
+ invert_m3(mat);
+
+ sub_v3_v3(dco, co);
+ mul_v3_m3v3(data, mat, dco);
+ } else if (to == MULTIRES_SPACE_OBJECT) {
+ sub_v3_v3(dco, co);
+ mul_v3_m3v3(data, mat, dco);
+ } else if (to == MULTIRES_SPACE_ABSOLUTE) {
+ copy_v3_v3(data, dco);
+ }
+ }
+ }
+ }
+ }
+
+cleanup:
+ if (subsurf) {
+ subsurf->needsFree = 1;
+ subsurf->release(subsurf);
+ }
+
+ if (ccgdm) {
+ ccgdm->needsFree = 1;
+ ccgdm->release(ccgdm);
+ }
+}
+
void multires_stitch_grids(Object *ob)
{
/* utility for smooth brush */
@@ -956,8 +1097,10 @@ 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);
- multiresModifier_disp_run(result, ob->data, 0, 0, subGridData, mmd->totlvl);
+ CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
+
+ /*run displacement*/
+ multiresModifier_disp_run(result, ob->data, dm, 0, 0, subGridData, mmd->totlvl);
for(i = 0; i < numGrids; i++)
MEM_freeN(subGridData[i]);
@@ -976,7 +1119,10 @@ void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u,
const int st_max = st - 1;
float urat, vrat, uopp;
float d[4][3], d2[2][3];
-
+
+ if (!disps || isnan(u) || isnan(v))
+ return;
+
if(u < 0)
u = 0;
else if(u >= st)
@@ -1057,15 +1203,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);
+ }
+
+ }
}
}
@@ -1590,8 +1754,8 @@ static void multires_sync_levels(Scene *scene, Object *ob, Object *to_ob)
Mesh *me= (Mesh*)ob->data;
- 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);
}
if(!mmd || !to_mmd) return;
@@ -1605,7 +1769,8 @@ static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3])
DerivedMesh *dm= NULL, *cddm= NULL, *subdm= NULL;
DMGridData **gridData, **subGridData;
Mesh *me= (Mesh*)ob->data;
- MFace *mface= me->mface;
+ MPoly *mpoly= me->mpoly;
+ /* MLoop *mloop = me->mloop; */ /* UNUSED */
MDisps *mdisps;
int *gridOffset;
int i, /*numGrids,*/ gridSize, dGridSize, dSkip, totvert;
@@ -1613,8 +1778,8 @@ static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3])
MultiresModifierData *mmd= get_multires_modifier(scene, ob, 1);
MultiresModifierData high_mmd;
- 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 || !mmd || !mmd->totlvl) return;
@@ -1650,15 +1815,15 @@ static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3])
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];
+ for(i = 0; i < me->totpoly; ++i) {
+ const int numVerts= mpoly[i].totloop;
+ MDisps *mdisp= &mdisps[mpoly[i].loopstart];
int S, x, y, gIndex = gridOffset[i];
- for(S = 0; S < numVerts; ++S, ++gIndex) {
+ for(S = 0; S < numVerts; ++S, ++gIndex, mdisp++) {
DMGridData *grid= gridData[gIndex];
DMGridData *subgrid= subGridData[gIndex];
- float (*dispgrid)[3]= &mdisp->disps[S*dGridSize*dGridSize];
+ float (*dispgrid)[3]= mdisp->disps;
for(y = 0; y < gridSize; y++) {
for(x = 0; x < gridSize; x++) {
@@ -1731,6 +1896,7 @@ void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob)
}
/* update multires data after topology changing */
+#if 0 // BMESH_TODO
void multires_topology_changed(Scene *scene, Object *ob)
{
Mesh *me= (Mesh*)ob->data;
@@ -1781,6 +1947,7 @@ void multires_topology_changed(Scene *scene, Object *ob)
}
}
}
+#endif // BMESH_TODO
/* makes displacement along grid boundary symmetrical */
void multires_mdisp_smooth_bounds(MDisps *disps)
diff --git a/source/blender/blenkernel/intern/navmesh_conversion.c b/source/blender/blenkernel/intern/navmesh_conversion.c
index e6749730fc9..4c9c0a3a1fc 100644
--- a/source/blender/blenkernel/intern/navmesh_conversion.c
+++ b/source/blender/blenkernel/intern/navmesh_conversion.c
@@ -134,8 +134,8 @@ int buildRawVertIndicesData(DerivedMesh* dm, int *nverts_r, float **verts_r,
}
//calculate number of tris
- nfaces = dm->getNumFaces(dm);
- faces = dm->getFaceArray(dm);
+ nfaces = dm->getNumTessFaces(dm);
+ faces = dm->getTessFaceArray(dm);
ntris = nfaces;
for (fi=0; fi<nfaces; fi++)
{
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 58fc3378476..aacc30094d0 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -86,6 +86,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_node.h"
@@ -1722,7 +1723,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;
@@ -1731,7 +1732,24 @@ 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 0 /* this was bmesh only, better, evaluate why this was needed - campbell*/
+ 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) {
+ copy_v3_v3(vec, eve->co);
+ break;
+ }
+ }
+ }
+#endif
+
dm = (em)? em->derivedFinal: par->derivedFinal;
if(dm) {
@@ -1760,9 +1778,6 @@ static void give_parvert(Object *par, int nr, float *vec)
}
}
else fprintf(stderr, "%s: DerivedMesh is needed to solve parenting, object position can be wrong now\n", __func__);
-
- if(em)
- BKE_mesh_end_editmesh(me, em);
}
else if (ELEM(par->type, OB_CURVE, OB_SURF)) {
Nurb *nu;
@@ -2522,22 +2537,24 @@ 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);
+ makeDerivedMesh(scene, ob, em, scene->customdata_mask, 0); /* was CD_MASK_BAREMESH */
+ }
+ else {
+ makeDerivedMesh(scene, ob, NULL, scene->customdata_mask, 0);
+ }
#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;
uint64_t data_mask= scene->customdata_mask | ob->customdata_mask | CD_MASK_BAREMESH;
if(em) {
- makeDerivedMesh(scene, ob, em, data_mask); /* was CD_MASK_BAREMESH */
- BKE_mesh_end_editmesh(ob->data, em);
- } else
- makeDerivedMesh(scene, ob, NULL, data_mask);
+ makeDerivedMesh(scene, ob, em, data_mask, 0); /* was CD_MASK_BAREMESH */
+ }
+ else {
+ makeDerivedMesh(scene, ob, NULL, data_mask, 0);
+ }
#endif
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index f0b05846670..38a73daab2a 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -774,6 +774,8 @@ void psys_render_restore(Object *ob, ParticleSystem *psys)
psys->renderdata= NULL;
}
+/* BMESH_TODO, for orig face data, we need to use MPoly */
+
int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
{
DerivedMesh *dm= ctx->dm;
@@ -801,10 +803,10 @@ 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);
- totorigface= me->totface;
+ mface= dm->getTessFaceArray(dm);
+ origindex= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ totface= dm->getNumTessFaces(dm);
+ totorigface= me->totpoly;
if(totface == 0 || totorigface == 0)
return tot;
@@ -1574,7 +1576,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);
}
@@ -1616,17 +1618,17 @@ static void psys_origspace_to_w(OrigSpaceFace *osface, int quad, const float w[4
int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, const float fw[4], struct LinkNode *node)
{
Mesh *me= (Mesh*)ob->data;
- MFace *mface;
+ MPoly *mface;
OrigSpaceFace *osface;
int *origindex;
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->getPolyArray(dm);
+ 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 */
@@ -1638,7 +1640,7 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, const f
return DMCACHE_NOTFOUND;
}
}
- else if(index >= me->totface)
+ else if(index >= me->totpoly)
return DMCACHE_NOTFOUND; /* index not in the original mesh */
psys_w_to_origspace(fw, uv);
@@ -1647,7 +1649,7 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, const f
for(;node; node=node->next) {
findex= GET_INT_FROM_POINTER(node->link);
faceuv= osface[findex].uv;
- quad= mface[findex].v4;
+ quad = (mface[findex].totloop == 4);
/* check that this intersects - Its possible this misses :/ -
* could also check its not between */
@@ -1663,7 +1665,7 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, const f
for(findex=0; findex<totface; findex++) {
if(origindex[findex] == index) {
faceuv= osface[findex].uv;
- quad= mface[findex].v4;
+ quad = (mface[findex].totloop == 4);
/* check that this intersects - Its possible this misses :/ -
* could also check its not between */
@@ -1695,7 +1697,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;
@@ -1719,15 +1721,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;
@@ -1785,7 +1787,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);
@@ -2935,6 +2937,11 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
vg_length = psys_cache_vgroup(psmd->dm, psys, PSYS_VG_LENGTH);
}
+ /* ensure we have tessfaces to be used for mapping */
+ if (part->from != PART_FROM_VERT) {
+ DM_ensure_tessface(psmd->dm);
+ }
+
/*---first main loop: create all actual particles' paths---*/
LOOP_SHOWN_PARTICLES {
if(!psys->totchild) {
@@ -3358,10 +3365,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))) {
copy_v3_v3(v[0], orcodata[mface->v1]);
@@ -3676,7 +3683,6 @@ void make_local_particlesettings(ParticleSettings *part)
}
else if(is_local && is_lib) {
ParticleSettings *part_new= psys_copy_settings(part);
-
part_new->id.us= 0;
/* Remap paths of new ID using old library as base. */
@@ -3716,7 +3722,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, co
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
@@ -3728,7 +3734,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, co
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);
@@ -4396,7 +4402,7 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part, Partic
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);
}
@@ -4416,14 +4422,14 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part, Partic
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);
}
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index c00101c98ab..33f20642ca6 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -352,9 +352,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);
- totelem= me->totface;
- origindex= dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ totdmelem= dm->getNumTessFaces(dm);
+ totelem= me->totpoly;
+ origindex= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
}
nodedmelem= MEM_callocN(sizeof(LinkNode)*totdmelem, "psys node elems");
@@ -523,8 +523,8 @@ static void distribute_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; }
@@ -783,7 +783,7 @@ static void distribute_threads_exec(ParticleThread *thread, ParticleData *pa, Ch
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:
@@ -813,7 +813,7 @@ static void distribute_threads_exec(ParticleThread *thread, ParticleData *pa, Ch
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);
@@ -825,7 +825,7 @@ static void distribute_threads_exec(ParticleThread *thread, ParticleData *pa, Ch
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;
@@ -873,7 +873,7 @@ static void distribute_threads_exec(ParticleThread *thread, ParticleData *pa, Ch
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);
@@ -1040,7 +1040,7 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
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;
@@ -1071,6 +1071,10 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
distr=PART_DISTR_RAND;
BLI_srandom(31415926 + psys->seed + psys->child_seed);
dm= finaldm;
+
+ /* BMESH ONLY */
+ DM_ensure_tessface(dm);
+
children=1;
tree=BLI_kdtree_new(totpart);
@@ -1092,6 +1096,11 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
dm= CDDM_from_mesh((Mesh*)ob->data, ob);
+ /* BMESH ONLY, for verts we dont care about tessfaces */
+ if (from != PART_FROM_VERT) {
+ DM_ensure_tessface(dm);
+ }
+
/* we need orco for consistent distributions */
DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, get_mesh_orco_verts(ob));
@@ -1117,7 +1126,7 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
}
/* Get total number of emission elements and allocate needed arrays */
- totelem = (from == PART_FROM_VERT) ? dm->getNumVerts(dm) : dm->getNumFaces(dm);
+ totelem = (from == PART_FROM_VERT) ? dm->getNumVerts(dm) : dm->getNumTessFaces(dm);
if(totelem == 0){
distribute_invalid(scene, psys, children ? PART_FROM_CHILD : 0);
@@ -1146,7 +1155,7 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
orcodata= dm->getVertDataArray(dm, CD_ORCO);
for(i=0; i<totelem; i++){
- MFace *mf=dm->getFaceData(dm,i,CD_MFACE);
+ MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
if(orcodata) {
copy_v3_v3(co1, orcodata[mf->v1]);
@@ -1204,7 +1213,7 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
}
else { /* PART_FROM_FACE / PART_FROM_VOLUME */
for(i=0;i<totelem; 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) {
@@ -1278,8 +1287,8 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
COMPARE_ORIG_INDEX= dm->getVertDataArray(dm, CD_ORIGINDEX);
}
else {
- if(dm->numFaceData)
- COMPARE_ORIG_INDEX= dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ if(dm->numTessFaceData)
+ COMPARE_ORIG_INDEX= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
}
if(COMPARE_ORIG_INDEX) {
@@ -3516,7 +3525,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);
}
@@ -3551,7 +3560,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
if(dvert) {
if(!dvert->totweight) {
- dvert->dw = MEM_callocN (sizeof(MDeformWeight), "deformWeight");
+ dvert->dw = MEM_callocN(sizeof(MDeformWeight), "deformWeight");
dvert->totweight = 1;
}
@@ -3572,7 +3581,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
if(dvert) {
if(!dvert->totweight) {
- dvert->dw = MEM_callocN (sizeof(MDeformWeight), "deformWeight");
+ dvert->dw = MEM_callocN(sizeof(MDeformWeight), "deformWeight");
dvert->totweight = 1;
}
/* roots should be 1.0, the rest can be anything from 0.0 to 1.0 */
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 9edcc7a73e8..d88a5c26c2c 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -1697,7 +1697,7 @@ float hyp3,hyp4,b4,b5
hyp2 = fabsf(angle*x+y+(-(yo-posy*0.5f)-angle*(xo-posx*0.5f)))*wipezone->pythangle;
}
- hwidth= MIN2(hwidth, fabsf(b3-b1)/2.0f);
+ hwidth = minf(hwidth, fabsf(b3-b1)/2.0f);
if(b2 < b1 && b2 < b3 ){
output = in_band(hwidth,hyp,0,1);
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index aed246690bd..53c7656663a 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -54,6 +54,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"))
@@ -89,11 +91,10 @@ 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) {
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 424f97f57ed..e7dbbf44223 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -317,7 +317,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;
}
@@ -328,7 +328,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
@@ -336,16 +336,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);
}
@@ -362,7 +362,7 @@ static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs)
copy_v3_v3(&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
@@ -1008,6 +1008,7 @@ static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd)
{
ParticleSimulationData sim;
ParticleSystem *psys = sfs->psys;
+ int totpart=psys->totpart, totchild;
int p = 0;
float *density = smoke_get_density(sds->fluid);
float *bigdensity = smoke_turbulence_get_density(sds->wt);
@@ -1043,7 +1044,23 @@ static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd)
}
// mostly copied from particle code
- for(p=0; p<psys->totpart; p++)
+ if(psys->part->type==PART_HAIR)
+ {
+ /*
+ if(psys->childcache)
+ {
+ totchild = psys->totchildcache;
+ }
+ else
+ */
+
+ // TODO: PART_HAIR not supported whatsoever
+ totchild=0;
+ }
+ else
+ totchild=psys->totchild*psys->part->disp/100;
+
+ for(p=0; p<totpart+totchild; p++)
{
int cell[3];
size_t i = 0;
@@ -1051,17 +1068,27 @@ static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd)
int badcell = 0;
ParticleKey state;
- if(psys->particles[p].flag & (PARS_NO_DISP|PARS_UNEXIST))
- continue;
+ if(p < totpart)
+ {
+ if(psys->particles[p].flag & (PARS_NO_DISP|PARS_UNEXIST))
+ continue;
+ }
+ else
+ {
+ /* handle child particle */
+ ChildParticle *cpa = &psys->child[p - totpart];
+
+ if(psys->particles[cpa->parent].flag & (PARS_NO_DISP|PARS_UNEXIST))
+ continue;
+ }
state.time = smd->time;
-
if(psys_get_particle_state(&sim, p, &state, 0) == 0)
continue;
-
+
// copy_v3_v3(pos, pa->state.co);
- // mul_m4_v3(ob->imat, pos);
- // 1. get corresponding cell
+ // mul_m4_v3(ob->imat, pos);
+ // 1. get corresponding cell
get_cell(smd->domain->p0, smd->domain->res, smd->domain->dx, state.co, cell, 0);
// check if cell is valid (in the domain boundary)
for(i = 0; i < 3; i++)
@@ -1354,7 +1381,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_from_tessface(dm);
#endif
// rigid movement support
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index f0dea976aa9..60c4c08795c 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -58,6 +58,10 @@
#include "BKE_paint.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
+#include "BKE_tessmesh.h"
+
+#include "PIL_time.h"
+#include "BLI_array.h"
#include "GL/glew.h"
@@ -69,9 +73,10 @@
extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */
-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);
static int ccgDM_use_grid_pbvh(CCGDerivedMesh *ccgdm);
///
@@ -206,13 +211,12 @@ static int getFaceIndex(CCGSubSurf *ss, CCGFace *f, int S, int x, int y, int edg
}
}
-static void get_face_uv_map_vert(UvVertMap *vmap, struct MFace *mf, int fi, CCGVertHDL *fverts) {
- unsigned int *fv = &mf->v1;
+static void get_face_uv_map_vert(UvVertMap *vmap, struct MPoly *mp, struct MLoop *ml, int fi, CCGVertHDL *fverts) {
UvMapVert *v, *nv;
- int j, nverts= mf->v4? 4: 3;
+ int j, nverts= mp->totloop;
- for (j=0; j<nverts; j++, fv++) {
- for (nv=v=get_uv_map_vert(vmap, *fv); v; v=v->next) {
+ for (j=0; j<nverts; j++) {
+ for (nv=v=get_uv_map_vert(vmap, ml[j].v); v; v=v->next) {
if (v->separate)
nv= v;
if (v->f == fi)
@@ -223,22 +227,24 @@ 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);
+static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, MLoopUV *mloopuv) {
+ MPoly *mpoly = dm->getPolyArray(dm);
+ MLoop *mloop = dm->getLoopArray(dm);
MVert *mvert = dm->getVertArray(dm);
int totvert = dm->getNumVerts(dm);
- int totface = dm->getNumFaces(dm);
+ int totface = dm->getNumPolys(dm);
int i, j, seam;
UvMapVert *v;
UvVertMap *vmap;
float limit[2];
- CCGVertHDL fverts[4];
+ CCGVertHDL *fverts= NULL;
+ BLI_array_declare(fverts);
EdgeHash *ehash;
float creaseFactor = (float)ccgSubSurf_getSubdivisionLevels(ss);
float uv[3]= {0.0f, 0.0f, 0.0f}; /* only first 2 values are written into */
limit[0]= limit[1]= STD_UV_CONNECT_LIMIT;
- vmap= make_uv_vert_map(mface, tface, totface, totvert, 0, limit);
+ vmap= make_uv_vert_map(mpoly, mloop, mloopuv, totface, totvert, 0, limit);
if (!vmap)
return 0;
@@ -260,7 +266,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm,
CCGVert *ssv;
CCGVertHDL vhdl = SET_INT_IN_POINTER(v->f*4 + v->tfindex);
- copy_v2_v2(uv, (tface+v->f)->uv[v->tfindex]);
+ copy_v2_v2(uv, mloopuv[mpoly[v->f].loopstart + v->tfindex].uv);
ccgSubSurf_syncVert(ss, vhdl, uv, seam, &ssv);
}
@@ -271,18 +277,22 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm,
ehash = BLI_edgehash_new();
for (i=0; i<totface; i++) {
- MFace *mf = &((MFace*) mface)[i];
- int nverts= mf->v4? 4: 3;
+ MPoly *mp = &((MPoly*) mpoly)[i];
+ int nverts= mp->totloop;
CCGFace *origf= ccgSubSurf_getFace(origss, SET_INT_IN_POINTER(i));
- unsigned int *fv = &mf->v1;
+ /* unsigned int *fv = &mp->v1; */
+ MLoop *ml= mloop + mp->loopstart;
- get_face_uv_map_vert(vmap, mf, i, fverts);
+ BLI_array_empty(fverts);
+ BLI_array_growitems(fverts, nverts);
+
+ get_face_uv_map_vert(vmap, mp, ml, i, fverts);
for (j=0; j<nverts; j++) {
int v0 = GET_INT_FROM_POINTER(fverts[j]);
int v1 = GET_INT_FROM_POINTER(fverts[(j+1)%nverts]);
- MVert *mv0 = mvert + *(fv+j);
- MVert *mv1 = mvert + *(fv+((j+1)%nverts));
+ MVert *mv0 = mvert + (ml[ j ]. v);
+ MVert *mv1 = mvert + (ml[ ((j+1)%nverts) ].v);
if (!BLI_edgehash_haskey(ehash, v0, v1)) {
CCGEdge *e, *orige= ccgSubSurf_getFaceEdge(origss, origf, j);
@@ -304,14 +314,20 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm,
/* create faces */
for (i=0; i<totface; i++) {
- MFace *mf = &((MFace*) mface)[i];
- int nverts= mf->v4? 4: 3;
+ MPoly *mp = &mpoly[i];
+ MLoop *ml= &mloop[mp->loopstart];
+ int nverts= mp->totloop;
CCGFace *f;
- get_face_uv_map_vert(vmap, mf, i, fverts);
+ BLI_array_empty(fverts);
+ BLI_array_growitems(fverts, nverts);
+
+ get_face_uv_map_vert(vmap, mp, ml, i, fverts);
ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), nverts, fverts, &f);
}
+ BLI_array_free(fverts);
+
free_uv_vert_map(vmap);
ccgSubSurf_processSync(ss);
@@ -323,18 +339,22 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result,
CCGSubSurf *uvss;
CCGFace **faceMap;
MTFace *tf;
+ MLoopUV *mluv;
CCGFaceIterator *fi;
int index, gridSize, gridFaces, /*edgeSize,*/ totface, x, y, S;
- MTFace *dmtface = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, n);
+ MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, n);
+ /* need to update both CD_MTFACE & CD_MLOOPUV, hrmf, we could get away with
+ * just tface except applying the modifier then looses subsurf UV */
MTFace *tface = CustomData_get_layer_n(&result->faceData, CD_MTFACE, n);
+ MLoopUV *mloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, n);
- if(!dmtface || !tface)
+ if(!dmloopuv || (!tface && !mloopuv))
return;
/* create a CCGSubSurf from uv's */
uvss = _getSubSurf(NULL, ccgSubSurf_getSubdivisionLevels(ss), CCG_USE_ARENA);
- if(!ss_sync_from_uv(uvss, ss, dm, dmtface)) {
+ if(!ss_sync_from_uv(uvss, ss, dm, dmloopuv)) {
ccgSubSurf_free(uvss);
return;
}
@@ -357,6 +377,7 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result,
/* load coordinates from uvss into tface */
tf= tface;
+ mluv= mloopuv;
for(index = 0; index < totface; index++) {
CCGFace *f = faceMap[index];
@@ -367,12 +388,27 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result,
for(y = 0; y < gridFaces; y++) {
for(x = 0; x < gridFaces; x++) {
- copy_v2_v2(tf->uv[0], faceGridData[(y + 0)*gridSize + x + 0]);
- copy_v2_v2(tf->uv[1], faceGridData[(y + 1)*gridSize + x + 0]);
- copy_v2_v2(tf->uv[2], faceGridData[(y + 1)*gridSize + x + 1]);
- copy_v2_v2(tf->uv[3], faceGridData[(y + 0)*gridSize + x + 1]);
+ float *a = faceGridData[(y + 0)*gridSize + x + 0];
+ float *b = faceGridData[(y + 0)*gridSize + x + 1];
+ float *c = faceGridData[(y + 1)*gridSize + x + 1];
+ float *d = faceGridData[(y + 1)*gridSize + x + 0];
+
+ if (tface) {
+ tf->uv[0][0] = a[0]; tf->uv[0][1] = a[1];
+ tf->uv[1][0] = d[0]; tf->uv[1][1] = d[1];
+ tf->uv[2][0] = c[0]; tf->uv[2][1] = c[1];
+ tf->uv[3][0] = b[0]; tf->uv[3][1] = b[1];
+ }
+
+ if (mloopuv) {
+ mluv[0].uv[0] = a[0]; mluv[0].uv[1] = a[1];
+ mluv[1].uv[0] = d[0]; mluv[1].uv[1] = d[1];
+ mluv[2].uv[0] = c[0]; mluv[2].uv[1] = c[1];
+ mluv[3].uv[0] = b[0]; mluv[3].uv[1] = b[1];
+ }
tf++;
+ mluv+=4;
}
}
}
@@ -383,65 +419,101 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result,
}
/* face weighting */
-static void calc_ss_weights(int gridFaces,
- FaceVertWeight **qweight, FaceVertWeight **tweight)
+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)
{
- FaceVertWeight *qw, *tw;
- int x, y, j;
- int numWeights = gridFaces * gridFaces;
-
- *tweight = MEM_mallocN(sizeof(**tweight) * numWeights, "ssTriWeight");
- *qweight = MEM_mallocN(sizeof(**qweight) * numWeights, "ssQuadWeight");
-
- qw = *qweight;
- tw = *tweight;
-
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- for (j = 0; j < 4; j++) {
- int fx = x + (j == 2 || j == 3);
- int fy = y + (j == 1 || j == 2);
- float x_v = (float) fx / gridFaces;
- float y_v = (float) fy / gridFaces;
- float tx_v = (1.0f - x_v), ty_v = (1.0f - y_v);
- float center = (1.0f / 3.0f) * tx_v * ty_v;
-
- (*tw)[j][0] = center + 0.5f * tx_v * y_v;
- (*tw)[j][2] = center + 0.5f * x_v * ty_v;
- (*tw)[j][1] = 1.0f - (*tw)[j][0] - (*tw)[j][2];
- (*tw)[j][3] = 0.0f;
-
- tx_v *= 0.5f;
- ty_v *= 0.5f;
-
- (*qw)[j][3] = tx_v * ty_v;
- (*qw)[j][0] = (*qw)[j][3] + tx_v * y_v;
- (*qw)[j][2] = (*qw)[j][3] + x_v * ty_v;
- (*qw)[j][1] = 1.0f - (*qw)[j][0] - (*qw)[j][2] - (*qw)[j][3];
+ 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.0f / (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.0f - fy + -fac2*fy*fac);
+
+ fac2 = 1.0f - (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;
+ }
}
- tw++;
- qw++;
}
}
+
+ return wtable->weight_table[faceLen].w;
+}
+
+static 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);
+ }
+
+ if (wtable->weight_table)
+ MEM_freeN(wtable->weight_table);
}
static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
float (*vertexCos)[3], int useFlatSubdiv)
{
float creaseFactor = (float) ccgSubSurf_getSubdivisionLevels(ss);
- CCGVertHDL fVerts[4];
- int totvert = dm->getNumVerts(dm);
- int totedge = dm->getNumEdges(dm);
- int totface = dm->getNumFaces(dm);
- int i;
- int *index;
+ CCGVertHDL *fVerts = NULL;
+ BLI_array_declare(fVerts);
MVert *mvert = dm->getVertArray(dm);
MEdge *medge = dm->getEdgeArray(dm);
- MFace *mface = dm->getFaceArray(dm);
+ /* MFace *mface = dm->getTessFaceArray(dm); */ /* UNUSED */
MVert *mv;
MEdge *me;
- MFace *mf;
+ MLoop *mloop = dm->getLoopArray(dm), *ml;
+ MPoly *mpoly = dm->getPolyArray(dm), *mp;
+ /*MFace *mf;*/ /*UNUSED*/
+ int totvert = dm->getNumVerts(dm);
+ int totedge = dm->getNumEdges(dm);
+ /*int totface = dm->getNumTessFaces(dm);*/ /*UNUSED*/
+ /*int totpoly = dm->getNumFaces(dm);*/ /*UNUSED*/
+ int i, j;
+ int *index;
ccgSubSurf_initFullSync(ss);
@@ -474,21 +546,24 @@ 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++) {
+ mp = mpoly;
+ index = DM_get_poly_data_layer(dm, CD_ORIGINDEX);
+ for (i=0; i<dm->numPolyData; i++, mp++) {
CCGFace *f;
- 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);
+ BLI_array_empty(fVerts);
+ BLI_array_growitems(fVerts, mp->totloop);
+
+ ml = mloop + mp->loopstart;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ fVerts[j] = SET_INT_IN_POINTER(ml->v);
+ }
/* 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), fVerts[3] ? 4 : 3,
+ if(ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), mp->totloop,
fVerts, &f) == eCCGError_InvalidValue) {
static int hasGivenError = 0;
@@ -506,6 +581,8 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
}
ccgSubSurf_processSync(ss);
+
+ BLI_array_free(fVerts);
}
/***/
@@ -576,11 +653,17 @@ static int ccgDM_getNumEdges(DerivedMesh *dm) {
return ccgSubSurf_getNumFinalEdges(ccgdm->ss);
}
-static int ccgDM_getNumFaces(DerivedMesh *dm) {
+static int ccgDM_getNumTessFaces(DerivedMesh *dm) {
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
return ccgSubSurf_getNumFinalFaces(ccgdm->ss);
}
+static int ccgDM_getNumLoops(DerivedMesh *dm) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+
+ /* All subsurf faces are quads */
+ return 4 * ccgSubSurf_getNumFinalFaces(ccgdm->ss);
+}
static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
{
@@ -701,6 +784,41 @@ static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
int gridSideEdges;
int gridInternalEdges;
+ /* code added in bmesh but works correctly without, commenting - campbell */
+#if 0
+ int lasti, previ;
+ i = lastface;
+ lasti = 0;
+ while (1) {
+ previ = i;
+ if (ccgdm->faceMap[i].startEdge >= edgeNum) {
+ i -= fabsf(i-lasti)/2.0f;
+ } else if (ccgdm->faceMap[i].startEdge < edgeNum) {
+ i += fabsf(i-lasti)/2.0f;
+ } else {
+ break;
+ }
+
+ if (i < 0) {
+ i = 0;
+ break;
+ }
+
+ if (i > lastface) {
+ i = lastface;
+ break;
+
+ }
+
+ if (i == lasti)
+ break;
+
+ lasti = previ;
+ }
+
+ i = i > 0 ? i - 1 : i;
+#endif
+
i = 0;
while(i < lastface && edgeNum >= ccgdm->faceMap[i + 1].startEdge)
++i;
@@ -775,14 +893,14 @@ static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf)
int offset;
int grid;
int x, y;
- int lastface = ccgSubSurf_getNumFaces(ss) - 1;
+ /*int lastface = ccgSubSurf_getNumFaces(ss) - 1;*/ /*UNUSED*/
char *faceFlags = ccgdm->faceFlags;
memset(mf, 0, sizeof(*mf));
+ if (faceNum >= ccgdm->dm.numTessFaceData)
+ return;
- i = 0;
- while(i < lastface && faceNum >= ccgdm->faceMap[i + 1].startFace)
- ++i;
+ i = ccgdm->reverseFaceMap[faceNum];
f = ccgdm->faceMap[i].face;
/*numVerts = ccgSubSurf_getFaceNumVerts(f);*/ /*UNUSED*/
@@ -995,6 +1113,109 @@ static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface)
}
}
+static void ccgDM_copyFinalLoopArray(DerivedMesh *dm, MLoop *mloop)
+{
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int index;
+ int totface;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int i = 0;
+ MLoop *mv;
+ /* char *faceFlags = ccgdm->faceFlags; */ /* UNUSED */
+
+ if (!ccgdm->ehash) {
+ MEdge *medge;
+
+ ccgdm->ehash = BLI_edgehash_new();
+ medge = ccgdm->dm.getEdgeArray((DerivedMesh*)ccgdm);
+
+ for (i=0; i<ccgdm->dm.numEdgeData; i++) {
+ BLI_edgehash_insert(ccgdm->ehash, medge[i].v1, medge[i].v2, SET_INT_IN_POINTER(i));
+ }
+ }
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ mv = mloop;
+ for(index = 0; index < totface; index++) {
+ CCGFace *f = ccgdm->faceMap[index].face;
+ int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
+ /* int flag = (faceFlags)? faceFlags[index*2]: ME_SMOOTH; */ /* UNUSED */
+ /* int mat_nr = (faceFlags)? faceFlags[index*2+1]: 0; */ /* UNUSED */
+
+ for(S = 0; S < numVerts; S++) {
+ for(y = 0; y < gridSize - 1; y++) {
+ for(x = 0; x < gridSize - 1; x++) {
+ int v1, v2, v3, v4;
+
+ v1 = getFaceIndex(ss, f, S, x + 0, y + 0,
+ edgeSize, gridSize);
+
+ v2 = getFaceIndex(ss, f, S, x + 0, y + 1,
+ edgeSize, gridSize);
+ v3 = getFaceIndex(ss, f, S, x + 1, y + 1,
+ edgeSize, gridSize);
+ v4 = getFaceIndex(ss, f, S, x + 1, y + 0,
+ edgeSize, gridSize);
+
+ mv->v = v1;
+ mv->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v1, v2));
+ mv++, i++;
+
+ mv->v = v2;
+ mv->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v2, v3));
+ mv++, i++;
+
+ mv->v = v3;
+ mv->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v3, v4));
+ mv++, i++;
+
+ mv->v = v4;
+ mv->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v4, v1));
+ mv++, i++;
+ }
+ }
+ }
+ }
+}
+
+static void ccgDM_copyFinalPolyArray(DerivedMesh *dm, MPoly *mface)
+{
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int index;
+ int totface;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ /* int edgeSize = ccgSubSurf_getEdgeSize(ss); */ /* UNUSED */
+ int i = 0, k = 0;
+ char *faceFlags = ccgdm->faceFlags;
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ for(index = 0; index < totface; index++) {
+ CCGFace *f = ccgdm->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;
+
+ for(S = 0; S < numVerts; S++) {
+ for(y = 0; y < gridSize - 1; y++) {
+ for(x = 0; x < gridSize - 1; x++) {
+ MPoly *mf = &mface[i];
+
+ mf->mat_nr = mat_nr;
+ mf->flag = flag;
+ mf->loopstart = k;
+ mf->totloop = 4;
+
+ k += 4;
+ i++;
+ }
+ }
+ }
+ }
+}
+
static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) {
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
CCGSubSurf *ss = ccgdm->ss;
@@ -1290,7 +1511,7 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
ccgdm_pbvh_update(ccgdm);
if(ccgdm->pbvh && ccgdm->multires.mmd && !fast) {
- if(dm->numFaceData) {
+ if(dm->numTessFaceData) {
/* should be per face */
if(!setMaterial(faceFlags[1]+1, NULL))
return;
@@ -1380,7 +1601,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
CCGSubSurf *ss = ccgdm->ss;
GPUVertexAttribs gattribs;
DMVertexAttribs attribs= {{{NULL}}};
- /* MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */
+ /* MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
int edgeSize = ccgSubSurf_getEdgeSize(ss);
@@ -1737,8 +1958,8 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
{
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);
+ MCol *mcol = dm->getTessFaceDataArray(dm, CD_WEIGHT_MCOL);
+ MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
char *faceFlags = ccgdm->faceFlags;
int i, totface, flag, gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
@@ -1748,10 +1969,10 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
ccgdm_pbvh_update(ccgdm);
if(!mcol)
- mcol = dm->getFaceDataArray(dm, CD_MCOL);
+ mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
if(!mcol)
- mcol = dm->getFaceDataArray(dm, CD_TEXTURE_MCOL);
+ mcol = dm->getTessFaceDataArray(dm, CD_TEXTURE_MCOL);
totface = ccgSubSurf_getNumFaces(ss);
for(i = 0; i < totface; i++) {
@@ -1876,7 +2097,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
}
static void ccgDM_drawFacesTex(DerivedMesh *dm,
- int (*setDrawOptions)(MTFace *tface, int has_mcol, int matnr),
+ int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr),
int (*compareDrawOptions)(void *userData, int cur_index, int next_index),
void *userData)
{
@@ -1894,13 +2115,13 @@ static void ccgDM_drawMappedFacesTex(DerivedMesh *dm,
static void ccgDM_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) {
glBegin(GL_LINES);
- for(i = 0; i < dm->numFaceData; i++, mf++, tf++) {
+ for(i = 0; i < dm->numTessFaceData; i++, mf++, tf++) {
if(!(mf->flag&ME_HIDE)) {
glVertex2fv(tf->uv[0]);
glVertex2fv(tf->uv[1]);
@@ -1941,9 +2162,9 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
(void)compareDrawOptions;
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);
@@ -2144,6 +2365,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);
@@ -2151,6 +2376,8 @@ static void ccgDM_release(DerivedMesh *dm) {
if(ccgdm->freeSS) ccgSubSurf_free(ccgdm->ss);
if(ccgdm->fmap) MEM_freeN(ccgdm->fmap);
if(ccgdm->fmap_mem) MEM_freeN(ccgdm->fmap_mem);
+ if(ccgdm->pmap) MEM_freeN(ccgdm->pmap);
+ if(ccgdm->pmap_mem) MEM_freeN(ccgdm->pmap_mem);
MEM_freeN(ccgdm->edgeFlags);
MEM_freeN(ccgdm->faceFlags);
MEM_freeN(ccgdm->vertMap);
@@ -2160,6 +2387,64 @@ static void ccgDM_release(DerivedMesh *dm) {
}
}
+static void ccg_loops_to_corners(CustomData *fdata, CustomData *ldata,
+ CustomData *pdata, int loopstart, int findex, int polyindex,
+ const int numTex, const int numCol, const int hasWCol, const int hasOrigSpace)
+{
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ int i, j;
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
+ texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i);
+
+ ME_MTEXFACE_CPY(texface, texpoly);
+
+ mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i);
+ for (j=0; j<4; j++, mloopuv++) {
+ copy_v2_v2(texface->uv[j], mloopuv->uv);
+ }
+ }
+
+ 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;
+ }
+ }
+
+ if (hasOrigSpace) {
+ OrigSpaceFace *of = CustomData_get(fdata, findex, CD_ORIGSPACE);
+ OrigSpaceLoop *lof;
+
+ lof = CustomData_get(ldata, loopstart, CD_ORIGSPACE_MLOOP);
+ for (j=0; j<4; j++, lof++) {
+ copy_v2_v2(of->uv[j], lof->uv);
+ }
+ }
+}
+
static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type)
{
if(type == CD_ORIGINDEX) {
@@ -2169,6 +2454,12 @@ static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type)
int *origindex;
int a, index, totnone, totorig;
+ /* Avoid re-creation if the layer exists already */
+ origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
+ if (origindex) {
+ return origindex;
+ }
+
DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
origindex= DM_get_vert_data_layer(dm, CD_ORIGINDEX);
@@ -2200,6 +2491,12 @@ static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type)
int a, i, index, totnone, totorig, totedge;
int edgeSize= ccgSubSurf_getEdgeSize(ss);
+ /* Avoid re-creation if the layer exists already */
+ origindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
+ if (origindex) {
+ return origindex;
+ }
+
DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
origindex= DM_get_edge_data_layer(dm, CD_ORIGINDEX);
@@ -2225,7 +2522,7 @@ static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type)
return DM_get_edge_data_layer(dm, type);
}
-static void *ccgDM_get_face_data_layer(DerivedMesh *dm, int type)
+static void *ccgDM_get_tessface_data_layer(DerivedMesh *dm, int type)
{
if(type == CD_ORIGINDEX) {
/* create origindex on demand to save memory */
@@ -2235,8 +2532,14 @@ static void *ccgDM_get_face_data_layer(DerivedMesh *dm, int type)
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);
+ /* Avoid re-creation if the layer exists already */
+ origindex = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
+ if (origindex) {
+ return origindex;
+ }
+
+ DM_add_tessface_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
+ origindex= DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
totface= ccgSubSurf_getNumFaces(ss);
@@ -2252,7 +2555,37 @@ 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 void *ccgDM_get_vert_data(DerivedMesh *dm, int index, int type)
+{
+ if (type == CD_ORIGINDEX) {
+ /* ensure creation of CD_ORIGINDEX layer */
+ ccgDM_get_vert_data_layer(dm, type);
+ }
+
+ return DM_get_vert_data(dm, index, type);
+}
+
+static void *ccgDM_get_edge_data(DerivedMesh *dm, int index, int type)
+{
+ if (type == CD_ORIGINDEX) {
+ /* ensure creation of CD_ORIGINDEX layer */
+ ccgDM_get_edge_data_layer(dm, type);
+ }
+
+ return DM_get_edge_data(dm, index, type);
+}
+
+static void *ccgDM_get_tessface_data(DerivedMesh *dm, int index, int type)
+{
+ if (type == CD_ORIGINDEX) {
+ /* ensure creation of CD_ORIGINDEX layer */
+ ccgDM_get_tessface_data_layer(dm, type);
+ }
+
+ return DM_get_tessface_data(dm, index, type);
}
static int ccgDM_getNumGrids(DerivedMesh *dm)
@@ -2398,6 +2731,21 @@ static int *ccgDM_getGridOffset(DerivedMesh *dm)
return ccgdm->gridOffset;
}
+static ListBase *ccgDM_getPolyMap(Object *ob, DerivedMesh *dm)
+{
+ CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
+
+ if(!ccgdm->multires.mmd && !ccgdm->pmap && ob->type == OB_MESH) {
+ Mesh *me= ob->data;
+
+ create_vert_poly_map(&ccgdm->pmap, &ccgdm->pmap_mem,
+ me->mpoly, me->mloop,
+ me->totvert, me->totpoly, me->totloop);
+ }
+
+ return ccgdm->pmap;
+}
+
static ListBase *ccgDM_getFaceMap(Object *ob, DerivedMesh *dm)
{
CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
@@ -2470,6 +2818,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
} else if(ob->type == OB_MESH) {
Mesh *me= ob->data;
ob->sculpt->pbvh= ccgdm->pbvh = BLI_pbvh_new();
+ BLI_assert(!(me->mface == NULL && me->mpoly != NULL)); /* BMESH ONLY complain if mpoly is valid but not mface */
BLI_pbvh_build_mesh(ccgdm->pbvh, me->mface, me->mvert,
me->totface, me->totvert);
}
@@ -2477,6 +2826,16 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
return ccgdm->pbvh;
}
+static void ccgDM_recalcTesselation(DerivedMesh *UNUSED(dm))
+{
+ /* Nothing to do: CCG handles creating its own tessfaces */
+}
+
+static void ccgDM_calcNormals(DerivedMesh *UNUSED(dm))
+{
+ /* Nothing to do: CCG calculates normals during drawing */
+}
+
static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
int drawInteriorEdges,
int useSubsurfUv,
@@ -2489,51 +2848,96 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
int index, totvert, totedge, totface;
int i;
int vertNum, edgeNum, faceNum;
+ int *vertOrigIndex, *faceOrigIndex, *polyOrigIndex, *base_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 hasWCol, hasOrigSpace;
int gridInternalEdges;
+ float *w = NULL;
+ WeightTable wtable = {0};
+ /* MCol *mcol; */ /* UNUSED */
MEdge *medge = NULL;
- MFace *mface = NULL;
- int *orig_indices;
- FaceVertWeight *qweight, *tweight;
+ /* MFace *mface = NULL; */
+ 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);
+ hasWCol = CustomData_has_layer(&ccgdm->dm.loopData, CD_WEIGHT_MLOOPCOL);
+ hasOrigSpace = CustomData_has_layer(&ccgdm->dm.loopData, CD_ORIGSPACE_MLOOP);
+
+ if (
+ (numTex && CustomData_number_of_layers(&ccgdm->dm.faceData, CD_MTFACE) != numTex) ||
+ (numCol && CustomData_number_of_layers(&ccgdm->dm.faceData, CD_MCOL) != numCol) ||
+ (hasOrigSpace && !CustomData_has_layer(&ccgdm->dm.faceData, CD_ORIGSPACE)) )
+ {
+ CustomData_from_bmeshpoly(&ccgdm->dm.faceData,
+ &ccgdm->dm.polyData,
+ &ccgdm->dm.loopData,
+ ccgSubSurf_getNumFinalFaces(ss));
+ }
ccgdm->dm.getMinMax = ccgDM_getMinMax;
ccgdm->dm.getNumVerts = ccgDM_getNumVerts;
- ccgdm->dm.getNumFaces = ccgDM_getNumFaces;
-
ccgdm->dm.getNumEdges = ccgDM_getNumEdges;
+ ccgdm->dm.getNumTessFaces = ccgDM_getNumTessFaces;
+ ccgdm->dm.getNumLoops = ccgDM_getNumLoops;
+ /* reuse of ccgDM_getNumTessFaces is intentional here: subsurf polys are just created from tessfaces */
+ ccgdm->dm.getNumPolys = ccgDM_getNumTessFaces;
+
+ ccgdm->dm.getNumGrids = ccgDM_getNumGrids;
+ ccgdm->dm.getPBVH = ccgDM_getPBVH;
+
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.getVertData = DM_get_vert_data;
- ccgdm->dm.getEdgeData = DM_get_edge_data;
- ccgdm->dm.getFaceData = DM_get_face_data;
+ ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray;
+ ccgdm->dm.copyLoopArray = ccgDM_copyFinalLoopArray;
+ ccgdm->dm.copyPolyArray = ccgDM_copyFinalPolyArray;
+
+ ccgdm->dm.getVertData = ccgDM_get_vert_data;
+ ccgdm->dm.getEdgeData = ccgDM_get_edge_data;
+ ccgdm->dm.getTessFaceData = ccgDM_get_tessface_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_tessface_data_layer;
ccgdm->dm.getNumGrids = ccgDM_getNumGrids;
ccgdm->dm.getGridSize = ccgDM_getGridSize;
ccgdm->dm.getGridData = ccgDM_getGridData;
ccgdm->dm.getGridAdjacency = ccgDM_getGridAdjacency;
ccgdm->dm.getGridOffset = ccgDM_getGridOffset;
+ ccgdm->dm.getPolyMap = ccgDM_getPolyMap;
ccgdm->dm.getFaceMap = ccgDM_getFaceMap;
ccgdm->dm.getPBVH = ccgDM_getPBVH;
+ ccgdm->dm.getTessFace = ccgDM_getFinalFace;
+ ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray;
+ ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray;
+ ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray;
+
+ ccgdm->dm.calcNormals = ccgDM_calcNormals;
+ ccgdm->dm.recalcTesselation = ccgDM_recalcTesselation;
+
ccgdm->dm.getVertCos = ccgdm_getVertCos;
ccgdm->dm.foreachMappedVert = ccgDM_foreachMappedVert;
ccgdm->dm.foreachMappedEdge = ccgDM_foreachMappedEdge;
@@ -2590,139 +2994,194 @@ 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 */
+ /* mvert = dm->getVertArray(dm); */ /* UNUSED */
medge = dm->getEdgeArray(dm);
- mface = dm->getFaceArray(dm);
+ /* mface = dm->getTessFaceArray(dm); */ /* UNUSED */
+ mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
+ base_polyOrigIndex = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
+
+ /*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(&ccgdm->dm, CD_ORIGINDEX);*/
+ faceOrigIndex = DM_get_tessface_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+
+ polyOrigIndex = DM_get_poly_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+
+#if 0
+ /* this is not in trunk, can gives problems because colors initialize
+ * as black, just dont do it!, it works fine - campbell */
+ 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);
+#endif
+
+ 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;
+
+ origIndex = base_polyOrigIndex ? base_polyOrigIndex[origIndex] : origIndex;
+
+ 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 ? mpoly[origIndex].flag : 0;
+ faceFlags[1] = mpoly ? mpoly[origIndex].mat_nr : 0;
+ 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);
+ BLI_array_growitems(loopidx, numVerts);
+ for (s = 0; s < numVerts; s++) {
+ loopidx[s] = loopindex++;
+ }
+
+ BLI_array_empty(vertidx);
+ BLI_array_growitems(vertidx, numVerts);
+ for (s = 0; s < numVerts; s++) {
+ CCGVert *v = ccgSubSurf_getFaceVert(ss, f, s);
+ 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, hasWCol, hasOrigSpace);
+
+ /*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));
@@ -2736,6 +3195,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;
@@ -2744,16 +3206,36 @@ 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;
}
+ if(useSubsurfUv) {
+ CustomData *ldata = &ccgdm->dm.loopData;
+ CustomData *dmldata = &dm->loopData;
+ int numlayer = CustomData_number_of_layers(ldata, CD_MLOOPUV);
+ int dmnumlayer = CustomData_number_of_layers(dmldata, CD_MLOOPUV);
+
+ for (i=0; i<numlayer && i<dmnumlayer; i++)
+ set_subsurf_uv(ss, dm, &ccgdm->dm, i);
+ }
+
for(index = 0; index < totvert; ++index) {
CCGVert *v = ccgdm->vertMap[index].vert;
+ int mapIndex = ccgDM_getVertMapIndex(ccgdm->ss, v);
int vertIdx;
vertIdx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
@@ -2765,11 +3247,22 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
DM_copy_vert_data(dm, &ccgdm->dm, vertIdx, vertNum, 1);
+ if (vertOrigIndex) {
+ *vertOrigIndex = mapIndex;
+ ++vertOrigIndex;
+ }
++vertNum;
}
- MEM_freeN(qweight);
- MEM_freeN(tweight);
+ ccgdm->dm.numVertData = vertNum;
+ ccgdm->dm.numEdgeData = edgeNum;
+ ccgdm->dm.numTessFaceData = faceNum;
+ ccgdm->dm.numLoopData = loopindex2;
+ ccgdm->dm.numPolyData = faceNum;
+
+ BLI_array_free(vertidx);
+ BLI_array_free(loopidx);
+ free_ss_weights(&wtable);
return ccgdm;
}
diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h
index a5453f1537b..9fa66e91393 100644
--- a/source/blender/blenlib/BLI_array.h
+++ b/source/blender/blenlib/BLI_array.h
@@ -177,11 +177,11 @@
* same purpose as BLI_array_staticdeclare()
* but use when the max size is known ahead of time */
#define BLI_array_fixedstack_declare(arr, maxstatic, realsize, allocstr) \
- char _##arr##_static[maxstatic*sizeof(*arr)]; \
+ char _##arr##_static[maxstatic*sizeof(*(arr))]; \
const int _##arr##_is_static= ((void *)_##arr##_static) != ( \
- arr= (realsize <= maxstatic) ? \
+ arr= ((realsize) <= maxstatic) ? \
(void *)_##arr##_static : \
- MEM_mallocN(sizeof(*arr)*realsize, allocstr) \
+ MEM_mallocN(sizeof(*(arr)) * (realsize), allocstr) \
) \
#define BLI_array_fixedstack_free(arr) \
diff --git a/source/blender/blenlib/BLI_scanfill.h b/source/blender/blenlib/BLI_scanfill.h
index 5c788bc6bb7..890a8c8247d 100644
--- a/source/blender/blenlib/BLI_scanfill.h
+++ b/source/blender/blenlib/BLI_scanfill.h
@@ -51,6 +51,12 @@ extern "C" {
/* scanfill.c: used in displist only... */
struct EditVert *BLI_addfillvert(float *vec);
struct EditEdge *BLI_addfilledge(struct EditVert *v1, struct EditVert *v2);
+
+/* Optionally set EditEdge f to this to mark original boundary edges.
+ Only needed if there are internal diagonal edges pased to BLI_edgefill. */
+#define FILLBOUNDARY 1
+
+int BLI_begin_edgefill(void);
int BLI_edgefill(short mat_nr);
void BLI_end_edgefill(void);
diff --git a/source/blender/blenlib/BLI_smallhash.h b/source/blender/blenlib/BLI_smallhash.h
new file mode 100755
index 00000000000..50631769ba9
--- /dev/null
+++ b/source/blender/blenlib/BLI_smallhash.h
@@ -0,0 +1,73 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_SMALLHASH_H__
+#define __BLI_SMALLHASH_H__
+
+/** \file BLI_smallhash.h
+ * \ingroup bli
+ */
+
+/* a light stack-friendly hash library,
+ * (it uses stack space for smallish hash tables) */
+
+/* based on a doubling non-chaining approach */
+
+typedef struct {
+ uintptr_t key;
+ void *val;
+} SmallHashEntry;
+
+/*how much stack space to use before dynamically allocating memory*/
+#define SMSTACKSIZE 521
+typedef struct SmallHash {
+ SmallHashEntry *table;
+ SmallHashEntry _stacktable[SMSTACKSIZE];
+ SmallHashEntry _copytable[SMSTACKSIZE];
+ SmallHashEntry *stacktable, *copytable;
+ int used;
+ int curhash;
+ int size;
+} SmallHash;
+
+typedef struct {
+ SmallHash *hash;
+ int i;
+} SmallHashIter;
+
+void BLI_smallhash_init(SmallHash *hash);
+void BLI_smallhash_release(SmallHash *hash);
+void BLI_smallhash_insert(SmallHash *hash, uintptr_t key, void *item);
+void BLI_smallhash_remove(SmallHash *hash, uintptr_t key);
+void * BLI_smallhash_lookup(SmallHash *hash, uintptr_t key);
+int BLI_smallhash_haskey(SmallHash *hash, uintptr_t key);
+int BLI_smallhash_count(SmallHash *hash);
+void * BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key);
+void * BLI_smallhash_iternew(SmallHash *hash, SmallHashIter *iter, uintptr_t *key);
+/* void BLI_smallhash_print(SmallHash *hash); */ /* UNUSED */
+
+#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..654cafbc200
--- /dev/null
+++ b/source/blender/blenlib/BLI_sparsemap.h
@@ -0,0 +1,81 @@
+#if 0
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ *
+ * Contributor(s): Joseph Eagar (original author)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_SPARSEMAP_H__
+#define __BLI_SPARSEMAP_H__
+
+/** \file BLI_sparsemap.h
+ * \ingroup bli
+ */
+
+#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 /* __BLI_SPARSEMAP_H__ */
+
+#endif
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index 8e75a2db629..03bf375a894 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -76,6 +76,7 @@ int BLI_system_thread_count(void); /* gets the number of threads the system can
#define LOCK_OPENGL 5
#define LOCK_NODES 6
#define LOCK_MOVIECLIP 7
+#define LOCK_SCANFILL 8
void BLI_lock_thread(int type);
void BLI_unlock_thread(int type);
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 22bccc1b3b0..ff0833448c9 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -80,6 +80,7 @@ set(SRC
intern/rand.c
intern/rct.c
intern/scanfill.c
+ intern/smallhash.c
intern/storage.c
intern/string.c
intern/string_utf8.c
@@ -90,6 +91,8 @@ set(SRC
intern/winstuff.c
BLI_array.h
+ BLI_smallhash.h
+ BLI_sparsemap.h
BLI_args.h
BLI_blenlib.h
BLI_boxpack2d.h
diff --git a/source/blender/blenlib/SConscript b/source/blender/blenlib/SConscript
index 00caf8cd01d..c8172439167 100644
--- a/source/blender/blenlib/SConscript
+++ b/source/blender/blenlib/SConscript
@@ -5,6 +5,8 @@ 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']
defs = []
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index e10082348be..943b67cce8e 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -47,7 +47,7 @@
#include "BLO_sys_types.h" // for intptr_t support
/***/
-static unsigned int hashsizes[]= {
+unsigned int hashsizes[]= {
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,
diff --git a/source/blender/blenlib/intern/pbvh.c b/source/blender/blenlib/intern/pbvh.c
index 5c7a29c6277..b7175db4ca3 100644
--- a/source/blender/blenlib/intern/pbvh.c
+++ b/source/blender/blenlib/intern/pbvh.c
@@ -1585,7 +1585,7 @@ void BLI_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3])
}
/* coordinates are new -- normals should also be updated */
- mesh_calc_normals(pbvh->verts, pbvh->totvert, pbvh->faces, pbvh->totprim, NULL);
+ mesh_calc_normals_tessface(pbvh->verts, pbvh->totvert, pbvh->faces, pbvh->totprim, NULL);
for (a= 0; a < pbvh->totnode; ++a)
BLI_pbvh_node_mark_update(&pbvh->nodes[a]);
diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c
index 369984c1719..7652cc4f4af 100644
--- a/source/blender/blenlib/intern/scanfill.c
+++ b/source/blender/blenlib/intern/scanfill.c
@@ -30,6 +30,10 @@
* \ingroup bli
*/
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
#include "MEM_guardedalloc.h"
@@ -38,6 +42,8 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_scanfill.h"
+#include "BLI_utildefines.h"
+#include "BLI_threads.h"
/* callbacks for errors and interrupts and some goo */
static void (*BLI_localErrorCallBack)(const char*) = NULL;
@@ -137,54 +143,64 @@ struct mem_elements {
only to be used within loops, and not by one function at a time
free in the end, with argument '-1'
*/
+#define MEM_ELEM_BLOCKSIZE 16384
+static struct mem_elements * melem__cur= 0;
+static int melem__offs= 0; /* the current free address */
+static ListBase melem__lb= {NULL, NULL};
-static void *new_mem_element(int size)
+static void *mem_element_new(int size)
{
- int blocksize= 16384;
- static int offs= 0; /* the current free address */
- static struct mem_elements *cur= 0;
- static ListBase lb= {0, 0};
- void *adr;
+ BLI_assert(!(size>10000 || size==0)); /* this is invalid use! */
+
+ size = (size + 3 ) & ~3; /* allocate in units of 4 */
- if(size>10000 || size==0) {
- printf("incorrect use of new_mem_element\n");
+ if(melem__cur && (size + melem__offs < MEM_ELEM_BLOCKSIZE)) {
+ void *adr= (void *) (melem__cur->data+melem__offs);
+ melem__offs+= size;
+ return adr;
}
- else if(size== -1) {
- cur= lb.first;
- while(cur) {
- MEM_freeN(cur->data);
- cur= cur->next;
- }
- BLI_freelistN(&lb);
-
- return NULL;
+ else {
+ melem__cur= MEM_callocN( sizeof(struct mem_elements), "newmem");
+ melem__cur->data= MEM_callocN(MEM_ELEM_BLOCKSIZE, "newmem");
+ BLI_addtail(&melem__lb, melem__cur);
+
+ melem__offs= size;
+ return melem__cur->data;
}
-
- size= 4*( (size+3)/4 );
-
- if(cur) {
- if(size+offs < blocksize) {
- adr= (void *) (cur->data+offs);
- offs+= size;
- return adr;
+}
+static void mem_element_reset(void)
+{
+ struct mem_elements *first;
+ /*BMESH_TODO: keep the first block, gives memory leak on exit with 'newmem' */
+
+ if((first= melem__lb.first)) { /* can be false if first fill fails */
+ BLI_remlink(&melem__lb, first);
+
+ melem__cur= melem__lb.first;
+ while(melem__cur) {
+ MEM_freeN(melem__cur->data);
+ melem__cur= melem__cur->next;
}
+ BLI_freelistN(&melem__lb);
+
+ /*reset the block we're keeping*/
+ BLI_addtail(&melem__lb, first);
+ memset(first->data, 0, MEM_ELEM_BLOCKSIZE);
}
-
- cur= MEM_callocN( sizeof(struct mem_elements), "newmem");
- cur->data= MEM_callocN(blocksize, "newmem");
- BLI_addtail(&lb, cur);
-
- offs= size;
- return cur->data;
+
+ melem__cur= first;
+ melem__offs= 0;
}
void BLI_end_edgefill(void)
{
- new_mem_element(-1);
+ mem_element_reset();
fillvertbase.first= fillvertbase.last= 0;
filledgebase.first= filledgebase.last= 0;
fillfacebase.first= fillfacebase.last= 0;
+
+ BLI_unlock_thread(LOCK_SCANFILL);
}
/* **** FILL ROUTINES *************************** */
@@ -193,7 +209,7 @@ EditVert *BLI_addfillvert(float *vec)
{
EditVert *eve;
- eve= new_mem_element(sizeof(EditVert));
+ eve= mem_element_new(sizeof(EditVert));
BLI_addtail(&fillvertbase, eve);
eve->co[0] = vec[0];
@@ -207,7 +223,7 @@ EditEdge *BLI_addfilledge(EditVert *v1, EditVert *v2)
{
EditEdge *newed;
- newed= new_mem_element(sizeof(EditEdge));
+ newed= mem_element_new(sizeof(EditEdge));
BLI_addtail(&filledgebase, newed);
newed->v1= v1;
@@ -221,7 +237,7 @@ static void addfillface(EditVert *v1, EditVert *v2, EditVert *v3, short mat_nr)
/* does not make edges */
EditFace *evl;
- evl= new_mem_element(sizeof(EditFace));
+ evl= mem_element_new(sizeof(EditFace));
BLI_addtail(&fillfacebase, evl);
evl->v1= v1;
@@ -498,7 +514,7 @@ static int scanfill(PolyFill *pf, short mat_nr)
EditVert *eve,*v1,*v2,*v3;
EditEdge *eed,*nexted,*ed1,*ed2,*ed3;
float miny = 0.0;
- int a,b,verts, maxface, totface;
+ int a,b,verts, maxface, totface;
short nr, test, twoconnected=0;
nr= pf->nr;
@@ -534,7 +550,7 @@ static int scanfill(PolyFill *pf, short mat_nr)
}
else {
eed->v2->f= 255;
- eed->v2->tmp.v = eed->v1->tmp.v;
+ eed->v2->tmp.v = eed->v1;
}
}
}
@@ -564,20 +580,22 @@ static int scanfill(PolyFill *pf, short mat_nr)
eed= filledgebase.first;
while(eed) {
nexted= eed->next;
- eed->f= 0;
BLI_remlink(&filledgebase,eed);
-/* commented all of this out, this I have no idea for what it is for, probably from ancient past */
-/* it does crash blender, since it uses mixed original and new vertices (ton) */
-// if(eed->v1->f==255) {
-// v1= eed->v1;
-// while((eed->v1->f == 255) && (eed->v1->tmp.v != v1))
-// eed->v1 = eed->v1->tmp.v;
-// }
-// if(eed->v2->f==255) {
-// v2= eed->v2;
-// while((eed->v2->f == 255) && (eed->v2->tmp.v != v2))
-// eed->v2 = eed->v2->tmp.v;
-// }
+ /* This code is for handling zero-length edges that get
+ collapsed in step 0. It was removed for some time to
+ fix trunk bug #4544, so if that comes back, this code
+ may need some work, or there will have to be a better
+ fix to #4544. */
+ if(eed->v1->f==255) {
+ v1= eed->v1;
+ while((eed->v1->f == 255) && (eed->v1->tmp.v != v1))
+ eed->v1 = eed->v1->tmp.v;
+ }
+ if(eed->v2->f==255) {
+ v2= eed->v2;
+ while((eed->v2->f == 255) && (eed->v2->tmp.v != v2))
+ eed->v2 = eed->v2->tmp.v;
+ }
if(eed->v1!=eed->v2) addedgetoscanlist(eed,verts);
eed= nexted;
@@ -687,8 +705,8 @@ static int scanfill(PolyFill *pf, short mat_nr)
ed1->v2->f= 0;
ed1->v1->h--;
ed1->v2->h--;
- /* ed2 can be removed when it's an old one */
- if(ed2->f==0 && twoconnected) {
+ /* ed2 can be removed when it's a boundary edge */
+ if((ed2->f == 0 && twoconnected) || (ed2->f == FILLBOUNDARY)) {
BLI_remlink((ListBase *)&(sc->first),ed2);
BLI_addtail(&filledgebase,ed2);
ed2->v2->f= 0;
@@ -706,19 +724,20 @@ static int scanfill(PolyFill *pf, short mat_nr)
/* printf("add new edge %x %x\n",v1,v3); */
sc1= addedgetoscanlist(ed3, verts);
- if(sc1) { /* ed3 already exists: remove */
+ if(sc1) { /* ed3 already exists: remove if a boundary */
/* printf("Edge exists\n"); */
ed3->v1->h--;
ed3->v2->h--;
- if(twoconnected) ed3= sc1->first;
- else ed3= 0;
+ ed3= sc1->first;
while(ed3) {
if( (ed3->v1==v1 && ed3->v2==v3) || (ed3->v1==v3 && ed3->v2==v1) ) {
- BLI_remlink((ListBase *)&(sc1->first),ed3);
- BLI_addtail(&filledgebase,ed3);
- ed3->v1->h--;
- ed3->v2->h--;
+ if (twoconnected || ed3->f==FILLBOUNDARY) {
+ BLI_remlink((ListBase *)&(sc1->first),ed3);
+ BLI_addtail(&filledgebase,ed3);
+ ed3->v1->h--;
+ ed3->v2->h--;
+ }
break;
}
ed3= ed3->next;
@@ -750,6 +769,12 @@ static int scanfill(PolyFill *pf, short mat_nr)
}
+int BLI_begin_edgefill(void)
+{
+ BLI_lock_thread(LOCK_SCANFILL);
+
+ return 1;
+}
int BLI_edgefill(short mat_nr)
{
@@ -765,24 +790,55 @@ int BLI_edgefill(short mat_nr)
EditVert *eve;
EditEdge *eed,*nexted;
PolyFill *pflist,*pf;
- float *minp, *maxp, *v1, *v2, norm[3], len;
+ float limit, *minp, *maxp, *v1, *v2, norm[3], len;
short a,c,poly=0,ok=0,toggle=0;
int totfaces= 0; /* total faces added */
/* 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 && (mat_nr & 2)) {
+ eve = fillvertbase.first;
+
+ addfillface(eve, eve->next, eve->next->next, 0);
+ return 1;
+ } else if (a == 4 && (mat_nr & 2)) {
+ float vec1[3], vec2[3];
+
+ eve = fillvertbase.first;
+ /* no need to check 'eve->next->next->next' is valid, already counted */
+ if (1) { //BMESH_TODO) {
+ /*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 2;
}
/* first test vertices if they are in edges */
/* including resetting of flags */
eed= filledgebase.first;
while(eed) {
- eed->f= eed->f1= eed->h= 0;
+ eed->f1= eed->h= 0;
eed->v1->f= 1;
eed->v2->f= 1;
@@ -810,9 +866,17 @@ int BLI_edgefill(short mat_nr)
v1= eve->co;
v2= 0;
eve= fillvertbase.first;
+ limit = a < 5 ? FLT_EPSILON*200 : M_PI/24.0;
while(eve) {
if(v2) {
if( compare_v3v3(v2, eve->co, COMPLIMIT)==0) {
+ float inner = angle_v3v3v3(v1, v2, eve->co);
+
+ if (fabsf(inner-M_PI) < limit || fabsf(inner) < limit) {
+ eve = eve->next;
+ continue;
+ }
+
len= normal_tri_v3( norm,v1, v2, eve->co);
if(len != 0.0f) break;
}
@@ -922,7 +986,7 @@ int BLI_edgefill(short mat_nr)
- eve->h :amount of edges connected to vertex
- eve->tmp.v :store! original vertex number
- - eed->f :
+ - eed->f :1= boundary edge (optionally set by caller)
- eed->f1 :poly number
*/
diff --git a/source/blender/blenlib/intern/smallhash.c b/source/blender/blenlib/intern/smallhash.c
new file mode 100644
index 00000000000..fb03849bfb3
--- /dev/null
+++ b/source/blender/blenlib/intern/smallhash.c
@@ -0,0 +1,281 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+#include "BLI_utildefines.h"
+
+#include "BLI_smallhash.h"
+
+/* SMHASH_CELL_UNUSED means this cell is inside a key series,
+ * while SMHASH_CELL_FREE means this cell terminates a key series.
+ *
+ * no chance of anyone shoving INT32_MAX-2 into a *val pointer, I
+ * imagine. hopefully.
+ *
+ * note: these have the SMHASH suffix because we may want to make them public.
+ */
+#define SMHASH_CELL_UNUSED ((void *)0x7FFFFFFF)
+#define SMHASH_CELL_FREE ((void *)0x7FFFFFFD)
+
+#define SMHASH_NONZERO(n) ((n) + !(n))
+#define SMHASH_NEXT(h, hoff) ABS(((h) + ((hoff = SMHASH_NONZERO(hoff * 2) + 1), hoff)))
+
+extern unsigned int hashsizes[];
+
+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 = SMHASH_CELL_FREE;
+ }
+}
+
+/*NOTE: does *not* free *hash itself! only the direct data!*/
+void BLI_smallhash_release(SmallHash *hash)
+{
+ if (hash == NULL) {
+ return;
+ }
+
+ if (hash->table != hash->stacktable) {
+ MEM_freeN(hash->table);
+ }
+}
+
+void BLI_smallhash_insert(SmallHash *hash, uintptr_t key, void *item)
+{
+ int h, hoff=1;
+
+ if (hash->size < hash->used * 3) {
+ int newsize = hashsizes[++hash->curhash];
+ SmallHashEntry *tmp;
+ int i = 0;
+
+ if (hash->table != hash->stacktable || newsize > SMSTACKSIZE) {
+ tmp = MEM_callocN(sizeof(*hash->table) * newsize, __func__);
+ }
+ else {
+ SWAP(SmallHashEntry *, hash->stacktable, hash->copytable);
+ tmp = hash->stacktable;
+ }
+
+ SWAP(SmallHashEntry *, tmp, hash->table);
+
+ hash->size = newsize;
+
+ for (i = 0; i < hash->size; i++) {
+ hash->table[i].val = SMHASH_CELL_FREE;
+ }
+
+ for (i = 0; i<hashsizes[hash->curhash - 1]; i++) {
+ if (ELEM(tmp[i].val, SMHASH_CELL_UNUSED, SMHASH_CELL_FREE)) {
+ continue;
+ }
+
+ h = ABS((int)(tmp[i].key));
+ hoff = 1;
+ while (!ELEM(hash->table[h % newsize].val, SMHASH_CELL_UNUSED, SMHASH_CELL_FREE)) {
+ h = SMHASH_NEXT(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 = ABS((int)key);
+ hoff = 1;
+
+ while (!ELEM(hash->table[h % hash->size].val, SMHASH_CELL_UNUSED, SMHASH_CELL_FREE)) {
+ h = SMHASH_NEXT(h, hoff);
+ }
+
+ h %= hash->size;
+ hash->table[h].key = key;
+ hash->table[h].val = item;
+
+ hash->used++;
+}
+
+void BLI_smallhash_remove(SmallHash *hash, uintptr_t key)
+{
+ int h, hoff=1;
+
+ h = ABS((int)key);
+
+ while ((hash->table[h % hash->size].key != key) ||
+ (hash->table[h % hash->size].val == SMHASH_CELL_UNUSED))
+ {
+ if (hash->table[h % hash->size].val == SMHASH_CELL_FREE) {
+ return;
+ }
+
+ h = SMHASH_NEXT(h, hoff);
+ }
+
+ h %= hash->size;
+ hash->table[h].key = 0;
+ hash->table[h].val = SMHASH_CELL_UNUSED;
+}
+
+void *BLI_smallhash_lookup(SmallHash *hash, uintptr_t key)
+{
+ int h, hoff=1;
+ void *v;
+
+ h = ABS((int)key);
+
+ if (hash->table == NULL) {
+ return NULL;
+ }
+
+ while ((hash->table[h % hash->size].key != key) ||
+ (hash->table[h % hash->size].val == SMHASH_CELL_UNUSED))
+ {
+ if (hash->table[h % hash->size].val == SMHASH_CELL_FREE) {
+ return NULL;
+ }
+
+ h = SMHASH_NEXT(h, hoff);
+ }
+
+ v = hash->table[h % hash->size].val;
+ if (ELEM(v, SMHASH_CELL_UNUSED, SMHASH_CELL_FREE)) {
+ return NULL;
+ }
+
+ return v;
+}
+
+
+int BLI_smallhash_haskey(SmallHash *hash, uintptr_t key)
+{
+ int h = ABS((int)key);
+ int hoff =1;
+
+ if (hash->table == NULL) {
+ return 0;
+ }
+
+ while ((hash->table[h % hash->size].key != key) ||
+ (hash->table[h % hash->size].val == SMHASH_CELL_UNUSED))
+ {
+ if (hash->table[h % hash->size].val == SMHASH_CELL_FREE) {
+ return 0;
+ }
+
+ h = SMHASH_NEXT(h, hoff);
+ }
+
+ return !ELEM(hash->table[h % hash->size].val, SMHASH_CELL_UNUSED, SMHASH_CELL_FREE);
+}
+
+int BLI_smallhash_count(SmallHash *hash)
+{
+ return hash->used;
+}
+
+void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key)
+{
+ while (iter->i < iter->hash->size) {
+ if ( (iter->hash->table[iter->i].val != SMHASH_CELL_UNUSED) &&
+ (iter->hash->table[iter->i].val != SMHASH_CELL_FREE))
+ {
+ if (key) {
+ *key = iter->hash->table[iter->i].key;
+ }
+
+ iter->i++;
+
+ return iter->hash->table[iter->i - 1].val;
+ }
+
+ iter->i++;
+ }
+
+ return NULL;
+}
+
+void *BLI_smallhash_iternew(SmallHash *hash, SmallHashIter *iter, uintptr_t *key)
+{
+ iter->hash = hash;
+ iter->i = 0;
+
+ return BLI_smallhash_iternext(iter, key);
+}
+
+/* note, this was called _print_smhash in knifetool.c
+ * it may not be intended for general use - campbell */
+#if 0
+void BLI_smallhash_print(SmallHash *hash)
+{
+ int i, linecol=79, c=0;
+
+ printf("{");
+ for (i=0; i<hash->size; i++) {
+ if (hash->table[i].val == SMHASH_CELL_UNUSED) {
+ printf("--u-");
+ }
+ else if (hash->table[i].val == SMHASH_CELL_FREE) {
+ printf("--f-");
+ }
+ else {
+ printf("%2x", (unsigned int)hash->table[i].key);
+ }
+
+ if (i != hash->size-1)
+ printf(", ");
+
+ c += 6;
+
+ if (c >= linecol) {
+ printf("\n ");
+ c = 0;
+ }
+ }
+
+ fflush(stdout);
+}
+#endif
diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c
index 98d2179e2dd..e92b445c27f 100644
--- a/source/blender/blenlib/intern/threads.c
+++ b/source/blender/blenlib/intern/threads.c
@@ -115,6 +115,7 @@ static pthread_mutex_t _rcache_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _opengl_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _nodes_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _movieclip_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t _scanfill_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_t mainid;
static int thread_levels= 0; /* threads can be invoked inside threads */
@@ -353,6 +354,8 @@ void BLI_lock_thread(int type)
pthread_mutex_lock(&_nodes_lock);
else if (type==LOCK_MOVIECLIP)
pthread_mutex_lock(&_movieclip_lock);
+ else if (type == LOCK_SCANFILL)
+ pthread_mutex_lock(&_scanfill_lock);
}
void BLI_unlock_thread(int type)
@@ -373,6 +376,8 @@ void BLI_unlock_thread(int type)
pthread_mutex_unlock(&_nodes_lock);
else if(type==LOCK_MOVIECLIP)
pthread_mutex_unlock(&_movieclip_lock);
+ else if(type == LOCK_SCANFILL)
+ pthread_mutex_unlock(&_scanfill_lock);
}
/* Mutex Locks */
diff --git a/source/blender/blenloader/SConscript b/source/blender/blenloader/SConscript
index 0333eab7e1f..20b560744b3 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 ../editors/include'
-incs += ' ../render/extern/include ../makesrna ../nodes ../imbuf'
+incs += ' ../render/extern/include ../makesrna ../nodes ../bmesh ../imbuf'
incs += ' ' + env['BF_ZLIB_INC']
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index f46543e9b55..82381f99ddc 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -101,6 +101,7 @@
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_edgehash.h"
#include "BKE_anim.h"
#include "BKE_action.h"
@@ -2704,6 +2705,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);
@@ -3626,6 +3637,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;
@@ -3653,10 +3684,28 @@ 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);
+ /*check if we need to convert mfaces to mpolys*/
+ if (me->totface && !me->totpoly) {
+ convert_mfaces_to_mpolys(me);
+ }
+
+ /*
+ * Re-tesselate, even if the polys were just created from tessfaces, this
+ * is important because it:
+ * - fill the CD_POLYINDEX layer
+ * - gives consistency of tessface between loading from a file and
+ * converting an edited BMesh back into a mesh (i.e. it replaces
+ * quad tessfaces in a loaded mesh immediately, instead of lazily
+ * waiting until edit mode has been entered/exited, making it easier
+ * to recognize problems that would otherwise only show up after edits).
+ */
+ BKE_mesh_tessface_calc(me);
+
me->id.flag -= LIB_NEEDLINK;
}
me= me->id.next;
@@ -3675,10 +3724,17 @@ static void direct_link_dverts(FileData *fd, int count, MDeformVert *mdverts)
}
for (i= count; i > 0; i--, mdverts++) {
- if(mdverts->dw) {
- mdverts->dw= newdataadr(fd, mdverts->dw);
+ /*convert to vgroup allocation system*/
+ MDeformWeight *dw;
+ if(mdverts->dw && (dw= newdataadr(fd, mdverts->dw))) {
+ const ssize_t dw_len= mdverts->totweight * sizeof(MDeformWeight);
+ void *dw_tmp= MEM_mallocN(dw_len, "direct_link_dverts");
+ memcpy(dw_tmp, dw, dw_len);
+ mdverts->dw= dw_tmp;
+ MEM_freeN(dw);
}
- if (mdverts->dw == NULL) {
+ else {
+ mdverts->dw= NULL;
mdverts->totweight= 0;
}
}
@@ -3691,7 +3747,18 @@ static void direct_link_mdisps(FileData *fd, int count, MDisps *mdisps, int exte
for(i = 0; i < count; ++i) {
mdisps[i].disps = newdataadr(fd, mdisps[i].disps);
-
+
+ /*put .disps into cellalloc system*/
+ if (mdisps[i].disps) {
+ float *disp2;
+
+ disp2 = MEM_mallocN(MEM_allocN_len(mdisps[i].disps), "cellalloc .disps copy");
+ memcpy(disp2, mdisps[i].disps, MEM_allocN_len(mdisps[i].disps));
+
+ MEM_freeN(mdisps[i].disps);
+ mdisps[i].disps = (float (*)[3])disp2;
+ }
+
if( (fd->flags & FD_FLAGS_SWITCH_ENDIAN) && (mdisps[i].disps) ) {
/* DNA_struct_switch_endian doesn't do endian swap for (*disps)[] */
/* this does swap for data written at write_mdisps() - readfile.c */
@@ -3741,12 +3808,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);
@@ -3758,7 +3830,9 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
direct_link_customdata(fd, &mesh->vdata, mesh->totvert);
direct_link_customdata(fd, &mesh->edata, mesh->totedge);
direct_link_customdata(fd, &mesh->fdata, mesh->totface);
-
+ direct_link_customdata(fd, &mesh->ldata, mesh->totloop);
+ direct_link_customdata(fd, &mesh->pdata, mesh->totpoly);
+
#ifdef USE_BMESH_FORWARD_COMPAT
/* NEVER ENABLE THIS CODE INTO BMESH!
@@ -3791,7 +3865,7 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
mesh->bb= NULL;
mesh->mselect = NULL;
- mesh->edit_mesh= NULL;
+ mesh->edit_btmesh= NULL;
/* Multires data */
mesh->mr= newdataadr(fd, mesh->mr);
@@ -6795,7 +6869,7 @@ static void customdata_version_242(Mesh *me)
}
}
- mesh_update_customdata_pointers(me);
+ mesh_update_customdata_pointers(me, TRUE);
}
/*only copy render texface layer from active*/
@@ -12498,7 +12572,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
Mesh *me;
for(me= main->mesh.first; me; me= me->id.next)
- mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+ mesh_calc_normals_tessface(me->mvert, me->totvert, me->mface, me->totface, NULL);
}
if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 2)){
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index a7f6354583f..f1b76cb56bf 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -156,6 +156,7 @@ Any case: direct data is ALWAYS after the lib block
#include "BKE_modifier.h"
#include "BKE_fcurve.h"
#include "BKE_pointcache.h"
+#include "BKE_mesh.h"
#include "BLO_writefile.h"
#include "BLO_readfile.h"
@@ -1686,22 +1687,135 @@ static void write_customdata(WriteData *wd, ID *id, int count, CustomData *data,
static void write_meshs(WriteData *wd, ListBase *idbase)
{
Mesh *mesh;
+ int save_for_old_blender= 0;
+
+#ifdef USE_BMESH_SAVE_AS_COMPAT
+ save_for_old_blender = wd->use_mesh_compat; /* option to save with older mesh format */
+#endif
mesh= idbase->first;
while(mesh) {
if(mesh->id.us>0 || wd->current) {
/* write LibData */
- writestruct(wd, ID_ME, "Mesh", 1, mesh);
+ if (!save_for_old_blender) {
+
+#ifdef USE_BMESH_SAVE_WITHOUT_MFACE
+ Mesh backup_mesh = {{0}};
+ /* cache only - dont write */
+ backup_mesh.mface = mesh->mface;
+ mesh->mface = NULL;
+ /* -- */
+ backup_mesh.totface = mesh->totface;
+ mesh->totface = 0;
+ /* -- */
+#endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
+
+ writestruct(wd, ID_ME, "Mesh", 1, mesh);
+
+ /* direct data */
+ if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
+ if (mesh->adt) write_animdata(wd, mesh->adt);
+
+ writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
+
+ write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, -1, 0);
+ /* fdata is really a dummy - written so slots align */
+ 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);
+
+#ifdef USE_BMESH_SAVE_WITHOUT_MFACE
+ /* cache only - dont write */
+ mesh->mface = backup_mesh.mface;
+ /* -- */
+ mesh->totface = backup_mesh.totface;
+#endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
- /* direct data */
- if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
- if (mesh->adt) write_animdata(wd, mesh->adt);
+ }
+ else {
- writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
+#ifdef USE_BMESH_SAVE_AS_COMPAT
- 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);
+ Mesh backup_mesh = {{0}};
+
+ /* backup */
+ backup_mesh.mpoly = mesh->mpoly;
+ mesh->mpoly = NULL;
+ /* -- */
+ backup_mesh.mface = mesh->mface;
+ mesh->mface = NULL;
+ /* -- */
+ backup_mesh.totface = mesh->totface;
+ mesh->totface = 0;
+ /* -- */
+ backup_mesh.totpoly = mesh->totpoly;
+ mesh->totpoly = 0;
+ /* -- */
+ backup_mesh.totloop = mesh->totloop;
+ mesh->totloop = 0;
+ /* -- */
+ backup_mesh.fdata = mesh->fdata;
+ memset(&mesh->fdata, 0, sizeof(CustomData));
+ /* -- */
+ backup_mesh.pdata = mesh->pdata;
+ memset(&mesh->pdata, 0, sizeof(CustomData));
+ /* -- */
+ backup_mesh.ldata = mesh->ldata;
+ memset(&mesh->ldata, 0, sizeof(CustomData));
+ /* -- */
+ backup_mesh.edit_btmesh = mesh->edit_btmesh;
+ mesh->edit_btmesh = NULL;
+ /* backup */
+
+
+ /* now fill in polys to mfaces*/
+ mesh->totface= mesh_mpoly_to_mface(&mesh->fdata, &backup_mesh.ldata, &backup_mesh.pdata,
+ mesh->totface, backup_mesh.totloop, backup_mesh.totpoly);
+
+ mesh_update_customdata_pointers(mesh, FALSE);
+
+ writestruct(wd, ID_ME, "Mesh", 1, mesh);
+
+ /* direct data */
+ if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
+ if (mesh->adt) write_animdata(wd, mesh->adt);
+
+ writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
+
+ 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);
+ /* harmless for older blender versioins but _not_ writing these keeps file size down */
+ /*
+ write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, -1, 0);
+ */
+
+ /* restore */
+ mesh->mpoly = backup_mesh.mpoly;
+ /* -- */
+ mesh->mface = backup_mesh.mface;
+ /* -- */
+ CustomData_free(&mesh->fdata, mesh->totface);
+ /* -- */
+ mesh->fdata= backup_mesh.fdata;
+ /* -- */
+ mesh->pdata= backup_mesh.pdata;
+ /* -- */
+ mesh->ldata= backup_mesh.ldata;
+ /* -- */
+ mesh->totface = backup_mesh.totface;
+ mesh->totpoly = backup_mesh.totpoly;
+ mesh->totloop = backup_mesh.totloop;
+ /* -- */
+ mesh_update_customdata_pointers(mesh, FALSE);
+ /* --*/
+ mesh->edit_btmesh = backup_mesh.edit_btmesh; /* keep this after updating custom pointers */
+ /* restore */
+
+#endif /* USE_BMESH_SAVE_AS_COMPAT */
+ }
}
mesh= mesh->id.next;
}
diff --git a/source/blender/blenpluginapi/SConscript b/source/blender/blenpluginapi/SConscript
index 7c7c1318a6e..a5e7f479cfb 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..48f653f4759
--- /dev/null
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -0,0 +1,137 @@
+# $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
+ .
+ intern
+ operators
+ ../avi
+ ../blenfont
+ ../blenkernel
+ ../blenlib
+ ../blenloader
+ ../editors/include
+ ../editors/mesh
+ ../gpu
+ ../ikplugin
+ ../imbuf
+ ../makesdna
+ ../makesrna
+ ../modifiers
+ ../nodes
+ ../render/extern/include
+ ../../../extern/glew/include
+ ../../../intern/audaspace/intern
+ ../../../intern/bsp/extern
+ ../../../intern/decimation/extern
+ ../../../intern/elbeem/extern
+ ../../../intern/guardedalloc
+ ../../../intern/iksolver/extern
+ ../../../intern/memutil
+ ../../../intern/mikktspace
+ ../../../intern/opennl/extern
+ ../../../intern/smoke/extern
+ # XXX - BAD LEVEL CALL WM_api.h
+ ../../../source/blender/windowmanager
+)
+
+set(INC_SYS
+ ${ZLIB_INCLUDE_DIRS}
+)
+
+set(SRC
+ operators/bmo_bevel.c
+ operators/bmo_connect.c
+ operators/bmo_create.c
+ operators/bmo_dissolve.c
+ operators/bmo_dupe.c
+ operators/bmo_edgesplit.c
+ operators/bmo_extrude.c
+ operators/bmo_join_triangles.c
+ operators/bmo_mesh_conv.c
+ operators/bmo_mirror.c
+ operators/bmo_primitive.c
+ operators/bmo_removedoubles.c
+ operators/bmo_subdivide.c
+ operators/bmo_subdivide.h
+ operators/bmo_triangulate.c
+ operators/bmo_utils.c
+
+ intern/bmesh_construct.c
+ intern/bmesh_inline.c
+ intern/bmesh_interp.c
+ intern/bmesh_iterators.c
+ intern/bmesh_iterators_inline.c
+ intern/bmesh_marking.c
+ intern/bmesh_mesh.c
+ intern/bmesh_mods.c
+ intern/bmesh_newcore.c
+ intern/bmesh_opdefines.c
+ intern/bmesh_operators.c
+ intern/bmesh_operators_private.h
+ intern/bmesh_polygon.c
+ intern/bmesh_private.h
+ intern/bmesh_queries.c
+ intern/bmesh_structure.c
+ intern/bmesh_structure.h
+ intern/bmesh_walkers.c
+ intern/bmesh_walkers_impl.c
+ intern/bmesh_walkers_private.h
+
+ tools/BME_bevel.c
+
+ bmesh.h
+ bmesh_class.h
+ bmesh_error.h
+ bmesh_iterators.h
+ bmesh_marking.h
+ bmesh_operator_api.h
+ bmesh_operators.h
+ bmesh_queries.h
+ bmesh_walkers.h
+)
+
+add_definitions(-DGLEW_STATIC)
+
+if(WITH_LZO)
+ add_definitions(-DWITH_LZO)
+ list(APPEND INC_SYS
+ ../../../extern/lzo/minilzo
+ )
+endif()
+
+if(WITH_LZMA)
+ add_definitions(-DWITH_LZMA)
+ list(APPEND INC_SYS
+ ../../../extern/lzma
+ )
+endif()
+
+if(MSVC)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
+endif()
+
+blender_add_lib(bf_bmesh "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/bmesh/SConscript b/source/blender/bmesh/SConscript
new file mode 100644
index 00000000000..91b7a72bb1f
--- /dev/null
+++ b/source/blender/bmesh/SConscript
@@ -0,0 +1,40 @@
+#!/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('../blenloader')
+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..ee41948589f
--- /dev/null
+++ b/source/blender/bmesh/bmesh.h
@@ -0,0 +1,382 @@
+/*
+ * ***** 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): Geoffrey Bantle, Levi Schooley.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_H__
+#define __BMESH_H__
+
+/** \file blender/bmesh/bmesh.h
+ * \ingroup bmesh
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "DNA_listBase.h"
+#include "DNA_customdata_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "bmesh_class.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->htype (char) */
+#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->hflag (char) */
+#define BM_ELEM_SELECT (1 << 0)
+#define BM_ELEM_HIDDEN (1 << 1)
+#define BM_ELEM_SEAM (1 << 2)
+#define BM_ELEM_SMOOTH (1 << 3) /* used for faces and edges, note from the user POV,
+ * this is a sharp edge when disabled */
+
+#define BM_ELEM_TAG (1 << 4) /* internal flag, used for ensuring correct normals
+ * during multires interpolation, and any other time
+ * when temp tagging is handy.
+ * always assume dirty & clear before use. */
+
+#define BM_ELEM_FREESTYLE (1 << 5) /* used for faces and edges */
+
+/* we have 3 spare flags which is awesome but since we're limited to 8
+ * only add new flags with care! - campbell */
+/* #define BM_ELEM_SPARE (1<<5) */
+/* #define BM_ELEM_SPARE (1<<6) */
+/* #define BM_ELEM_NONORMCALC (1<<7) */ /* UNUSED */
+
+/* stub */
+void bmesh_error(void);
+
+/* Mesh Level Ops */
+extern int bm_mesh_allocsize_default[4];
+
+/* ob is needed by multires */
+BMesh *BM_mesh_create(struct Object *ob, const int allocsize[4]);
+BMesh *BM_mesh_copy(BMesh *bmold);
+void BM_mesh_free(BMesh *bm);
+
+/* frees mesh, but not actual BMesh struct */
+void BM_mesh_data_free(BMesh *bm);
+void BM_mesh_normals_update(BMesh *bm);
+
+/* Construction */
+BMVert *BM_vert_create(BMesh *bm, const float co[3], const BMVert *example);
+BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *example, int nodouble);
+BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len, int nodouble);
+
+BMFace *BM_face_create_quad_tri_v(BMesh *bm,
+ BMVert **verts, int len,
+ const BMFace *example, const int nodouble);
+
+/* easier to use version of BM_face_create_quad_tri_v.
+ * creates edges if necassary. */
+BMFace *BM_face_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
+ const BMFace *example, const 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. */
+BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, int nodouble);
+
+/* stuff for dealing with header flags */
+BM_INLINE char BM_elem_flag_test(const void *element, const char hflag);
+
+/* stuff for dealing with header flags */
+BM_INLINE void BM_elem_flag_enable(void *element, const char hflag);
+
+/* stuff for dealing with header flags */
+BM_INLINE void BM_elem_flag_disable(void *element, const char hflag);
+
+/* stuff for dealing BM_elem_flag_toggle header flags */
+BM_INLINE void BM_elem_flag_toggle(void *element, const char hflag);
+BM_INLINE void BM_elem_flag_merge(void *element_a, void *element_b);
+
+/* notes on BM_elem_index_set(...) usage,
+ * Set index is sometimes abused as temp storage, other times we cant be
+ * sure if the index values are valid because certain operations have modified
+ * the mesh structure.
+ *
+ * To set the elements to valid indicies 'BM_mesh_elem_index_ensure' should be used
+ * rather then adding inline loops, however there are cases where we still
+ * set the index directly
+ *
+ * In an attempt to manage this, here are 3 tags Im adding to uses of
+ * 'BM_elem_index_set'
+ *
+ * - 'set_inline' -- since the data is already being looped over set to a
+ * valid value inline.
+ *
+ * - 'set_dirty!' -- intentionally sets the index to an invalid value,
+ * flagging 'bm->elem_index_dirty' so we dont use it.
+ *
+ * - 'set_ok' -- this is valid use since the part of the code is low level.
+ *
+ * - 'set_ok_invalid' -- set to -1 on purpose since this should not be
+ * used without a full array re-index, do this on
+ * adding new vert/edge/faces since they may be added at
+ * the end of the array.
+ *
+ * - 'set_loop' -- currently loop index values are not used used much so
+ * assume each case they are dirty.
+ * - campbell */
+
+BM_INLINE void BM_elem_index_set(void *element, const int index);
+BM_INLINE int BM_elem_index_get(const void *element);
+
+/* todo */
+BMFace *BM_face_copy(BMesh *bm, BMFace *f, int copyedges, int copyverts);
+
+/* copies loop data from adjacent faces */
+void BM_face_copy_shared(BMesh *bm, BMFace *f);
+
+/* copies attributes, e.g. customdata, header flags, etc, from one element
+ * to another of the same type.*/
+void BM_elem_attrs_copy(BMesh *source_mesh, BMesh *target_mesh, const 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_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e);
+
+/* generic, flexible join faces function; note that most everything uses
+ * this, including BM_faces_join_pair */
+BMFace *BM_faces_join(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.*/
+BMFace *BM_face_split(BMesh *bm, BMFace *f,
+ BMVert *v1, BMVert *v2,
+ struct BMLoop **nl, BMEdge *example);
+
+/* these 2 functions are very similar */
+BMEdge* BM_vert_collapse_faces(BMesh *bm, BMEdge *ke, BMVert *kv, float fac, const int join_faces);
+BMEdge* BM_vert_collapse_edges(BMesh *bm, BMEdge *ke, BMVert *kv);
+
+
+/* splits an edge. ne is set to the new edge created. */
+BMVert *BM_edge_split(BMesh *bm, BMVert *v, BMEdge *e, BMEdge **ne, float percent);
+
+/* split an edge multiple times evenly */
+BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts);
+
+/* connect two verts together, through a face they share. this function may
+ * be removed in the future. */
+BMEdge *BM_verts_connect(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_edge_rotate(BMesh *bm, BMEdge *e, int ccw);
+
+/* Rip a single face from a vertex fan */
+BMVert *BM_vert_rip(BMesh *bm, BMFace *sf, BMVert *sv);
+
+/*updates a face normal*/
+void BM_face_normal_update(BMesh *bm, BMFace *f);
+void BM_face_normal_update_vcos(BMesh *bm, BMFace *f, float no[3], float (*vertexCos)[3]);
+
+/*updates face and vertex normals incident on an edge*/
+void BM_edge_normals_update(BMesh *bm, BMEdge *e);
+
+/*update a vert normal (but not the faces incident on it)*/
+void BM_vert_normal_update(BMesh *bm, BMVert *v);
+void BM_vert_normal_update_all(BMesh *bm, BMVert *v);
+
+void BM_face_normal_flip(BMesh *bm, BMFace *f);
+
+/*dissolves all faces around a vert, and removes it.*/
+int BM_disk_dissolve(BMesh *bm, BMVert *v);
+
+/* dissolves vert, in more situations then BM_disk_dissolve
+ * (e.g. if the vert is part of a wire edge, etc).*/
+int BM_vert_dissolve(BMesh *bm, BMVert *v);
+
+/* Projects co onto face f, and returns true if it is inside
+ * the face bounds. Note that this uses a best-axis projection
+ * test, instead of projecting co directly into f's orientation
+ * space, so there might be accuracy issues.*/
+int BM_face_point_inside_test(BMesh *bm, BMFace *f, const float co[3]);
+
+/* Interpolation */
+
+/* projects target onto source for customdata interpolation. note: only
+ * does loop customdata. multires is handled. */
+void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source);
+
+/* projects a single loop, target, onto source for customdata interpolation. multires is handled.
+ * if do_vertex is true, target's vert data will also get interpolated.*/
+void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source,
+ int do_vertex, int do_multires);
+
+/* smoothes boundaries between multires grids, including some borders in adjacent faces */
+void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f);
+
+/* project the multires grid in target onto source's set of multires grids */
+void BM_loop_interp_multires(BMesh *bm, BMLoop *target, BMFace *source);
+void BM_vert_interp_from_face(BMesh *bm, BMVert *v, BMFace *source);
+
+void BM_data_interp_from_verts(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, const float fac);
+void BM_data_interp_face_vert_edge(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, struct BMEdge *e1, const float fac);
+void BM_data_layer_add(BMesh *em, CustomData *data, int type);
+void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name);
+void BM_data_layer_free(BMesh *em, CustomData *data, int type);
+void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n);
+float BM_elem_float_data_get(struct CustomData *cd, void *element, int type);
+void BM_elem_float_data_set(struct CustomData *cd, void *element, int type, const float val);
+
+/* get the area of the face */
+float BM_face_area_calc(BMesh *bm, BMFace *f);
+/* computes the centroid of a face, using the center of the bounding box */
+void BM_face_center_bounds_calc(BMesh *bm, BMFace *f, float center[3]);
+/* computes the centroid of a face, using the mean average */
+void BM_face_center_mean_calc(BMesh *bm, BMFace *f, float center[3]);
+
+void BM_mesh_select_mode_flush(BMesh *bm);
+
+/* mode independant flushing up/down */
+void BM_mesh_deselect_flush(BMesh *bm);
+void BM_mesh_select_flush(BMesh *bm);
+
+/* flag conversion funcs */
+char BM_face_flag_from_mflag(const char mflag);
+char BM_edge_flag_from_mflag(const short mflag);
+char BM_vert_flag_from_mflag(const char mflag);
+/* reverse */
+char BM_face_flag_to_mflag(BMFace *f);
+short BM_edge_flag_to_mflag(BMEdge *e);
+char BM_vert_flag_to_mflag(BMVert *v);
+
+
+/* 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_loop_kill(BMesh *bm, BMLoop *l);
+void BM_face_kill(BMesh *bm, BMFace *f);
+void BM_edge_kill(BMesh *bm, BMEdge *e);
+void BM_vert_kill(BMesh *bm, BMVert *v);
+
+/* kills all edges associated with f, along with any other faces containing
+ * those edges*/
+void BM_face_edges_kill(BMesh *bm, BMFace *f);
+
+/* kills all verts associated with f, along with any other faces containing
+ * those vertices*/
+void BM_face_verts_kill(BMesh *bm, BMFace *f);
+
+/*clear all data in bm*/
+void BM_mesh_clear(BMesh *bm);
+
+void BM_mesh_elem_index_ensure(BMesh *bm, const char hflag);
+
+void BM_mesh_elem_index_validate(BMesh *bm, const char *location, const char *func,
+ const char *msg_a, const char *msg_b);
+
+BMVert *BM_vert_at_index(BMesh *bm, const int index);
+BMEdge *BM_edge_at_index(BMesh *bm, const int index);
+BMFace *BM_face_at_index(BMesh *bm, const int index);
+
+/*start/stop edit*/
+void bmesh_begin_edit(BMesh *bm, int flag);
+void bmesh_end_edit(BMesh *bm, int flag);
+
+
+#ifdef USE_BMESH_HOLES
+# define BM_FACE_FIRST_LOOP(p) (((BMLoopList *)((p)->loops.first))->first)
+#else
+# define BM_FACE_FIRST_LOOP(p) ((p)->l_first)
+#endif
+
+/* size to use for static arrays when dealing with NGons,
+ * alloc after this limit is reached.
+ * this value is rather arbitrary */
+#define BM_NGON_STACK_SIZE 32
+
+/* avoid inf loop, this value is arbtrary
+ * but should not error on valid cases */
+#define BM_LOOP_RADIAL_MAX 10000
+#define BM_NGON_MAX 100000
+
+/* include the rest of the API */
+#include "bmesh_marking.h"
+#include "bmesh_operator_api.h"
+#include "bmesh_operators.h"
+#include "bmesh_error.h"
+#include "bmesh_queries.h"
+#include "bmesh_iterators.h"
+#include "bmesh_walkers.h"
+#include "intern/bmesh_inline.c"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BMESH_H__ */
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
new file mode 100644
index 00000000000..3a62eaa2eeb
--- /dev/null
+++ b/source/blender/bmesh/bmesh_class.h
@@ -0,0 +1,190 @@
+/*
+ * ***** 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): Geoffrey Bantle, Levi Schooley, Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_CLASS_H__
+#define __BMESH_CLASS_H__
+
+/** \file blender/bmesh/bmesh_class.h
+ * \ingroup bmesh
+ */
+
+/* bmesh data structures */
+
+/* dissable holes for now, these are ifdef'd because they use more memory and cant be saved in DNA currently */
+// define USE_BMESH_HOLES
+
+struct BMesh;
+struct BMVert;
+struct BMEdge;
+struct BMLoop;
+struct BMFace;
+struct BMFlagLayer;
+struct BMLayerType;
+struct BMSubClassLayer;
+
+struct BLI_mempool;
+struct Object;
+
+/*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 */
+ int index; /* notes:
+ * - Use BM_elem_index_get/SetIndex macros for index
+ * - Unitialized to -1 so we can easily tell its not set.
+ * - Used for edge/vert/face, check BMesh.elem_index_dirty for valid index values,
+ * this is abused by various tools which set it dirty.
+ * - For loops this is used for sorting during tesselation. */
+
+ char htype; /* element geometric type (verts/edges/loops/faces) */
+ char hflag; /* this would be a CD layer, see below */
+} 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.*/
+
+typedef struct BMVert {
+ BMHeader head;
+ struct BMFlagLayer *oflags; /* keep after header, an array of flags, mostly used by the operator stack */
+
+ float co[3];
+ float no[3];
+ struct BMEdge *e;
+} BMVert;
+
+/* disk link structure, only used by edges */
+typedef struct BMDiskLink {
+ struct BMEdge *next, *prev;
+} BMDiskLink;
+
+typedef struct BMEdge {
+ BMHeader head;
+ struct BMFlagLayer *oflags; /* keep after header, an array of flags, mostly used by the operator stack */
+
+ struct BMVert *v1, *v2;
+ struct BMLoop *l;
+
+ /* disk cycle pointers */
+ BMDiskLink v1_disk_link, v2_disk_link;
+} BMEdge;
+
+typedef struct BMLoop {
+ BMHeader head;
+ /* notice no flags layer */
+
+ struct BMVert *v;
+ struct BMEdge *e;
+ struct BMFace *f;
+
+ struct BMLoop *radial_next, *radial_prev;
+
+ /* these were originally commented as private but are used all over the code */
+ /* can't use ListBase API, due to head */
+ struct BMLoop *next, *prev;
+} BMLoop;
+
+/* can cast BMFace/BMEdge/BMVert, but NOT BMLoop, since these dont have a flag layer */
+typedef struct BMElemF {
+ BMHeader head;
+ struct BMFlagLayer *oflags; /* keep after header, an array of flags, mostly used by the operator stack */
+} BMElemF;
+
+#ifdef USE_BMESH_HOLES
+/* eventually, this structure will be used for supporting holes in faces */
+typedef struct BMLoopList {
+ struct BMLoopList *next, *prev;
+ struct BMLoop *first, *last;
+} BMLoopList;
+#endif
+
+typedef struct BMFace {
+ BMHeader head;
+ struct BMFlagLayer *oflags; /* an array of flags, mostly used by the operator stack */
+
+ int len; /*includes all boundary loops*/
+#ifdef USE_BMESH_HOLES
+ int totbounds; /*total boundaries, is one plus the number of holes in the face*/
+ ListBase loops;
+#else
+ BMLoop *l_first;
+#endif
+ float no[3]; /*yes, we do store this here*/
+ short mat_nr;
+} BMFace;
+
+typedef struct BMFlagLayer {
+ short f, pflag; /* flags */
+} BMFlagLayer;
+
+typedef struct BMesh {
+ int totvert, totedge, totloop, totface;
+ int totvertsel, totedgesel, totfacesel;
+
+ /* flag index arrays as being dirty so we can check if they are clean and
+ * avoid looping over the entire vert/edge/face array in those cases.
+ * valid flags are - BM_VERT | BM_EDGE | BM_FACE.
+ * BM_LOOP isnt handled so far. */
+ char elem_index_dirty;
+
+ /*element pools*/
+ struct BLI_mempool *vpool, *epool, *lpool, *fpool;
+
+ /*operator api stuff*/
+ struct BLI_mempool *toolflagpool;
+ int stackdepth;
+ struct BMOperator *currentop;
+
+ CustomData vdata, edata, ldata, pdata;
+
+#ifdef USE_BMESH_HOLES
+ struct BLI_mempool *looplistpool;
+#endif
+
+ /* should be copy of scene select mode */
+ /* stored in BMEditMesh too, this is a bit confusing,
+ * make sure the're in sync!
+ * Only use when the edit mesh cant be accessed - campbell */
+ short selectmode;
+
+ /*ID of the shape key this bmesh came from*/
+ int shapenr;
+
+ int walkers, totflags;
+ ListBase selected, error_stack;
+
+ BMFace *act_face;
+
+ ListBase errorstack;
+ struct Object *ob; /* owner object */
+
+ int opflag; /* current operator flag */
+} BMesh;
+
+#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..26f499afd22
--- /dev/null
+++ b/source/blender/bmesh/bmesh_error.h
@@ -0,0 +1,72 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_ERROR_H__
+#define __BMESH_ERROR_H__
+
+/** \file blender/bmesh/bmesh_error.h
+ * \ingroup bmesh
+ */
+
+/*----------- 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_error_raise(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_error_get(BMesh *bm, const char **msg, BMOperator **op);
+int BMO_error_occurred(BMesh *bm);
+
+/* same as geterror, only pops the error off the stack as well */
+int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op);
+void BMO_error_clear(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_error_catch_op(BMesh *bm, BMOperator *catchop, int errorcode, char **msg);
+#endif
+
+#define BM_ELEM_INDEX_VALIDATE(_bm, _msg_a, _msg_b) \
+ BM_mesh_elem_index_validate(_bm, __FILE__ ":" STRINGIFY(__LINE__), __func__, _msg_a, _msg_b)
+
+/*------ 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
+#define BMERR_MESH_ERROR 10
+
+#endif /* __BMESH_ERROR_H__ */
diff --git a/source/blender/bmesh/bmesh_iterators.h b/source/blender/bmesh/bmesh_iterators.h
new file mode 100644
index 00000000000..51df9460e8b
--- /dev/null
+++ b/source/blender/bmesh/bmesh_iterators.h
@@ -0,0 +1,136 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_ITERATORS_H__
+#define __BMESH_ITERATORS_H__
+
+/** \file blender/bmesh/bmesh_iterators.h
+ * \ingroup bmesh
+ */
+
+/*
+ * 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.
+ *
+*/
+
+#include "BLI_mempool.h"
+
+/* Defines for passing to BM_iter_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, itype, data) \
+ ele = BM_iter_new(iter, bm, itype, data); \
+ for ( ; ele; ele=BM_iter_step(iter))
+
+#define BM_ITER_INDEX(ele, iter, bm, itype, data, indexvar) \
+ ele = BM_iter_new(iter, bm, itype, data); \
+ for (indexvar=0; ele; indexvar++, ele=BM_iter_step(iter))
+
+/*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 count;
+ char itype;
+} BMIter;
+
+void *BM_iter_at_index(struct BMesh *bm, const char htype, void *data, int index);
+int BM_iter_as_array(struct BMesh *bm, const char htype, void *data, void **array, const int len);
+
+/* private for bmesh_iterators_inline.c */
+void bmiter__vert_of_mesh_begin(struct BMIter *iter);
+void *bmiter__vert_of_mesh_step(struct BMIter *iter);
+void bmiter__edge_of_mesh_begin(struct BMIter *iter);
+void *bmiter__edge_of_mesh_step(struct BMIter *iter);
+void bmiter__face_of_mesh_begin(struct BMIter *iter);
+void *bmiter__face_of_mesh_step(struct BMIter *iter);
+void bmiter__edge_of_vert_begin(struct BMIter *iter);
+void *bmiter__edge_of_vert_step(struct BMIter *iter);
+void bmiter__face_of_vert_begin(struct BMIter *iter);
+void *bmiter__face_of_vert_step(struct BMIter *iter);
+void bmiter__loop_of_vert_begin(struct BMIter *iter);
+void *bmiter__loop_of_vert_step(struct BMIter *iter);
+void bmiter__loops_of_edge_begin(struct BMIter *iter);
+void *bmiter__loops_of_edge_step(struct BMIter *iter);
+void bmiter__loops_of_loop_begin(struct BMIter *iter);
+void *bmiter__loops_of_loop_step(struct BMIter *iter);
+void bmiter__face_of_edge_begin(struct BMIter *iter);
+void *bmiter__face_of_edge_step(struct BMIter *iter);
+void bmiter__vert_of_face_begin(struct BMIter *iter);
+void *bmiter__vert_of_face_step(struct BMIter *iter);
+void bmiter__edge_of_face_begin(struct BMIter *iter);
+void *bmiter__edge_of_face_step(struct BMIter *iter);
+void bmiter__loop_of_face_begin(struct BMIter *iter);
+void *bmiter__loop_of_face_step(struct BMIter *iter);
+
+#include "intern/bmesh_iterators_inline.c"
+
+#endif /* __BMESH_ITERATORS_H__ */
diff --git a/source/blender/bmesh/bmesh_marking.h b/source/blender/bmesh/bmesh_marking.h
new file mode 100644
index 00000000000..9b45ac10394
--- /dev/null
+++ b/source/blender/bmesh/bmesh_marking.h
@@ -0,0 +1,75 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_MARKING_H__
+#define __BMESH_MARKING_H__
+
+/** \file blender/bmesh/bmesh_marking.h
+ * \ingroup bmesh
+ */
+
+typedef struct BMEditSelection
+{
+ struct BMEditSelection *next, *prev;
+ void *data;
+ char htype;
+} BMEditSelection;
+
+/* geometry hiding code */
+void BM_elem_hide_set(BMesh *bm, void *element, int hide);
+void BM_vert_hide_set(BMesh *bm, BMVert *v, int hide);
+void BM_edge_hide_set(BMesh *bm, BMEdge *e, int hide);
+void BM_face_hide_set(BMesh *bm, BMFace *f, int hide);
+
+/* Selection code */
+void BM_elem_select_set(struct BMesh *bm, void *element, int select);
+
+/* use BM_elem_flag_test(ele, BM_ELEM_SELECT) to test selection */
+
+void BM_mesh_elem_flag_enable_all(BMesh *bm, const char htype, const char hflag);
+void BM_mesh_elem_flag_disable_all(BMesh *bm, const char htype, const char hflag);
+
+/* individual element select functions, BM_elem_select_set is a shortcut for these
+ * that automatically detects which one to use*/
+void BM_vert_select_set(struct BMesh *bm, struct BMVert *v, int select);
+void BM_edge_select_set(struct BMesh *bm, struct BMEdge *e, int select);
+void BM_face_select_set(struct BMesh *bm, struct BMFace *f, int select);
+
+void BM_select_mode_set(struct BMesh *bm, int selectmode);
+
+/* counts number of elements with flag set */
+int BM_mesh_count_flag(struct BMesh *bm, const char htype, const char hflag, int respecthide);
+
+/* edit selection stuff */
+void BM_active_face_set(BMesh *em, BMFace *f);
+BMFace *BM_active_face_get(BMesh *bm, int sloppy);
+void BM_editselection_center(BMesh *bm, float r_center[3], BMEditSelection *ese);
+void BM_editselection_normal(float r_normal[3], BMEditSelection *ese);
+void BM_editselection_plane(BMesh *bm, float r_plane[3], BMEditSelection *ese);
+
+int BM_select_history_check(BMesh *bm, void *data);
+void BM_select_history_remove(BMesh *bm, void *data);
+void BM_select_history_store(BMesh *bm, void *data);
+void BM_select_history_validate(BMesh *bm);
+void BM_select_history_clear(BMesh *em);
+
+#endif /* __BMESH_MARKING_H__ */
diff --git a/source/blender/bmesh/bmesh_operator_api.h b/source/blender/bmesh/bmesh_operator_api.h
new file mode 100644
index 00000000000..7bbb579685d
--- /dev/null
+++ b/source/blender/bmesh/bmesh_operator_api.h
@@ -0,0 +1,555 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_OPERATOR_API_H__
+#define __BMESH_OPERATOR_API_H__
+
+/** \file blender/bmesh/bmesh_operator_api.h
+ * \ingroup bmesh
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_memarena.h"
+#include "BLI_ghash.h"
+
+#include "BKE_utildefines.h"
+
+#include <stdarg.h>
+#include <string.h> /* for memcpy */
+
+/*
+ * 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_op_callf or BMO_op_initf). 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 BMO_OP_SLOT_SENTINEL 0
+#define BMO_OP_SLOT_INT 1
+#define BMO_OP_SLOT_FLT 2
+#define BMO_OP_SLOT_PNT 3
+#define BMO_OP_SLOT_MAT 4
+#define BMO_OP_SLOT_VEC 7
+
+/* after BMO_OP_SLOT_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 BMO_OP_SLOT_ELEMENT_BUF 8
+#define BMO_OP_SLOT_MAPPING 9
+/* #define BMO_OP_SLOT_TOTAL_TYPES 10 */ /* not used yet */
+
+/* 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 BMO_OP_MAX_SLOTS 16 /* way more than probably needed */
+
+#ifdef slots
+#undef slots
+#endif
+
+typedef struct BMOperator {
+ int type;
+ int slottype;
+ int needflag;
+ int flag;
+ struct BMOpSlot slots[BMO_OP_MAX_SLOTS];
+ void (*exec)(struct BMesh *bm, struct BMOperator *op);
+ MemArena *arena;
+} BMOperator;
+
+#define MAX_SLOTNAME 32
+
+typedef struct BMOSlotType {
+ int type;
+ char name[MAX_SLOTNAME];
+} BMOSlotType;
+
+typedef struct BMOpDefine {
+ const char *name;
+ BMOSlotType slottypes[BMO_OP_MAX_SLOTS];
+ void (*exec)(BMesh *bm, BMOperator *op);
+ int flag;
+} BMOpDefine;
+
+/* BMOpDefine->flag */
+#define BMO_OP_FLAG_UNTAN_MULTIRES 1 /*switch from multires tangent space to absolute coordinates*/
+
+/* ensures consistent normals before operator execution,
+ * restoring the original ones windings/normals afterwards.
+ * keep in mind, this won't work if the input mesh isn't
+ * manifold.*/
+#define BMO_OP_FLAG_RATIONALIZE_NORMALS 2
+
+/*------------- Operator API --------------*/
+
+/* data types that use pointers (arrays, etc) should never
+ * have it set directly. and never use BMO_slot_ptr_set to
+ * pass in a list of edges or any arrays, really.*/
+
+void BMO_op_init(struct BMesh *bm, struct BMOperator *op, const char *opname);
+
+/* executes an operator, pushing and popping a new tool flag
+ * layer as appropriate.*/
+void BMO_op_exec(struct BMesh *bm, struct BMOperator *op);
+
+/* finishes an operator (though note the operator's tool flag is removed
+ * after it finishes executing in BMO_op_exec).*/
+void BMO_op_finish(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_elem_flag_test(bm, element, oflag) ((element)->oflags[bm->stackdepth-1].f & (oflag))
+#define BMO_elem_flag_enable(bm, element, oflag) ((element)->oflags[bm->stackdepth-1].f |= (oflag))
+#define BMO_elem_flag_disable(bm, element, oflag) ((element)->oflags[bm->stackdepth-1].f &= ~(oflag))
+#define BMO_elem_flag_toggle(bm, element, oflag) ((element)->oflags[bm->stackdepth-1].f ^= (oflag))
+
+/* profiling showed a significant amount of time spent in BMO_elem_flag_test */
+#if 0
+void BMO_elem_flag_enable(struct BMesh *bm, void *element, const short oflag);
+void BMO_elem_flag_disable(struct BMesh *bm, void *element, const short oflag);
+int BMO_elem_flag_test(struct BMesh *bm, void *element, const short oflag);
+#endif
+
+/* count the number of elements with a specific flag.
+ * type can be a bitmask of BM_FACE, BM_EDGE, or BM_FACE. */
+int BMO_mesh_flag_count(struct BMesh *bm, const short oflag, const char htype);
+
+/*---------formatted operator initialization/execution-----------*/
+/*
+ * this system is used to execute or initialize an operator,
+ * using a formatted-string system.
+ *
+ * for example, BMO_op_callf(bm, "del geom=%hf context=%d", BM_ELEM_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_op_callf(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_op_exec and BMO_op_finish) yourself. */
+int BMO_op_initf(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_op_vinitf(BMesh *bm, BMOperator *op, const char *fmt, va_list vlist);
+
+/* test whether a named slot exists */
+int BMO_slot_exists(struct BMOperator *op, const char *slotname);
+
+/* get a pointer to a slot. this may be removed layer on from the public API. */
+BMOpSlot *BMO_slot_get(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_slot_copy(struct BMOperator *source_op, struct BMOperator *dest_op,
+ const char *src, const char *dst);
+
+/* remove tool flagged elements */
+void BMO_remove_tagged_faces(struct BMesh *bm, const short oflag);
+void BMO_remove_tagged_edges(struct BMesh *bm, const short oflag);
+void BMO_remove_tagged_verts(struct BMesh *bm, const short oflag);
+
+/* take care, uses operator flag DEL_WIREVERT */
+void BMO_remove_tagged_context(BMesh *bm, const short oflag, const int type);
+
+/* del "context" slot values, used for operator too */
+enum {
+ DEL_VERTS = 1,
+ DEL_EDGES,
+ DEL_ONLYFACES,
+ DEL_EDGESFACES,
+ DEL_FACES,
+ DEL_ALL ,
+ DEL_ONLYTAGGED
+};
+
+void BMO_op_flag_enable(struct BMesh *bm, struct BMOperator *op, const int op_flag);
+void BMO_op_flag_disable(struct BMesh *bm, struct BMOperator *op, const int op_flag);
+
+void BMO_slot_float_set(struct BMOperator *op, const char *slotname, const float f);
+float BMO_slot_float_get(BMOperator *op, const char *slotname);
+void BMO_slot_int_set(struct BMOperator *op, const char *slotname, const int i);
+int BMO_slot_int_get(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_slot_ptr_set(struct BMOperator *op, const char *slotname, void *p);
+void *BMO_slot_ptr_get(BMOperator *op, const char *slotname);
+void BMO_slot_vec_set(struct BMOperator *op, const char *slotname, const float vec[3]);
+void BMO_slot_vec_get(BMOperator *op, const char *slotname, float r_vec[3]);
+
+/* 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_slot_mat_set(struct BMOperator *op, const char *slotname, const float *mat, int size);
+void BMO_slot_mat4_get(struct BMOperator *op, const char *slotname, float r_mat[4][4]);
+void BMO_slot_mat3_set(struct BMOperator *op, const char *slotname, float r_mat[3][3]);
+
+void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *op, const char htype, const short oflag);
+
+/* puts every element of type type (which is a bitmask) with tool flag flag,
+ * into a slot. */
+void BMO_slot_from_flag(struct BMesh *bm, struct BMOperator *op, const char *slotname,
+ const short oflag, const char htype);
+
+/* tool-flags all elements inside an element slot array with flag flag. */
+void BMO_slot_buffer_flag_enable(struct BMesh *bm, struct BMOperator *op, const char *slotname,
+ const short oflag, const char htype);
+/* clears tool-flag flag from all elements inside a slot array. */
+void BMO_slot_buffer_flag_disable(struct BMesh *bm, struct BMOperator *op, const char *slotname,
+ const short oflag, const char htype);
+
+/* tool-flags all elements inside an element slot array with flag flag. */
+void BMO_slot_buffer_hflag_enable(struct BMesh *bm, struct BMOperator *op, const char *slotname,
+ const char hflag, const char htype);
+/* clears tool-flag flag from all elements inside a slot array. */
+void BMO_slot_buffer_hflag_disable(struct BMesh *bm, struct BMOperator *op, const char *slotname,
+ const char hflag, const char htype);
+
+/* 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_ELEM_HIDDEN set).*/
+void BMO_slot_from_hflag(struct BMesh *bm, struct BMOperator *op, const char *slotname,
+ const char hflag, const char htype);
+
+/* counts number of elements inside a slot array. */
+int BMO_slot_buf_count(struct BMesh *bm, struct BMOperator *op, const char *slotname);
+int BMO_slot_map_count(struct BMesh *bm, struct BMOperator *op, const char *slotname);
+
+/* Counts the number of edges with tool flag toolflag around
+ */
+int BMO_vert_edge_flags_count(BMesh *bm, BMVert *v, const short oflag);
+
+/* inserts a key/value mapping into a mapping slot. note that it copies the
+ * value, it doesn't store a reference to it. */
+
+#if 0
+
+BM_INLINE void BMO_slot_map_insert(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_slot_map_float_insert(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_slot_map_contains(BMesh *bm, BMOperator *op, const char *slotname, void *element);
+
+/* returns a point to the value of a specific key. */
+BM_INLINE void *BMO_slot_map_data_get(BMesh *bm, BMOperator *op, const char *slotname, void *element);
+
+/* returns the float part of a key/float pair. */
+BM_INLINE float BMO_slot_map_float_get(BMesh *bm, BMOperator *op, const char *slotname, void *element);
+
+#endif
+
+/* flags all elements in a mapping. note that the mapping must only have
+ * bmesh elements in it.*/
+void BMO_slot_map_to_flag(struct BMesh *bm, struct BMOperator *op,
+ const char *slotname, const short oflag);
+
+/* pointer versoins of BMO_slot_map_float_get and BMO_slot_map_float_insert.
+ *
+ * do NOT use these for non-operator-api-allocated memory! instead
+ * use BMO_slot_map_data_get and BMO_slot_map_insert, which copies the data. */
+
+#if 0
+BM_INLINE void BMO_slot_map_ptr_insert(BMesh *bm, BMOperator *op, const char *slotname, void *key, void *val);
+BM_INLINE void *BMO_slot_map_ptr_get(BMesh *bm, BMOperator *op, const char *slotname, void *key);
+#endif
+
+/* 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_iter_new(&oiter, bm, some_operator, "slotname", BM_FACE);
+ * for (; f; f=BMO_iter_step(&oiter)) {
+ * /do something with the face
+ * }
+ *
+ * another example, iterating over a mapping:
+ * BMOIter oiter;
+ * void *key;
+ * void *val;
+ *
+ * key = BMO_iter_new(&oiter, bm, some_operator, "slotname", 0);
+ * for (; key; key=BMO_iter_step(&oiter)) {
+ * val = BMO_iter_map_value(&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_iter_map_value(&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;
+ char restrictmask; /* bitwise '&' with BMHeader.htype */
+} BMOIter;
+
+void *BMO_slot_elem_first(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_iter_new(BMOIter *iter, BMesh *bm, BMOperator *op,
+ const char *slotname, const char restrictmask);
+void *BMO_iter_step(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_iter_map_value(BMOIter *iter);
+
+/* use this for pointer mappings */
+void *BMO_iter_map_value_p(BMOIter *iter);
+
+/* use this for float mappings */
+float BMO_iter_map_value_f(BMOIter *iter);
+
+#define BMO_ITER(ele, iter, bm, op, slotname, restrict) \
+ ele = BMO_iter_new(iter, bm, op, slotname, restrict); \
+ for ( ; ele; ele=BMO_iter_step(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 BMOElemMapping {
+ BMHeader *element;
+ int len;
+} BMOElemMapping;
+
+extern const int BMO_OPSLOT_TYPEINFO[];
+
+BM_INLINE void BMO_slot_map_insert(BMesh *UNUSED(bm), BMOperator *op, const char *slotname,
+ void *element, void *data, int len)
+{
+ BMOElemMapping *mapping;
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+
+ /*sanity check*/
+ if (slot->slottype != BMO_OP_SLOT_MAPPING) {
+ return;
+ }
+
+ mapping = (BMOElemMapping *) 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_slot_map_int_insert(BMesh *bm, BMOperator *op, const char *slotname,
+ void *element, int val)
+{
+ BMO_slot_map_insert(bm, op, slotname, element, &val, sizeof(int));
+}
+
+BM_INLINE void BMO_slot_map_float_insert(BMesh *bm, BMOperator *op, const char *slotname,
+ void *element, float val)
+{
+ BMO_slot_map_insert(bm, op, slotname, element, &val, sizeof(float));
+}
+
+BM_INLINE void BMO_slot_map_ptr_insert(BMesh *bm, BMOperator *op, const char *slotname,
+ void *element, void *val)
+{
+ BMO_slot_map_insert(bm, op, slotname, element, &val, sizeof(void*));
+}
+
+BM_INLINE int BMO_slot_map_contains(BMesh *UNUSED(bm), BMOperator *op, const char *slotname, void *element)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+
+ /*sanity check*/
+ if (slot->slottype != BMO_OP_SLOT_MAPPING) return 0;
+ if (!slot->data.ghash) return 0;
+
+ return BLI_ghash_haskey(slot->data.ghash, element);
+}
+
+BM_INLINE void *BMO_slot_map_data_get(BMesh *UNUSED(bm), BMOperator *op, const char *slotname,
+ void *element)
+{
+ BMOElemMapping *mapping;
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+
+ /*sanity check*/
+ if (slot->slottype != BMO_OP_SLOT_MAPPING) return NULL;
+ if (!slot->data.ghash) return NULL;
+
+ mapping = (BMOElemMapping *)BLI_ghash_lookup(slot->data.ghash, element);
+
+ if (!mapping) return NULL;
+
+ return mapping + 1;
+}
+
+BM_INLINE float BMO_slot_map_float_get(BMesh *bm, BMOperator *op, const char *slotname,
+ void *element)
+{
+ float *val = (float*) BMO_slot_map_data_get(bm, op, slotname, element);
+ if (val) return *val;
+
+ return 0.0f;
+}
+
+BM_INLINE int BMO_slot_map_int_get(BMesh *bm, BMOperator *op, const char *slotname,
+ void *element)
+{
+ int *val = (int*) BMO_slot_map_data_get(bm, op, slotname, element);
+ if (val) return *val;
+
+ return 0;
+}
+
+BM_INLINE void *BMO_slot_map_ptr_get(BMesh *bm, BMOperator *op, const char *slotname,
+ void *element)
+{
+ void **val = (void**) BMO_slot_map_data_get(bm, op, slotname, element);
+ if (val) return *val;
+
+ return NULL;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BMESH_OPERATOR_API_H__ */
diff --git a/source/blender/bmesh/bmesh_operators.h b/source/blender/bmesh/bmesh_operators.h
new file mode 100644
index 00000000000..0a84246091b
--- /dev/null
+++ b/source/blender/bmesh/bmesh_operators.h
@@ -0,0 +1,107 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_OPERATORS_H__
+#define __BMESH_OPERATORS_H__
+
+/** \file blender/bmesh/bmesh_operators.h
+ * \ingroup bmesh
+ */
+
+/*see comments in intern/bmesh_opdefines.c for documentation of specific operators*/
+
+/*--------defines/enumerations for specific operators-------*/
+
+/*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,
+ SIMFACE_FREESTYLE
+};
+
+/* similar edge selection slot values */
+enum {
+ SIMEDGE_LENGTH = 101,
+ SIMEDGE_DIR,
+ SIMEDGE_FACE,
+ SIMEDGE_FACE_ANGLE,
+ SIMEDGE_CREASE,
+ SIMEDGE_SEAM,
+ SIMEDGE_SHARP,
+ SIMEDGE_FREESTYLE
+};
+
+/* 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;
+
+#if 0
+void BMO_dupe_from_flag(struct BMesh *bm, int etypeflag, const char hflag);
+#endif
+void BM_mesh_esubdivideflag(struct Object *obedit, BMesh *bm, int flag, float smooth,
+ float fractal, int beauty, int numcuts, int seltype,
+ int cornertype, int singleedge, int gridfill, int seed);
+
+#endif /* __BMESH_OPERATORS_H__ */
diff --git a/source/blender/bmesh/bmesh_queries.h b/source/blender/bmesh/bmesh_queries.h
new file mode 100644
index 00000000000..1ae469eb663
--- /dev/null
+++ b/source/blender/bmesh/bmesh_queries.h
@@ -0,0 +1,123 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_QUERIES_H__
+#define __BMESH_QUERIES_H__
+
+/** \file blender/bmesh/bmesh_queries.h
+ * \ingroup bmesh
+ */
+
+#include <stdio.h>
+
+/* Queries */
+
+/* counts number of elements of type type are in the mesh. */
+int BM_mesh_elem_count(struct BMesh *bm, const char htype);
+
+/*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);
+
+int BM_verts_in_edge(struct BMVert *v1, struct BMVert *v2, struct BMEdge *e);
+
+/*get opposing vert from v in edge e.*/
+struct BMVert *BM_edge_other_vert(struct BMEdge *e, struct BMVert *v);
+
+/*finds other loop that shares v with e's loop in f.*/
+struct BMLoop *BM_face_other_loop(BMEdge *e, BMFace *f, BMVert *v);
+
+/*returns the edge existing between v1 and v2, or NULL if there isn't one.*/
+struct BMEdge *BM_edge_exists(struct BMVert *v1, struct BMVert *v2);
+
+
+/*returns number of edges aroudn a vert*/
+int BM_vert_edge_count(struct BMVert *v);
+
+/*returns number of faces around an edge*/
+int BM_edge_face_count(struct BMEdge *e);
+
+/*returns number of faces around a vert.*/
+int BM_vert_face_count(struct BMVert *v);
+
+
+/*returns true if v is a wire vert*/
+int BM_vert_is_wire(struct BMesh *bm, struct BMVert *v);
+
+/*returns true if e is a wire edge*/
+int BM_edge_is_wire(struct BMesh *bm, struct BMEdge *e);
+
+/* returns FALSE 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_vert_is_manifold(struct BMesh *bm, struct BMVert *v);
+
+/* returns FALSE if e is shared by more then two faces. */
+int BM_edge_is_manifold(struct BMesh *bm, struct BMEdge *e);
+
+/* returns true if e is a boundary edge, e.g. has only 1 face bordering it. */
+int BM_edge_is_boundry(struct BMEdge *e);
+
+
+/* returns angle of two faces surrounding an edge. note there must be
+ * exactly two faces sharing the edge.*/
+float BM_edge_face_angle(struct BMesh *bm, struct BMEdge *e);
+
+/* returns angle of two faces surrounding edges. note there must be
+ * exactly two edges sharing the vertex.*/
+float BM_vert_edge_angle(struct BMesh *bm, struct BMVert *v);
+
+/* checks overlapping of existing faces with the verts in varr. */
+int BM_face_exists_overlap(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_share_edges(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);
+
+/* returns bool 1/0 if the edges share a vertex */
+int BM_edge_share_vert(struct BMEdge *e1, struct BMEdge *e2);
+
+/* edge verts in winding order from face */
+void BM_edge_ordered_verts(struct BMEdge *edge, struct BMVert **r_v1, struct BMVert **r_v2);
+
+/* checks if a face is valid in the data structure */
+int BM_face_validate(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_face_legal_splits(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len);
+
+#endif /* __BMESH_QUERIES_H__ */
diff --git a/source/blender/bmesh/bmesh_walkers.h b/source/blender/bmesh/bmesh_walkers.h
new file mode 100644
index 00000000000..a9515dbd3e7
--- /dev/null
+++ b/source/blender/bmesh/bmesh_walkers.h
@@ -0,0 +1,139 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_WALKERS_H__
+#define __BMESH_WALKERS_H__
+
+/** \file blender/bmesh/bmesh_walkers.h
+ * \ingroup bmesh
+ */
+
+#include "BLI_ghash.h"
+
+/*
+ NOTE: do NOT modify topology while walking a mesh!
+*/
+
+typedef enum {
+ BMW_DEPTH_FIRST,
+ BMW_BREADTH_FIRST
+} BMWOrder;
+
+/*Walkers*/
+typedef struct BMWalker {
+ void (*begin) (struct BMWalker *walker, void *start);
+ void *(*step) (struct BMWalker *walker);
+ void *(*yield)(struct BMWalker *walker);
+ int structsize;
+ BMWOrder order;
+ int valid_mask;
+
+ /* runtime */
+ int layer;
+
+ BMesh *bm;
+ BLI_mempool *worklist;
+ ListBase states;
+
+ short mask_vert;
+ short mask_edge;
+ short mask_loop;
+ short mask_face;
+
+ GHash *visithash;
+ int depth;
+} BMWalker;
+
+/* define to make BMW_init more clear */
+#define BMW_MASK_NOP 0
+
+/* 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,
+ short mask_vert, short mask_edge, short mask_loop, short mask_face,
+ int layer);
+void *BMW_begin(BMWalker *walker, void *start);
+void *BMW_step(struct BMWalker *walker);
+void BMW_end(struct BMWalker *walker);
+int BMW_current_depth(BMWalker *walker);
+
+/*these are used by custom walkers*/
+void *BMW_current_state(BMWalker *walker);
+void *BMW_state_add(BMWalker *walker);
+void BMW_state_remove(BMWalker *walker);
+void *BMW_walk(BMWalker *walker);
+void BMW_reset(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,
+ /* walk from a vertex to all connected vertices. */
+ BMW_CONNECTED_VERTEX,
+ /* end of array index enum vals */
+
+ /* do not intitialze function pointers and struct size in BMW_init */
+ BMW_CUSTOM,
+ BMW_MAXWALKERS
+};
+
+/* use with BMW_init, so as not to confuse with restrict flags */
+#define BMW_NIL_LAY 0
+
+#endif /* __BMESH_WALKERS_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
new file mode 100644
index 00000000000..ca16e568bb6
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -0,0 +1,777 @@
+/*
+ * ***** 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): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_construct.c
+ * \ingroup bmesh
+ *
+ * BM construction functions.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_array.h"
+#include "BLI_math.h"
+
+#include "BKE_customdata.h"
+
+#include "DNA_meshdata_types.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#define SELECT 1
+
+/* prototypes */
+static void bm_loop_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
+ const BMLoop *source_loop, BMLoop *target_loop);
+
+/*
+ * 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_face_create_quad_tri(BMesh *bm,
+ BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
+ const BMFace *example, const int nodouble)
+{
+ BMVert *vtar[4] = {v1, v2, v3, v4};
+ return BM_face_create_quad_tri_v(bm, vtar, v4 ? 4 : 3, example, nodouble);
+}
+
+/* remove the edge array bits from this. Its not really needed? */
+BMFace *BM_face_create_quad_tri_v(BMesh *bm, BMVert **verts, int len, const BMFace *example, const int nodouble)
+{
+ BMEdge *edar[4] = {NULL};
+ BMFace *f = NULL;
+ int overlap = 0;
+
+ edar[0] = BM_edge_exists(verts[0], verts[1]);
+ edar[1] = BM_edge_exists(verts[1], verts[2]);
+ if (len == 4) {
+ edar[2] = BM_edge_exists(verts[2], verts[3]);
+ edar[3] = BM_edge_exists(verts[3], verts[0]);
+ }
+ else {
+ edar[2] = BM_edge_exists(verts[2], verts[0]);
+ }
+
+ if (nodouble) {
+ /* check if face exists or overlaps */
+ if (len == 4) {
+ overlap = BM_face_exists_overlap(bm, verts, len, &f);
+ }
+ else {
+ overlap = BM_face_exists_overlap(bm, verts, len, &f);
+ }
+ }
+
+ /* make new face */
+ if ((!f) && (!overlap)) {
+ if (!edar[0]) edar[0] = BM_edge_create(bm, verts[0], verts[1], NULL, FALSE);
+ if (!edar[1]) edar[1] = BM_edge_create(bm, verts[1], verts[2], NULL, FALSE);
+ if (len == 4) {
+ if (!edar[2]) edar[2] = BM_edge_create(bm, verts[2], verts[3], NULL, FALSE);
+ if (!edar[3]) edar[3] = BM_edge_create(bm, verts[3], verts[0], NULL, FALSE);
+ }
+ else {
+ if (!edar[2]) edar[2] = BM_edge_create(bm, verts[2], verts[0], NULL, FALSE);
+ }
+
+ f = BM_face_create(bm, verts, edar, len, FALSE);
+
+ if (example && f) {
+ BM_elem_attrs_copy(bm, bm, example, f);
+ }
+ }
+
+ return f;
+}
+
+
+/* copies face data from shared adjacent faces */
+void BM_face_copy_shared(BMesh *bm, BMFace *f)
+{
+ BMIter iter;
+ BMLoop *l, *l2;
+
+ if (!f) return;
+
+ l = BM_iter_new(&iter, bm, BM_LOOPS_OF_FACE, f);
+ for ( ; l; l = BM_iter_step(&iter)) {
+ l2 = l->radial_next;
+
+ if (l2 && l2 != l) {
+ if (l2->v == l->v) {
+ bm_loop_attrs_copy(bm, bm, l2, l);
+ }
+ else {
+ l2 = l2->next;
+ bm_loop_attrs_copy(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
+ *
+ * Note that while this function will work fine when the edges
+ * are already sorted, if the edges are always going to be sorted,
+ * BM_face_create should be considered over this function as it
+ * avoids some unnecessary work.
+ */
+BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, int nodouble)
+{
+ BMEdge **edges2 = NULL;
+ BLI_array_staticdeclare(edges2, BM_NGON_STACK_SIZE);
+ BMVert **verts = NULL, *v;
+ BLI_array_staticdeclare(verts, BM_NGON_STACK_SIZE);
+ BMFace *f = NULL;
+ BMEdge *e;
+ BMVert *ev1, *ev2;
+ int 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_face_create_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++) {
+ BM_ELEM_API_FLAG_ENABLE(edges[i], _FLAG_MF);
+ }
+
+ ev1 = edges[0]->v1;
+ ev2 = edges[0]->v2;
+
+ if (v1 == ev2) {
+ /* Swapping here improves performance and consistency of face
+ * structure in the special case that the edges are already in
+ * the correct order and winding */
+ SWAP(BMVert *, ev1, ev2);
+ }
+
+ BLI_array_append(verts, ev1);
+ v = ev2;
+ 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 && BM_ELEM_API_FLAG_TEST(e2, _FLAG_MF)) {
+ v = BM_edge_other_vert(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 = FALSE;
+ 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 = TRUE;
+ break;
+ }
+ }
+
+ v1found = TRUE;
+ }
+
+ if ((v1found == FALSE) && BM_vert_in_edge(edges2[i], v2)) {
+ reverse = TRUE;
+ 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_exists(verts[i], verts[(i + 1) % len]);
+ if (!edges2[i]) {
+ goto err;
+ }
+ }
+
+ f = BM_face_create(bm, verts, edges2, len, nodouble);
+
+ /* clean up flags */
+ for (i = 0; i < len; i++) {
+ BM_ELEM_API_FLAG_DISABLE(edges2[i], _FLAG_MF);
+ }
+
+ BLI_array_free(verts);
+ BLI_array_free(edges2);
+
+ return f;
+
+err:
+ for (i = 0; i < len; i++) {
+ BM_ELEM_API_FLAG_DISABLE(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 BMO_remove_tagged_faces(BMesh *bm, const short oflag)
+{
+ BMFace *f;
+ BMIter iter;
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (BMO_elem_flag_test(bm, f, oflag)) {
+ BM_face_kill(bm, f);
+ }
+ }
+}
+
+void BMO_remove_tagged_edges(BMesh *bm, const short oflag)
+{
+ BMEdge *e;
+ BMIter iter;
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (BMO_elem_flag_test(bm, e, oflag)) {
+ BM_edge_kill(bm, e);
+ }
+ }
+}
+
+void BMO_remove_tagged_verts(BMesh *bm, const short oflag)
+{
+ BMVert *v;
+ BMIter iter;
+
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMO_elem_flag_test(bm, v, oflag)) {
+ BM_vert_kill(bm, v);
+ }
+ }
+}
+
+/*************************************************************/
+/* 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....
+ */
+
+static void bmo_remove_tagged_context_verts(BMesh *bm, const short oflag)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ for (v = BM_iter_new(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BM_iter_step(&verts)) {
+ if (BMO_elem_flag_test(bm, v, oflag)) {
+ /* Visit edge */
+ for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_VERT, v); e; e = BM_iter_step(&edges))
+ BMO_elem_flag_enable(bm, e, oflag);
+ /* Visit face */
+ for (f = BM_iter_new(&faces, bm, BM_FACES_OF_VERT, v); f; f = BM_iter_step(&faces))
+ BMO_elem_flag_enable(bm, f, oflag);
+ }
+ }
+
+ BMO_remove_tagged_faces(bm, oflag);
+ BMO_remove_tagged_edges(bm, oflag);
+ BMO_remove_tagged_verts(bm, oflag);
+}
+
+static void bmo_remove_tagged_context_edges(BMesh *bm, const short oflag)
+{
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter edges;
+ BMIter faces;
+
+ for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
+ if (BMO_elem_flag_test(bm, e, oflag)) {
+ for (f = BM_iter_new(&faces, bm, BM_FACES_OF_EDGE, e); f; f = BM_iter_step(&faces)) {
+ BMO_elem_flag_enable(bm, f, oflag);
+ }
+ }
+ }
+ BMO_remove_tagged_faces(bm, oflag);
+ BMO_remove_tagged_edges(bm, oflag);
+}
+
+#define DEL_WIREVERT (1 << 10)
+
+/* warning, oflag applies to different types in some contexts,
+ * not just the type being removed */
+void BMO_remove_tagged_context(BMesh *bm, const short oflag, const int type)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ switch (type) {
+ case DEL_VERTS:
+ {
+ bmo_remove_tagged_context_verts(bm, oflag);
+
+ break;
+ }
+ case DEL_EDGES:
+ {
+ /* flush down to vert */
+ for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
+ if (BMO_elem_flag_test(bm, e, oflag)) {
+ BMO_elem_flag_enable(bm, e->v1, oflag);
+ BMO_elem_flag_enable(bm, e->v2, oflag);
+ }
+ }
+ bmo_remove_tagged_context_edges(bm, oflag);
+ /* remove loose vertice */
+ for (v = BM_iter_new(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BM_iter_step(&verts)) {
+ if (BMO_elem_flag_test(bm, v, oflag) && (!(v->e)))
+ BMO_elem_flag_enable(bm, v, DEL_WIREVERT);
+ }
+ BMO_remove_tagged_verts(bm, DEL_WIREVERT);
+
+ break;
+ }
+ case DEL_EDGESFACES:
+ {
+ bmo_remove_tagged_context_edges(bm, oflag);
+
+ break;
+ }
+ case DEL_ONLYFACES:
+ {
+ BMO_remove_tagged_faces(bm, oflag);
+
+ break;
+ }
+ case DEL_ONLYTAGGED:
+ {
+ BMO_remove_tagged_faces(bm, oflag);
+ BMO_remove_tagged_edges(bm, oflag);
+ BMO_remove_tagged_verts(bm, oflag);
+
+ break;
+ }
+ case DEL_FACES:
+ {
+ /* go through and mark all edges and all verts of all faces for delet */
+ for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
+ if (BMO_elem_flag_test(bm, f, oflag)) {
+ for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_FACE, f); e; e = BM_iter_step(&edges))
+ BMO_elem_flag_enable(bm, e, oflag);
+ for (v = BM_iter_new(&verts, bm, BM_VERTS_OF_FACE, f); v; v = BM_iter_step(&verts))
+ BMO_elem_flag_enable(bm, v, oflag);
+ }
+ }
+ /* now go through and mark all remaining faces all edges for keeping */
+ for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
+ if (!BMO_elem_flag_test(bm, f, oflag)) {
+ for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_FACE, f); e; e = BM_iter_step(&edges)) {
+ BMO_elem_flag_disable(bm, e, oflag);
+ }
+ for (v = BM_iter_new(&verts, bm, BM_VERTS_OF_FACE, f); v; v = BM_iter_step(&verts)) {
+ BMO_elem_flag_disable(bm, v, oflag);
+ }
+ }
+ }
+ /* also mark all the vertices of remaining edges for keeping */
+ for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
+ if (!BMO_elem_flag_test(bm, e, oflag)) {
+ BMO_elem_flag_disable(bm, e->v1, oflag);
+ BMO_elem_flag_disable(bm, e->v2, oflag);
+ }
+ }
+ /* now delete marked face */
+ BMO_remove_tagged_faces(bm, oflag);
+ /* delete marked edge */
+ BMO_remove_tagged_edges(bm, oflag);
+ /* remove loose vertice */
+ BMO_remove_tagged_verts(bm, oflag);
+
+ break;
+ }
+ case DEL_ALL:
+ {
+ /* does this option even belong in here? */
+ for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces))
+ BMO_elem_flag_enable(bm, f, oflag);
+ for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges))
+ BMO_elem_flag_enable(bm, e, oflag);
+ for (v = BM_iter_new(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BM_iter_step(&verts))
+ BMO_elem_flag_enable(bm, v, oflag);
+
+ BMO_remove_tagged_faces(bm, oflag);
+ BMO_remove_tagged_edges(bm, oflag);
+ BMO_remove_tagged_verts(bm, oflag);
+
+ break;
+ }
+ }
+}
+/*************************************************************/
+
+
+static void bm_vert_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
+ const BMVert *source_vertex, BMVert *target_vertex)
+{
+ if ((source_mesh == target_mesh) && (source_vertex == target_vertex)) {
+ return;
+ }
+ copy_v3_v3(target_vertex->no, source_vertex->no);
+ CustomData_bmesh_free_block(&target_mesh->vdata, &target_vertex->head.data);
+ CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata,
+ source_vertex->head.data, &target_vertex->head.data);
+}
+
+static void bm_edge_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
+ const BMEdge *source_edge, BMEdge *target_edge)
+{
+ if ((source_mesh == target_mesh) && (source_edge == target_edge)) {
+ return;
+ }
+ CustomData_bmesh_free_block(&target_mesh->edata, &target_edge->head.data);
+ CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata,
+ source_edge->head.data, &target_edge->head.data);
+}
+
+static void bm_loop_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
+ const BMLoop *source_loop, BMLoop *target_loop)
+{
+ if ((source_mesh == target_mesh) && (source_loop == target_loop)) {
+ return;
+ }
+ CustomData_bmesh_free_block(&target_mesh->ldata, &target_loop->head.data);
+ CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata,
+ source_loop->head.data, &target_loop->head.data);
+}
+
+static void bm_face_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
+ const BMFace *source_face, BMFace *target_face)
+{
+ if ((source_mesh == target_mesh) && (source_face == target_face)) {
+ return;
+ }
+ copy_v3_v3(target_face->no, source_face->no);
+ CustomData_bmesh_free_block(&target_mesh->pdata, &target_face->head.data);
+ 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;
+}
+
+/* BMESH_TODO: Special handling for hide flags? */
+
+void BM_elem_attrs_copy(BMesh *source_mesh, BMesh *target_mesh, const void *source, void *target)
+{
+ const BMHeader *sheader = source;
+ BMHeader *theader = target;
+
+ if (sheader->htype != theader->htype)
+ return;
+
+ /* First we copy select */
+ if (BM_elem_flag_test(source, BM_ELEM_SELECT)) BM_elem_select_set(target_mesh, target, TRUE);
+
+ /* Now we copy flags */
+ theader->hflag = sheader->hflag;
+
+ /* Copy specific attributes */
+ if (theader->htype == BM_VERT)
+ bm_vert_attrs_copy(source_mesh, target_mesh, (const BMVert *)source, (BMVert *)target);
+ else if (theader->htype == BM_EDGE)
+ bm_edge_attrs_copy(source_mesh, target_mesh, (const BMEdge *)source, (BMEdge *)target);
+ else if (theader->htype == BM_LOOP)
+ bm_loop_attrs_copy(source_mesh, target_mesh, (const BMLoop *)source, (BMLoop *)target);
+ else if (theader->htype == BM_FACE)
+ bm_face_attrs_copy(source_mesh, target_mesh, (const BMFace *)source, (BMFace *)target);
+}
+
+BMesh *BM_mesh_copy(BMesh *bmold)
+{
+ BMesh *bm;
+ BMVert *v, *v2, **vtable = NULL;
+ BMEdge *e, *e2, **edges = NULL, **etable = NULL;
+ BLI_array_declare(edges);
+ BMLoop *l, /* *l2, */ **loops = NULL;
+ BLI_array_declare(loops);
+ BMFace *f, *f2, **ftable = NULL;
+ BMEditSelection *ese;
+ BMIter iter, liter;
+ int i, j;
+
+ /* allocate a bmesh */
+ bm = BM_mesh_create(bmold->ob, bm_mesh_allocsize_default);
+
+ 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, bm_mesh_allocsize_default[0]);
+ CustomData_bmesh_init_pool(&bm->edata, bm_mesh_allocsize_default[1]);
+ CustomData_bmesh_init_pool(&bm->ldata, bm_mesh_allocsize_default[2]);
+ CustomData_bmesh_init_pool(&bm->pdata, bm_mesh_allocsize_default[3]);
+
+ vtable = MEM_mallocN(sizeof(BMVert *) * bmold->totvert, "BM_mesh_copy vtable");
+ etable = MEM_mallocN(sizeof(BMEdge *) * bmold->totedge, "BM_mesh_copy etable");
+ ftable = MEM_mallocN(sizeof(BMFace *) * bmold->totface, "BM_mesh_copy ftable");
+
+ v = BM_iter_new(&iter, bmold, BM_VERTS_OF_MESH, NULL);
+ for (i = 0; v; v = BM_iter_step(&iter), i++) {
+ v2 = BM_vert_create(bm, v->co, NULL); /* copy between meshes so cant use 'example' argument */
+ BM_elem_attrs_copy(bmold, bm, v, v2);
+ vtable[i] = v2;
+ BM_elem_index_set(v, i); /* set_inline */
+ BM_elem_index_set(v2, i); /* set_inline */
+ }
+ bmold->elem_index_dirty &= ~BM_VERT;
+ bm->elem_index_dirty &= ~BM_VERT;
+
+ /* safety check */
+ BLI_assert(i == bmold->totvert);
+
+ e = BM_iter_new(&iter, bmold, BM_EDGES_OF_MESH, NULL);
+ for (i = 0; e; e = BM_iter_step(&iter), i++) {
+ e2 = BM_edge_create(bm,
+ vtable[BM_elem_index_get(e->v1)],
+ vtable[BM_elem_index_get(e->v2)],
+ e, FALSE);
+
+ BM_elem_attrs_copy(bmold, bm, e, e2);
+ etable[i] = e2;
+ BM_elem_index_set(e, i); /* set_inline */
+ BM_elem_index_set(e2, i); /* set_inline */
+ }
+ bmold->elem_index_dirty &= ~BM_EDGE;
+ bm->elem_index_dirty &= ~BM_EDGE;
+
+ /* safety check */
+ BLI_assert(i == bmold->totedge);
+
+ f = BM_iter_new(&iter, bmold, BM_FACES_OF_MESH, NULL);
+ for (i = 0; f; f = BM_iter_step(&iter), i++) {
+ BM_elem_index_set(f, i); /* set_inline */
+
+ BLI_array_empty(loops);
+ BLI_array_empty(edges);
+ BLI_array_growitems(loops, f->len);
+ BLI_array_growitems(edges, f->len);
+
+ l = BM_iter_new(&liter, bmold, BM_LOOPS_OF_FACE, f);
+ for (j = 0; j < f->len; j++, l = BM_iter_step(&liter)) {
+ loops[j] = l;
+ edges[j] = etable[BM_elem_index_get(l->e)];
+ }
+
+ v = vtable[BM_elem_index_get(loops[0]->v)];
+ v2 = vtable[BM_elem_index_get(loops[1]->v)];
+
+ if (!bmesh_verts_in_edge(v, v2, edges[0])) {
+ v = vtable[BM_elem_index_get(loops[BLI_array_count(loops) - 1]->v)];
+ v2 = vtable[BM_elem_index_get(loops[0]->v)];
+ }
+
+ f2 = BM_face_create_ngon(bm, v, v2, edges, f->len, FALSE);
+ if (!f2)
+ continue;
+ /* use totface incase adding some faces fails */
+ BM_elem_index_set(f2, (bm->totface - 1)); /* set_inline */
+
+ ftable[i] = f2;
+
+ BM_elem_attrs_copy(bmold, bm, f, f2);
+ copy_v3_v3(f2->no, f->no);
+
+ l = BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, f2);
+ for (j = 0; j < f->len; j++, l = BM_iter_step(&liter)) {
+ BM_elem_attrs_copy(bmold, bm, loops[j], l);
+ }
+
+ if (f == bmold->act_face) bm->act_face = f2;
+ }
+ bmold->elem_index_dirty &= ~BM_FACE;
+ bm->elem_index_dirty &= ~BM_FACE;
+
+ /* safety check */
+ BLI_assert(i == bmold->totface);
+
+ /* copy over edit selection history */
+ for (ese = bmold->selected.first; ese; ese = ese->next) {
+ void *ele = NULL;
+
+ if (ese->htype == BM_VERT)
+ ele = vtable[BM_elem_index_get(ese->data)];
+ else if (ese->htype == BM_EDGE)
+ ele = etable[BM_elem_index_get(ese->data)];
+ else if (ese->htype == BM_FACE) {
+ ele = ftable[BM_elem_index_get(ese->data)];
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ if (ele)
+ BM_select_history_store(bm, ele);
+ }
+
+ MEM_freeN(etable);
+ MEM_freeN(vtable);
+ MEM_freeN(ftable);
+
+ BLI_array_free(loops);
+ BLI_array_free(edges);
+
+ return bm;
+}
+
+/* ME -> BM */
+char BM_vert_flag_from_mflag(const char meflag)
+{
+ return ( ((meflag & SELECT) ? BM_ELEM_SELECT : 0) |
+ ((meflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0)
+ );
+}
+char BM_edge_flag_from_mflag(const short meflag)
+{
+ return ( ((meflag & SELECT) ? BM_ELEM_SELECT : 0) |
+ ((meflag & ME_SEAM) ? BM_ELEM_SEAM : 0) |
+ ((meflag & ME_SHARP) == 0 ? BM_ELEM_SMOOTH : 0) | /* invert */
+ ((meflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0) |
+ ((meflag & ME_FREESTYLE_EDGE) ? BM_ELEM_FREESTYLE : 0)
+ );
+}
+char BM_face_flag_from_mflag(const char meflag)
+{
+ return ( ((meflag & ME_FACE_SEL) ? BM_ELEM_SELECT : 0) |
+ ((meflag & ME_SMOOTH) ? BM_ELEM_SMOOTH : 0) |
+ ((meflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0) |
+ ((meflag & ME_FREESTYLE_FACE) ? BM_ELEM_FREESTYLE : 0)
+ );
+}
+
+/* BM -> ME */
+char BM_vert_flag_to_mflag(BMVert *eve)
+{
+ const char hflag = eve->head.hflag;
+
+ return ( ((hflag & BM_ELEM_SELECT) ? SELECT : 0) |
+ ((hflag & BM_ELEM_HIDDEN) ? ME_HIDE : 0)
+ );
+}
+short BM_edge_flag_to_mflag(BMEdge *eed)
+{
+ const char hflag = eed->head.hflag;
+
+ return ( ((hflag & BM_ELEM_SELECT) ? SELECT : 0) |
+ ((hflag & BM_ELEM_SEAM) ? ME_SEAM : 0) |
+ ((hflag & BM_ELEM_SMOOTH) == 0 ? ME_SHARP : 0) |
+ ((hflag & BM_ELEM_HIDDEN) ? ME_HIDE : 0) |
+ ((hflag & BM_ELEM_FREESTYLE) ? ME_FREESTYLE_EDGE : 0) |
+ ((BM_edge_is_wire(NULL, eed)) ? ME_LOOSEEDGE : 0) | /* not typical */
+ (ME_EDGEDRAW | ME_EDGERENDER)
+ );
+}
+char BM_face_flag_to_mflag(BMFace *efa)
+{
+ const char hflag = efa->head.hflag;
+
+ return ( ((hflag & BM_ELEM_SELECT) ? ME_FACE_SEL : 0) |
+ ((hflag & BM_ELEM_SMOOTH) ? ME_SMOOTH : 0) |
+ ((hflag & BM_ELEM_HIDDEN) ? ME_HIDE : 0) |
+ ((hflag & BM_ELEM_FREESTYLE) ? ME_FREESTYLE_FACE : 0)
+ );
+}
diff --git a/source/blender/bmesh/intern/bmesh_inline.c b/source/blender/bmesh/intern/bmesh_inline.c
new file mode 100644
index 00000000000..4433aaa0fc6
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_inline.c
@@ -0,0 +1,71 @@
+/*
+ * ***** 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): Joseph Eagar, Geoffrey Bantle, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_inline.c
+ * \ingroup bmesh
+ *
+ * BM Inline functions.
+ */
+
+#ifndef __BMESH_INLINE_C__
+#define __BMESH_INLINE_C__
+
+#include "bmesh.h"
+
+BM_INLINE char BM_elem_flag_test(const void *element, const char hflag)
+{
+ return ((const BMHeader *)element)->hflag & hflag;
+}
+
+BM_INLINE void BM_elem_flag_enable(void *element, const char hflag)
+{
+ ((BMHeader *)element)->hflag |= hflag;
+}
+
+BM_INLINE void BM_elem_flag_disable(void *element, const char hflag)
+{
+ ((BMHeader *)element)->hflag &= ~hflag;
+}
+
+BM_INLINE void BM_elem_flag_toggle(void *element, const char hflag)
+{
+ ((BMHeader *)element)->hflag ^= hflag;
+}
+
+BM_INLINE void BM_elem_flag_merge(void *element_a, void *element_b)
+{
+ ((BMHeader *)element_a)->hflag =
+ ((BMHeader *)element_b)->hflag = (((BMHeader *)element_a)->hflag |
+ ((BMHeader *)element_b)->hflag);
+}
+
+BM_INLINE void BM_elem_index_set(void *element, const int index)
+{
+ ((BMHeader *)element)->index = index;
+}
+
+BM_INLINE int BM_elem_index_get(const void *element)
+{
+ return ((BMHeader *)element)->index;
+}
+
+#endif /* __BMESH_INLINE_C__ */
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
new file mode 100644
index 00000000000..d5f22690d63
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -0,0 +1,984 @@
+/*
+ * ***** 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): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_interp.c
+ * \ingroup bmesh
+ *
+ * Functions for interpolating data across the surface of a mesh.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_multires.h"
+
+#include "BLI_array.h"
+#include "BLI_math.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+/**
+ * bmesh_data_interp_from_verts
+ *
+ * Interpolates per-vertex data from two sources to a target.
+ */
+void BM_data_interp_from_verts(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, const float fac)
+{
+ if (v1->head.data && v2->head.data) {
+ /* first see if we can avoid interpolation */
+ if (fac <= 0.0f) {
+ if (v1 == v) {
+ /* do nothing */
+ }
+ else {
+ CustomData_bmesh_free_block(&bm->vdata, &v->head.data);
+ CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, v1->head.data, &v->head.data);
+ }
+ }
+ else if (fac >= 1.0f) {
+ if (v2 == v) {
+ /* do nothing */
+ }
+ else {
+ CustomData_bmesh_free_block(&bm->vdata, &v->head.data);
+ CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, v2->head.data, &v->head.data);
+ }
+ }
+ else {
+ void *src[2];
+ float w[2];
+
+ 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.
+ */
+
+
+static void UNUSED_FUNCTION(BM_Data_Vert_Average)(BMesh *UNUSED(bm), BMFace *UNUSED(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_interp_face_vert_edge(BMesh *bm, BMVert *v1, BMVert *UNUSED(v2), BMVert *v, BMEdge *e1, const float fac)
+{
+ void *src[2];
+ float w[2];
+ BMLoop *v1loop = NULL, *vloop = NULL, *v2loop = NULL;
+ BMLoop *l_iter = NULL;
+
+ if (!e1->l) {
+ return;
+ }
+
+ w[1] = 1.0f - fac;
+ w[0] = fac;
+
+ l_iter = e1->l;
+ do {
+ if (l_iter->v == v1) {
+ v1loop = l_iter;
+ vloop = v1loop->next;
+ v2loop = vloop->next;
+ }
+ else if (l_iter->v == v) {
+ v1loop = l_iter->next;
+ vloop = l_iter;
+ v2loop = l_iter->prev;
+ }
+
+ if (!v1loop || !v2loop)
+ return;
+
+ src[0] = v1loop->head.data;
+ src[1] = v2loop->head.data;
+
+ CustomData_bmesh_interp(&bm->ldata, src, w, NULL, 2, vloop->head.data);
+ } while ((l_iter = l_iter->radial_next) != 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);
+
+ ME_MTEXFACE_CPY(texface, texpoly);
+
+ 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);
+ copy_v2_v2(texface->uv[j], mloopuv->uv);
+
+ 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++;
+ }
+ }
+}
+
+/**
+ * BM_data_interp_from_face
+ *
+ * projects target onto source, and pulls interpolated customdata from
+ * source.
+ *
+ * Returns -
+ * Nothing
+ */
+void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source)
+{
+ BMLoop *l_iter;
+ BMLoop *l_first;
+
+ void **blocks = NULL;
+ float (*cos)[3] = NULL, *w = NULL;
+ BLI_array_fixedstack_declare(cos, BM_NGON_STACK_SIZE, source->len, __func__);
+ BLI_array_fixedstack_declare(w, BM_NGON_STACK_SIZE, source->len, __func__);
+ BLI_array_fixedstack_declare(blocks, BM_NGON_STACK_SIZE, source->len, __func__);
+ int i;
+
+ BM_elem_attrs_copy(bm, bm, source, target);
+
+ i = 0;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(source);
+ do {
+ copy_v3_v3(cos[i], l_iter->v->co);
+ blocks[i] = l_iter->head.data;
+ i++;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ i = 0;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(target);
+ do {
+ interp_weights_poly_v3(w, cos, source->len, l_iter->v->co);
+ CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, source->len, l_iter->head.data);
+ i++;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ BLI_array_fixedstack_free(cos);
+ BLI_array_fixedstack_free(w);
+ BLI_array_fixedstack_free(blocks);
+}
+
+/* some math stuff for dealing with doubles, put here to
+ * avoid merge errors - joeedh */
+
+#define VECMUL(a, b) (((a)[0] = (a)[0] * (b)), ((a)[1] = (a)[1] * (b)), ((a)[2] = (a)[2] * (b)))
+#define VECADD2(a, b) (((a)[0] = (a)[0] + (b)[0]), ((a)[1] = (a)[1] + (b)[1]), ((a)[2] = (a)[2] + (b)[2]))
+#define VECSUB2(a, b) (((a)[0] = (a)[0] - (b)[0]), ((a)[1] = (a)[1] - (b)[1]), ((a)[2] = (a)[2] - (b)[2]))
+
+/* find closest point to p on line through l1, l2 and return lambda,
+ * where (0 <= lambda <= 1) when cp is in the line segement l1, l2
+ */
+static double closest_to_line_v3_d(double cp[3], const double p[3], const double l1[3], const double l2[3])
+{
+ double h[3], u[3], lambda;
+ VECSUB(u, l2, l1);
+ VECSUB(h, p, l1);
+ lambda = INPR(u, h) / INPR(u, u);
+ cp[0] = l1[0] + u[0] * lambda;
+ cp[1] = l1[1] + u[1] * lambda;
+ cp[2] = l1[2] + u[2] * lambda;
+ return lambda;
+}
+
+/* point closest to v1 on line v2-v3 in 3D */
+static void UNUSED_FUNCTION(closest_to_line_segment_v3_d)(double *closest, double v1[3], double v2[3], double v3[3])
+{
+ double lambda, cp[3];
+
+ lambda = closest_to_line_v3_d(cp, v1, v2, v3);
+
+ if (lambda <= 0.0) {
+ VECCOPY(closest, v2);
+ }
+ else if (lambda >= 1.0) {
+ VECCOPY(closest, v3);
+ }
+ else {
+ VECCOPY(closest, cp);
+ }
+}
+
+static double UNUSED_FUNCTION(len_v3_d)(const double a[3])
+{
+ return sqrt(INPR(a, a));
+}
+
+static double UNUSED_FUNCTION(len_v3v3_d)(const double a[3], const double b[3])
+{
+ double d[3];
+
+ VECSUB(d, b, a);
+ return sqrt(INPR(d, d));
+}
+
+static void cent_quad_v3_d(double *cent, double *v1, double *v2, double *v3, double *v4)
+{
+ cent[0] = 0.25 * (v1[0] + v2[0] + v3[0] + v4[0]);
+ cent[1] = 0.25 * (v1[1] + v2[1] + v3[1] + v4[1]);
+ cent[2] = 0.25 * (v1[2] + v2[2] + v3[2] + v4[2]);
+}
+
+static void UNUSED_FUNCTION(cent_tri_v3_d)(double *cent, double *v1, double *v2, double *v3)
+{
+ cent[0] = (1.0 / 3.0) * (v1[0] + v2[0] + v3[0]);
+ cent[1] = (1.0 / 3.0) * (v1[1] + v2[1] + v3[1]);
+ cent[2] = (1.0 / 3.0) * (v1[2] + v2[2] + v3[2]);
+}
+
+static void UNUSED_FUNCTION(cross_v3_v3v3_d)(double r[3], const double a[3], const double b[3])
+{
+ r[0] = a[1] * b[2] - a[2] * b[1];
+ r[1] = a[2] * b[0] - a[0] * b[2];
+ r[2] = a[0] * b[1] - a[1] * b[0];
+}
+
+/* distance v1 to line-piece v2-v3 */
+static double UNUSED_FUNCTION(dist_to_line_segment_v2_d)(double v1[3], double v2[3], double v3[3])
+{
+ double labda, rc[2], pt[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.0) {
+ rc[0] = v1[0] - v2[0];
+ rc[1] = v1[1] - v2[1];
+ return sqrt(rc[0] * rc[0] + rc[1] * rc[1]);
+ }
+
+ labda = (rc[0] * (v1[0] - v2[0]) + rc[1] * (v1[1] - v2[1])) / len;
+ if (labda <= 0.0) {
+ pt[0] = v2[0];
+ pt[1] = v2[1];
+ }
+ else if (labda >= 1.0) {
+ pt[0] = v3[0];
+ pt[1] = v3[1];
+ }
+ else {
+ pt[0] = labda * rc[0] + v2[0];
+ pt[1] = labda * rc[1] + v2[1];
+ }
+
+ rc[0] = pt[0] - v1[0];
+ rc[1] = pt[1] - v1[1];
+ return sqrt(rc[0] * rc[0] + rc[1] * rc[1]);
+}
+
+
+MINLINE double line_point_side_v2_d(const double *l1, const double *l2, const double *pt)
+{
+ return ((l1[0] - pt[0]) * (l2[1] - pt[1])) -
+ ((l2[0] - pt[0]) * (l1[1] - pt[1]));
+}
+
+/* point in quad - only convex quads */
+static int isect_point_quad_v2_d(double pt[2], double v1[2], double v2[2], double v3[2], double v4[2])
+{
+ if (line_point_side_v2_d(v1, v2, pt) >= 0.0) {
+ if (line_point_side_v2_d(v2, v3, pt) >= 0.0) {
+ if (line_point_side_v2_d(v3, v4, pt) >= 0.0) {
+ if (line_point_side_v2_d(v4, v1, pt) >= 0.0) {
+ return 1;
+ }
+ }
+ }
+ }
+ else {
+ if (! (line_point_side_v2_d(v2, v3, pt) >= 0.0)) {
+ if (! (line_point_side_v2_d(v3, v4, pt) >= 0.0)) {
+ if (! (line_point_side_v2_d(v4, v1, pt) >= 0.0)) {
+ return -1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/***** multires interpolation*****
+ *
+ * mdisps is a grid of displacements, ordered thus:
+ *
+ * v1/center----v4/next -> x
+ * | |
+ * | |
+ * v2/prev------v3/cur
+ * |
+ * V
+ * y
+ */
+
+static int compute_mdisp_quad(BMLoop *l, double v1[3], double v2[3], double v3[3], double v4[3],
+ double e1[3], double e2[3])
+{
+ double cent[3] = {0.0, 0.0, 0.0}, n[3], p[3];
+ BMLoop *l_first;
+ BMLoop *l_iter;
+
+ /* computer center */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(l->f);
+ do {
+ cent[0] += (double)l_iter->v->co[0];
+ cent[1] += (double)l_iter->v->co[1];
+ cent[2] += (double)l_iter->v->co[2];
+ } while ((l_iter = l_iter->next) != l_first);
+
+ VECMUL(cent, (1.0 / (double)l->f->len));
+
+ VECADD(p, l->prev->v->co, l->v->co);
+ VECMUL(p, 0.5);
+ VECADD(n, l->next->v->co, l->v->co);
+ VECMUL(n, 0.5);
+
+ VECCOPY(v1, cent);
+ VECCOPY(v2, p);
+ VECCOPY(v3, l->v->co);
+ VECCOPY(v4, n);
+
+ VECSUB(e1, v2, v1);
+ VECSUB(e2, v3, v4);
+
+ return 1;
+}
+
+/* funnily enough, I think this is identical to face_to_crn_interp, heh */
+static double quad_coord(double aa[3], double bb[3], double cc[3], double dd[3], int a1, int a2)
+{
+ double x, y, z, f1;
+
+ x = aa[a1] * cc[a2] - cc[a1] * aa[a2];
+ y = aa[a1] * dd[a2] + bb[a1] * cc[a2] - cc[a1] * bb[a2] - dd[a1] * aa[a2];
+ z = bb[a1] * dd[a2] - dd[a1] * bb[a2];
+
+ if (fabs(2 * (x - y + z)) > DBL_EPSILON * 10.0) {
+ double f2;
+
+ f1 = (sqrt(y * y - 4.0 * x * z) - y + 2.0 * z) / (2.0 * (x - y + z));
+ f2 = (-sqrt(y * y - 4.0 * x * z) - y + 2.0 * z) / (2.0 * (x - y + z));
+
+ f1 = fabs(f1);
+ f2 = fabs(f2);
+ f1 = MIN2(f1, f2);
+ CLAMP(f1, 0.0, 1.0 + DBL_EPSILON);
+ }
+ else {
+ f1 = -z / (y - 2 * z);
+ CLAMP(f1, 0.0, 1.0 + DBL_EPSILON);
+
+ if (isnan(f1) || f1 > 1.0 || f1 < 0.0) {
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ if (fabsf(aa[i]) < FLT_EPSILON * 100)
+ return aa[(i + 1) % 2] / fabs(bb[(i + 1) % 2] - aa[(i + 1) % 2]);
+ if (fabsf(cc[i]) < FLT_EPSILON * 100)
+ return cc[(i + 1) % 2] / fabs(dd[(i + 1) % 2] - cc[(i + 1) % 2]);
+ }
+ }
+ }
+
+ return f1;
+}
+
+static int quad_co(double *x, double *y, double v1[3], double v2[3], double v3[3], double v4[3],
+ double p[3], float n[3])
+{
+ float projverts[5][3], n2[3];
+ double dprojverts[4][3], origin[3] = {0.0f, 0.0f, 0.0f};
+ int i;
+
+ /* project points into 2d along normal */
+ VECCOPY(projverts[0], v1);
+ VECCOPY(projverts[1], v2);
+ VECCOPY(projverts[2], v3);
+ VECCOPY(projverts[3], v4);
+ VECCOPY(projverts[4], p);
+
+ normal_quad_v3(n2, projverts[0], projverts[1], projverts[2], projverts[3]);
+
+ if (INPR(n, n2) < -FLT_EPSILON) {
+ return 0;
+ }
+
+ /* rotate */
+ poly_rotate_plane(n, projverts, 5);
+
+ /* flatten */
+ for (i = 0; i < 5; i++) {
+ projverts[i][2] = 0.0f;
+ }
+
+ /* subtract origin */
+ for (i = 0; i < 4; i++) {
+ VECSUB2(projverts[i], projverts[4]);
+ }
+
+ VECCOPY(dprojverts[0], projverts[0]);
+ VECCOPY(dprojverts[1], projverts[1]);
+ VECCOPY(dprojverts[2], projverts[2]);
+ VECCOPY(dprojverts[3], projverts[3]);
+
+ if (!isect_point_quad_v2_d(origin, dprojverts[0], dprojverts[1], dprojverts[2], dprojverts[3])) {
+ return 0;
+ }
+
+ *y = quad_coord(dprojverts[1], dprojverts[0], dprojverts[2], dprojverts[3], 0, 1);
+ *x = quad_coord(dprojverts[2], dprojverts[1], dprojverts[3], dprojverts[0], 0, 1);
+
+ return 1;
+}
+
+
+/* tl is loop to project onto, l is loop whose internal displacement, co, is being
+ * projected. x and y are location in loop's mdisps grid of point co. */
+static int mdisp_in_mdispquad(BMesh *bm, BMLoop *l, BMLoop *tl, double p[3], double *x, double *y, int res)
+{
+ double v1[3], v2[3], c[3], v3[3], v4[3], e1[3], e2[3];
+ double eps = FLT_EPSILON * 4000;
+
+ if (len_v3(l->v->no) == 0.0f)
+ BM_vert_normal_update_all(bm, l->v);
+ if (len_v3(tl->v->no) == 0.0f)
+ BM_vert_normal_update_all(bm, tl->v);
+
+ compute_mdisp_quad(tl, v1, v2, v3, v4, e1, e2);
+
+ /* expand quad a bit */
+ cent_quad_v3_d(c, v1, v2, v3, v4);
+
+ VECSUB2(v1, c); VECSUB2(v2, c);
+ VECSUB2(v3, c); VECSUB2(v4, c);
+ VECMUL(v1, 1.0 + eps); VECMUL(v2, 1.0 + eps);
+ VECMUL(v3, 1.0 + eps); VECMUL(v4, 1.0 + eps);
+ VECADD2(v1, c); VECADD2(v2, c);
+ VECADD2(v3, c); VECADD2(v4, c);
+
+ if (!quad_co(x, y, v1, v2, v3, v4, p, l->v->no))
+ return 0;
+
+ *x *= res - 1;
+ *y *= res - 1;
+
+ return 1;
+}
+
+static void bmesh_loop_interp_mdisps(BMesh *bm, BMLoop *target, BMFace *source)
+{
+ MDisps *mdisps;
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ double x, y, d, v1[3], v2[3], v3[3], v4[3] = {0.0f, 0.0f, 0.0f}, e1[3], e2[3];
+ int ix, iy, res;
+
+ /* ignore 2-edged faces */
+ if (target->f->len < 3)
+ return;
+
+ if (!CustomData_has_layer(&bm->ldata, CD_MDISPS))
+ return;
+
+ mdisps = CustomData_bmesh_get(&bm->ldata, target->head.data, CD_MDISPS);
+ compute_mdisp_quad(target, v1, v2, v3, v4, e1, e2);
+
+ /* if no disps data allocate a new grid, the size of the first grid in source. */
+ if (!mdisps->totdisp) {
+ MDisps *md2 = CustomData_bmesh_get(&bm->ldata, BM_FACE_FIRST_LOOP(source)->head.data, CD_MDISPS);
+
+ mdisps->totdisp = md2->totdisp;
+ if (mdisps->totdisp) {
+ mdisps->disps = MEM_callocN(sizeof(float) * 3 * mdisps->totdisp,
+ "mdisp->disps in bmesh_loop_intern_mdisps");
+ }
+ else {
+ return;
+ }
+ }
+
+ res = (int)sqrt(mdisps->totdisp);
+ d = 1.0 / (double)(res - 1);
+ for (x = 0.0f, ix = 0; ix < res; x += d, ix++) {
+ for (y = 0.0f, iy = 0; iy < res; y += d, iy++) {
+ double co1[3], co2[3], co[3];
+ /* double xx, yy; */ /* UNUSED */
+
+ VECCOPY(co1, e1);
+
+ /* if (!iy) yy = y + (double)FLT_EPSILON * 20; */
+ /* else yy = y - (double)FLT_EPSILON * 20; */
+
+ VECMUL(co1, y);
+ VECADD2(co1, v1);
+
+ VECCOPY(co2, e2);
+ VECMUL(co2, y);
+ VECADD2(co2, v4);
+
+ /* if (!ix) xx = x + (double)FLT_EPSILON * 20; */ /* UNUSED */
+ /* else xx = x - (double)FLT_EPSILON * 20; */ /* UNUSED */
+
+ VECSUB(co, co2, co1);
+ VECMUL(co, x);
+ VECADD2(co, co1);
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(source);
+ do {
+ double x2, y2;
+ MDisps *md1, *md2;
+
+ md1 = CustomData_bmesh_get(&bm->ldata, target->head.data, CD_MDISPS);
+ md2 = CustomData_bmesh_get(&bm->ldata, l_iter->head.data, CD_MDISPS);
+
+ if (mdisp_in_mdispquad(bm, target, l_iter, co, &x2, &y2, res)) {
+ /* int ix2 = (int)x2; */ /* UNUSED */
+ /* int iy2 = (int)y2; */ /* UNUSED */
+
+ old_mdisps_bilinear(md1->disps[iy * res + ix], md2->disps, res, (float)x2, (float)y2);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ }
+}
+
+void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
+{
+ BMLoop *l;
+ BMIter liter;
+
+ if (!CustomData_has_layer(&bm->ldata, CD_MDISPS))
+ return;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ MDisps *mdp = CustomData_bmesh_get(&bm->ldata, l->prev->head.data, CD_MDISPS);
+ MDisps *mdl = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MDISPS);
+ MDisps *mdn = CustomData_bmesh_get(&bm->ldata, l->next->head.data, CD_MDISPS);
+ float co1[3];
+ int sides;
+ int y;
+
+ /*
+ * mdisps is a grid of displacements, ordered thus:
+ *
+ * v4/next
+ * |
+ * | v1/cent-----mid2 ---> x
+ * | | |
+ * | | |
+ * v2/prev---mid1-----v3/cur
+ * |
+ * V
+ * y
+ */
+
+ sides = (int)sqrt(mdp->totdisp);
+ for (y = 0; y < sides; y++) {
+ add_v3_v3v3(co1, mdn->disps[y * sides], mdl->disps[y]);
+ mul_v3_fl(co1, 0.5);
+
+ copy_v3_v3(mdn->disps[y * sides], co1);
+ copy_v3_v3(mdl->disps[y], co1);
+ }
+ }
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ MDisps *mdl1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MDISPS);
+ MDisps *mdl2;
+ float co1[3], co2[3], co[3];
+ int sides;
+ int y;
+
+ /*
+ * mdisps is a grid of displacements, ordered thus:
+ *
+ * v4/next
+ * |
+ * | v1/cent-----mid2 ---> x
+ * | | |
+ * | | |
+ * v2/prev---mid1-----v3/cur
+ * |
+ * V
+ * y
+ */
+
+ if (l->radial_next == l)
+ continue;
+
+ if (l->radial_next->v == l->v)
+ mdl2 = CustomData_bmesh_get(&bm->ldata, l->radial_next->head.data, CD_MDISPS);
+ else
+ mdl2 = CustomData_bmesh_get(&bm->ldata, l->radial_next->next->head.data, CD_MDISPS);
+
+ sides = (int)sqrt(mdl1->totdisp);
+ for (y = 0; y < sides; y++) {
+ int a1, a2, o1, o2;
+
+ if (l->v != l->radial_next->v) {
+ a1 = sides * y + sides - 2;
+ a2 = (sides - 2) * sides + y;
+
+ o1 = sides * y + sides - 1;
+ o2 = (sides - 1) * sides + y;
+ }
+ else {
+ a1 = sides * y + sides - 2;
+ a2 = sides * y + sides - 2;
+ o1 = sides * y + sides - 1;
+ o2 = sides * y + sides - 1;
+ }
+
+ /* magic blending numbers, hardcoded! */
+ add_v3_v3v3(co1, mdl1->disps[a1], mdl2->disps[a2]);
+ mul_v3_fl(co1, 0.18);
+
+ add_v3_v3v3(co2, mdl1->disps[o1], mdl2->disps[o2]);
+ mul_v3_fl(co2, 0.32);
+
+ add_v3_v3v3(co, co1, co2);
+
+ copy_v3_v3(mdl1->disps[o1], co);
+ copy_v3_v3(mdl2->disps[o2], co);
+ }
+ }
+}
+
+void BM_loop_interp_multires(BMesh *bm, BMLoop *target, BMFace *source)
+{
+ bmesh_loop_interp_mdisps(bm, target, source);
+}
+
+void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source,
+ int do_vertex, int do_multires)
+{
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ void **blocks = NULL;
+ void **vblocks = NULL;
+ float (*cos)[3] = NULL, co[3], *w = NULL;
+ float cent[3] = {0.0f, 0.0f, 0.0f};
+ BLI_array_fixedstack_declare(cos, BM_NGON_STACK_SIZE, source->len, __func__);
+ BLI_array_fixedstack_declare(w, BM_NGON_STACK_SIZE, source->len, __func__);
+ BLI_array_fixedstack_declare(blocks, BM_NGON_STACK_SIZE, source->len, __func__);
+ BLI_array_fixedstack_declare(vblocks, BM_NGON_STACK_SIZE, do_vertex ? source->len : 0, __func__);
+ int i, ax, ay;
+
+ BM_elem_attrs_copy(bm, bm, source, target->f);
+
+ i = 0;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(source);
+ do {
+ copy_v3_v3(cos[i], l_iter->v->co);
+ add_v3_v3(cent, cos[i]);
+
+ w[i] = 0.0f;
+ blocks[i] = l_iter->head.data;
+
+ if (do_vertex) {
+ vblocks[i] = l_iter->v->head.data;
+ }
+ i++;
+
+ } while ((l_iter = l_iter->next) != l_first);
+
+ /* find best projection of face XY, XZ or YZ: barycentric weights of
+ * the 2d projected coords are the same and faster to compute */
+
+ axis_dominant_v3(&ax, &ay, source->no);
+
+ /* scale source face coordinates a bit, so points sitting directonly on an
+ * edge will work. */
+ mul_v3_fl(cent, 1.0f / (float)source->len);
+ for (i = 0; i < source->len; i++) {
+ float vec[3], tmp[3];
+ sub_v3_v3v3(vec, cent, cos[i]);
+ mul_v3_fl(vec, 0.001f);
+ add_v3_v3(cos[i], vec);
+
+ copy_v3_v3(tmp, cos[i]);
+ cos[i][0] = tmp[ax];
+ cos[i][1] = tmp[ay];
+ cos[i][2] = 0.0;
+ }
+
+
+ /* interpolate */
+ co[0] = target->v->co[ax];
+ co[1] = target->v->co[ay];
+ co[2] = 0.0f;
+
+ interp_weights_poly_v3(w, cos, source->len, co);
+ CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, source->len, target->head.data);
+ if (do_vertex) {
+ CustomData_bmesh_interp(&bm->vdata, vblocks, w, NULL, source->len, target->v->head.data);
+ BLI_array_fixedstack_free(vblocks);
+ }
+
+ BLI_array_fixedstack_free(cos);
+ BLI_array_fixedstack_free(w);
+ BLI_array_fixedstack_free(blocks);
+
+ if (do_multires) {
+ if (CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
+ bmesh_loop_interp_mdisps(bm, target, source);
+ }
+ }
+}
+
+
+void BM_vert_interp_from_face(BMesh *bm, BMVert *v, BMFace *source)
+{
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ void **blocks = NULL;
+ float (*cos)[3] = NULL, *w = NULL;
+ float cent[3] = {0.0f, 0.0f, 0.0f};
+ BLI_array_fixedstack_declare(cos, BM_NGON_STACK_SIZE, source->len, __func__);
+ BLI_array_fixedstack_declare(w, BM_NGON_STACK_SIZE, source->len, __func__);
+ BLI_array_fixedstack_declare(blocks, BM_NGON_STACK_SIZE, source->len, __func__);
+ int i;
+
+ i = 0;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(source);
+ do {
+ copy_v3_v3(cos[i], l_iter->v->co);
+ add_v3_v3(cent, cos[i]);
+
+ w[i] = 0.0f;
+ blocks[i] = l_iter->v->head.data;
+ i++;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ /* scale source face coordinates a bit, so points sitting directonly on an
+ * edge will work. */
+ mul_v3_fl(cent, 1.0f / (float)source->len);
+ for (i = 0; i < source->len; i++) {
+ float vec[3];
+ sub_v3_v3v3(vec, cent, cos[i]);
+ mul_v3_fl(vec, 0.01);
+ add_v3_v3(cos[i], vec);
+ }
+
+ /* interpolate */
+ interp_weights_poly_v3(w, cos, source->len, v->co);
+ CustomData_bmesh_interp(&bm->vdata, blocks, w, NULL, source->len, v->head.data);
+
+ BLI_array_fixedstack_free(cos);
+ BLI_array_fixedstack_free(w);
+ BLI_array_fixedstack_free(blocks);
+}
+
+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;
+ }
+ }
+ }
+ }
+
+ if (oldpool) {
+ /* this should never happen but can when dissolve fails - [#28960] */
+ BLI_assert(data->pool != oldpool);
+
+ BLI_mempool_destroy(oldpool);
+ }
+}
+
+void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
+{
+ CustomData olddata;
+
+ olddata = *data;
+ olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers): NULL;
+
+ /* the pool is now owned by olddata and must not be shared */
+ data->pool = 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_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name)
+{
+ CustomData olddata;
+
+ olddata = *data;
+ olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers): NULL;
+
+ /* the pool is now owned by olddata and must not be shared */
+ data->pool = 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_data_layer_free(BMesh *bm, CustomData *data, int type)
+{
+ CustomData olddata;
+
+ olddata = *data;
+ olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers): NULL;
+
+ /* the pool is now owned by olddata and must not be shared */
+ data->pool = NULL;
+
+ CustomData_free_layer_active(data, type, 0);
+
+ update_data_blocks(bm, &olddata, data);
+ if (olddata.layers) MEM_freeN(olddata.layers);
+}
+
+void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n)
+{
+ CustomData olddata;
+
+ olddata = *data;
+ olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers): NULL;
+
+ /* the pool is now owned by olddata and must not be shared */
+ data->pool = NULL;
+
+ CustomData_free_layer(data, type, 0, CustomData_get_layer_index_n(data, type, n));
+
+ update_data_blocks(bm, &olddata, data);
+ if (olddata.layers) MEM_freeN(olddata.layers);
+}
+
+float BM_elem_float_data_get(CustomData *cd, void *element, int type)
+{
+ float *f = CustomData_bmesh_get(cd, ((BMHeader *)element)->data, type);
+ return f ? *f : 0.0f;
+}
+
+void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float val)
+{
+ float *f = CustomData_bmesh_get(cd, ((BMHeader *)element)->data, type);
+ if (f) *f = val;
+}
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
new file mode 100644
index 00000000000..0c6ac24f456
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -0,0 +1,417 @@
+/*
+ * ***** 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): Joseph Eagar, Geoffrey Bantle, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_iterators.c
+ * \ingroup bmesh
+ *
+ * Functions to abstract looping over bmesh data structures.
+ *
+ * See: bmesh_iterators_inlin.c too, some functions are here for speed reasons.
+ */
+
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+/*
+ * note, we have BM_vert_at_index/BM_edge_at_index/BM_face_at_index for arrays
+ */
+void *BM_iter_at_index(struct BMesh *bm, const char itype, void *data, int index)
+{
+ BMIter iter;
+ void *val;
+ int i;
+
+ /* sanity check */
+ if (index < 0) {
+ return NULL;
+ }
+
+ val = BM_iter_new(&iter, bm, itype, data);
+
+ i = 0;
+ while (i < index) {
+ val = BM_iter_step(&iter);
+ i++;
+ }
+
+ return val;
+}
+
+
+/*
+ * ITERATOR AS ARRAY
+ *
+ * Sometimes its convenient to get the iterator as an array
+ * to avoid multiple calls to BM_iter_at_index.
+ */
+
+int BM_iter_as_array(struct BMesh *bm, const char type, void *data, void **array, const int len)
+{
+ int i = 0;
+
+ /* sanity check */
+ if (len > 0) {
+
+ BMIter iter;
+ void *val;
+
+ BM_ITER(val, &iter, bm, type, data) {
+ array[i] = val;
+ i++;
+ if (i == len) {
+ return len;
+ }
+ }
+ }
+
+ return i;
+}
+
+
+/*
+ * 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
+ *
+ * The 'bmiter__' prefix is used because these are used in
+ * bmesh_iterators_inine.c but should otherwise be seen as
+ * private.
+ */
+
+/*
+ * VERT OF MESH CALLBACKS
+ *
+ */
+
+void bmiter__vert_of_mesh_begin(BMIter *iter)
+{
+ BLI_mempool_iternew(iter->bm->vpool, &iter->pooliter);
+}
+
+void *bmiter__vert_of_mesh_step(BMIter *iter)
+{
+ return BLI_mempool_iterstep(&iter->pooliter);
+
+}
+
+void bmiter__edge_of_mesh_begin(BMIter *iter)
+{
+ BLI_mempool_iternew(iter->bm->epool, &iter->pooliter);
+}
+
+void *bmiter__edge_of_mesh_step(BMIter *iter)
+{
+ return BLI_mempool_iterstep(&iter->pooliter);
+
+}
+
+void bmiter__face_of_mesh_begin(BMIter *iter)
+{
+ BLI_mempool_iternew(iter->bm->fpool, &iter->pooliter);
+}
+
+void *bmiter__face_of_mesh_step(BMIter *iter)
+{
+ return BLI_mempool_iterstep(&iter->pooliter);
+
+}
+
+/*
+ * EDGE OF VERT CALLBACKS
+ *
+ */
+
+void bmiter__edge_of_vert_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ if (iter->vdata->e) {
+ iter->firstedge = iter->vdata->e;
+ iter->nextedge = iter->vdata->e;
+ }
+}
+
+void *bmiter__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
+ *
+ */
+
+void bmiter__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;
+ }
+}
+void *bmiter__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;
+
+ return current ? current->f : NULL;
+}
+
+
+/*
+ * LOOP OF VERT CALLBACKS
+ *
+ */
+
+void bmiter__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;
+ }
+}
+void *bmiter__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;
+}
+
+
+void bmiter__loops_of_edge_begin(BMIter *iter)
+{
+ BMLoop *l;
+
+ l = iter->edata->l;
+
+ /* note sure why this sets ldata ... */
+ init_iterator(iter);
+
+ iter->firstloop = iter->nextloop = l;
+}
+
+void *bmiter__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;
+}
+
+void bmiter__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);
+
+ if (iter->nextloop == iter->firstloop)
+ iter->nextloop = NULL;
+}
+
+void *bmiter__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
+ *
+ */
+
+void bmiter__face_of_edge_begin(BMIter *iter)
+{
+ init_iterator(iter);
+
+ if (iter->edata->l) {
+ iter->firstloop = iter->edata->l;
+ iter->nextloop = iter->edata->l;
+ }
+}
+
+void *bmiter__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;
+
+ return current ? current->f : NULL;
+}
+
+/*
+ * VERT OF FACE CALLBACKS
+ *
+ */
+
+void bmiter__vert_of_face_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ iter->firstloop = iter->nextloop = BM_FACE_FIRST_LOOP(iter->pdata);
+}
+
+void *bmiter__vert_of_face_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if (iter->nextloop) iter->nextloop = iter->nextloop->next;
+ if (iter->nextloop == iter->firstloop) iter->nextloop = NULL;
+
+ return current ? current->v : NULL;
+}
+
+/*
+ * EDGE OF FACE CALLBACKS
+ *
+ */
+
+void bmiter__edge_of_face_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ iter->firstloop = iter->nextloop = BM_FACE_FIRST_LOOP(iter->pdata);
+}
+
+void *bmiter__edge_of_face_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if (iter->nextloop) iter->nextloop = iter->nextloop->next;
+ if (iter->nextloop == iter->firstloop) iter->nextloop = NULL;
+
+ return current ? current->e : NULL;
+}
+
+/*
+ * LOOP OF FACE CALLBACKS
+ *
+ */
+
+void bmiter__loop_of_face_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ iter->firstloop = iter->nextloop = BM_FACE_FIRST_LOOP(iter->pdata);
+}
+
+void *bmiter__loop_of_face_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if (iter->nextloop) iter->nextloop = iter->nextloop->next;
+ if (iter->nextloop == iter->firstloop) iter->nextloop = NULL;
+
+ return current;
+}
diff --git a/source/blender/bmesh/intern/bmesh_iterators_inline.c b/source/blender/bmesh/intern/bmesh_iterators_inline.c
new file mode 100644
index 00000000000..ef644f96ce0
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_iterators_inline.c
@@ -0,0 +1,160 @@
+/*
+ * ***** 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): Joseph Eagar, Geoffrey Bantle, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_iterators_inline.c
+ * \ingroup bmesh
+ *
+ * BMesh inline iterator functions.
+ */
+
+#ifndef __BMESH_ITERATORS_INLINE_C__
+#define __BMESH_ITERATORS_INLINE_C__
+
+#include "bmesh.h"
+
+/* inline here optimizes out the switch statement when called with
+ * constant values (which is very common), nicer for loop-in-loop situations */
+
+/*
+ * BMESH ITERATOR STEP
+ *
+ * Calls an iterators step fucntion to return
+ * the next element.
+ */
+
+BM_INLINE void *BM_iter_step(BMIter *iter)
+{
+ return iter->step(iter);
+}
+
+
+/*
+ * 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.
+ *
+ */
+BM_INLINE void *BM_iter_new(BMIter *iter, BMesh *bm, const char itype, void *data)
+{
+ /* int argtype; */
+ iter->itype = itype;
+ iter->bm = bm;
+
+ /* inlining optimizes out this switch when called with the defined type */
+ switch (itype) {
+ case BM_VERTS_OF_MESH:
+ iter->begin = bmiter__vert_of_mesh_begin;
+ iter->step = bmiter__vert_of_mesh_step;
+ break;
+ case BM_EDGES_OF_MESH:
+ iter->begin = bmiter__edge_of_mesh_begin;
+ iter->step = bmiter__edge_of_mesh_step;
+ break;
+ case BM_FACES_OF_MESH:
+ iter->begin = bmiter__face_of_mesh_begin;
+ iter->step = bmiter__face_of_mesh_step;
+ break;
+ case BM_EDGES_OF_VERT:
+ if (!data)
+ return NULL;
+
+ iter->begin = bmiter__edge_of_vert_begin;
+ iter->step = bmiter__edge_of_vert_step;
+ iter->vdata = data;
+ break;
+ case BM_FACES_OF_VERT:
+ if (!data)
+ return NULL;
+
+ iter->begin = bmiter__face_of_vert_begin;
+ iter->step = bmiter__face_of_vert_step;
+ iter->vdata = data;
+ break;
+ case BM_LOOPS_OF_VERT:
+ if (!data)
+ return NULL;
+
+ iter->begin = bmiter__loop_of_vert_begin;
+ iter->step = bmiter__loop_of_vert_step;
+ iter->vdata = data;
+ break;
+ case BM_FACES_OF_EDGE:
+ if (!data)
+ return NULL;
+
+ iter->begin = bmiter__face_of_edge_begin;
+ iter->step = bmiter__face_of_edge_step;
+ iter->edata = data;
+ break;
+ case BM_VERTS_OF_FACE:
+ if (!data)
+ return NULL;
+
+ iter->begin = bmiter__vert_of_face_begin;
+ iter->step = bmiter__vert_of_face_step;
+ iter->pdata = data;
+ break;
+ case BM_EDGES_OF_FACE:
+ if (!data)
+ return NULL;
+
+ iter->begin = bmiter__edge_of_face_begin;
+ iter->step = bmiter__edge_of_face_step;
+ iter->pdata = data;
+ break;
+ case BM_LOOPS_OF_FACE:
+ if (!data)
+ return NULL;
+
+ iter->begin = bmiter__loop_of_face_begin;
+ iter->step = bmiter__loop_of_face_step;
+ iter->pdata = data;
+ break;
+ case BM_LOOPS_OF_LOOP:
+ if (!data)
+ return NULL;
+
+ iter->begin = bmiter__loops_of_loop_begin;
+ iter->step = bmiter__loops_of_loop_step;
+ iter->ldata = data;
+ break;
+ case BM_LOOPS_OF_EDGE:
+ if (!data)
+ return NULL;
+
+ iter->begin = bmiter__loops_of_edge_begin;
+ iter->step = bmiter__loops_of_edge_step;
+ iter->edata = data;
+ break;
+ default:
+ break;
+ }
+
+ iter->begin(iter);
+ return BM_iter_step(iter);
+}
+
+
+#endif /* __BMESH_ITERATORS_INLINE_C__ */
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
new file mode 100644
index 00000000000..8a8ccb5efb1
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -0,0 +1,910 @@
+/*
+ * ***** 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): Joseph Eagar, Geoffrey Bantle, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_marking.c
+ * \ingroup bmesh
+ *
+ * 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.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+
+#include "bmesh.h"
+
+
+/*
+ * 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;
+ const char iter_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 = BM_iter_new(&iter, bm, iter_types[i], NULL);
+ for ( ; ele; ele = BM_iter_step(&iter)) {
+ if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) *tots[i] += 1;
+ }
+ }
+}
+
+void BM_mesh_select_mode_flush(BMesh *bm)
+{
+ BMEdge *e;
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ BMFace *f;
+
+ BMIter edges;
+ BMIter faces;
+
+ int ok;
+
+ if (bm->selectmode & SCE_SELECT_VERTEX) {
+ for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
+ if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
+ !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
+ {
+ BM_elem_flag_enable(e, BM_ELEM_SELECT);
+ }
+ else {
+ BM_elem_flag_disable(e, BM_ELEM_SELECT);
+ }
+ }
+ for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
+ ok = TRUE;
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
+ ok = FALSE;
+ break;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ else {
+ ok = FALSE;
+ }
+
+ if (ok) {
+ BM_elem_flag_enable(f, BM_ELEM_SELECT);
+ }
+ else {
+ BM_elem_flag_disable(f, BM_ELEM_SELECT);
+ }
+ }
+ }
+ else if (bm->selectmode & SCE_SELECT_EDGE) {
+ for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
+ ok = TRUE;
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (!BM_elem_flag_test(&(l_iter->e->head), BM_ELEM_SELECT)) {
+ ok = FALSE;
+ break;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ else {
+ ok = FALSE;
+ }
+
+ if (ok) {
+ BM_elem_flag_enable(f, BM_ELEM_SELECT);
+ }
+ else {
+ BM_elem_flag_disable(f, BM_ELEM_SELECT);
+ }
+ }
+ }
+
+ /* Remove any deselected elements from the BMEditSelection */
+ BM_select_history_validate(bm);
+
+ recount_totsels(bm);
+}
+
+/* BMESH NOTE: matches EM_deselect_flush() behavior from trunk */
+void BM_mesh_deselect_flush(BMesh *bm)
+{
+ BMEdge *e;
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ BMFace *f;
+
+ BMIter edges;
+ BMIter faces;
+
+ int ok;
+
+ for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
+ if (!(BM_elem_flag_test(e->v1, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
+ !BM_elem_flag_test(e, BM_ELEM_HIDDEN)))
+ {
+ BM_elem_flag_disable(e, BM_ELEM_SELECT);
+ }
+ }
+
+ for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
+ ok = TRUE;
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
+ ok = FALSE;
+ break;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ else {
+ ok = FALSE;
+ }
+
+ if (ok == FALSE) {
+ BM_elem_flag_disable(f, BM_ELEM_SELECT);
+ }
+ }
+
+ /* Remove any deselected elements from the BMEditSelection */
+ BM_select_history_validate(bm);
+
+ recount_totsels(bm);
+}
+
+
+/* BMESH NOTE: matches EM_select_flush() behavior from trunk */
+void BM_mesh_select_flush(BMesh *bm)
+{
+ BMEdge *e;
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ BMFace *f;
+
+ BMIter edges;
+ BMIter faces;
+
+ int ok;
+
+ for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
+ if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
+ !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
+ {
+ BM_elem_flag_enable(e, BM_ELEM_SELECT);
+ }
+ }
+
+ for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
+ ok = TRUE;
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
+ ok = FALSE;
+ break;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ else {
+ ok = FALSE;
+ }
+
+ if (ok) {
+ BM_elem_flag_enable(f, BM_ELEM_SELECT);
+ }
+ }
+
+ recount_totsels(bm);
+}
+
+/*
+ * BMESH SELECT VERT
+ *
+ * Changes selection state of a single vertex
+ * in a mesh
+ *
+ */
+
+void BM_vert_select_set(BMesh *bm, BMVert *v, int select)
+{
+ /* BMIter iter; */
+ /* BMEdge *e; */
+
+ if (BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ return;
+ }
+
+ if (select) {
+ if (!BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ bm->totvertsel += 1;
+ BM_elem_flag_enable(v, BM_ELEM_SELECT);
+ }
+ }
+ else {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ bm->totvertsel -= 1;
+ BM_elem_flag_disable(v, BM_ELEM_SELECT);
+ }
+ }
+}
+
+/*
+ * BMESH SELECT EDGE
+ *
+ * Changes selection state of a single edge
+ * in a mesh.
+ *
+ */
+
+void BM_edge_select_set(BMesh *bm, BMEdge *e, int select)
+{
+ if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ return;
+ }
+
+ if (select) {
+ if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) bm->totedgesel += 1;
+
+ BM_elem_flag_enable(&(e->head), BM_ELEM_SELECT);
+ BM_elem_select_set(bm, e->v1, TRUE);
+ BM_elem_select_set(bm, e->v2, TRUE);
+ }
+ else {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) bm->totedgesel -= 1;
+ BM_elem_flag_disable(&(e->head), BM_ELEM_SELECT);
+
+ if ( bm->selectmode == SCE_SELECT_EDGE ||
+ bm->selectmode == SCE_SELECT_FACE ||
+ bm->selectmode == (SCE_SELECT_EDGE | SCE_SELECT_FACE))
+ {
+
+ BMIter iter;
+ BMVert *verts[2] = {e->v1, e->v2};
+ BMEdge *e2;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ int deselect = 1;
+
+ for (e2 = BM_iter_new(&iter, bm, BM_EDGES_OF_VERT, verts[i]); e2; e2 = BM_iter_step(&iter)) {
+ if (e2 == e) {
+ continue;
+ }
+
+ if (BM_elem_flag_test(e2, BM_ELEM_SELECT)) {
+ deselect = 0;
+ break;
+ }
+ }
+
+ if (deselect) BM_vert_select_set(bm, verts[i], FALSE);
+ }
+ }
+ else {
+ BM_elem_select_set(bm, e->v1, FALSE);
+ BM_elem_select_set(bm, e->v2, FALSE);
+ }
+
+ }
+}
+
+/*
+ *
+ * BMESH SELECT FACE
+ *
+ * Changes selection state of a single
+ * face in a mesh.
+ *
+ */
+
+void BM_face_select_set(BMesh *bm, BMFace *f, int select)
+{
+ BMLoop *l_iter;
+ BMLoop *l_first;
+
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ return;
+ }
+
+ if (select) {
+ if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ bm->totfacesel++;
+ }
+
+ BM_elem_flag_enable(&(f->head), BM_ELEM_SELECT);
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_vert_select_set(bm, l_iter->v, TRUE);
+ BM_edge_select_set(bm, l_iter->e, TRUE);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ else {
+ BMIter liter;
+ BMLoop *l;
+
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) bm->totfacesel -= 1;
+ BM_elem_flag_disable(&(f->head), BM_ELEM_SELECT);
+
+ /* flush down to edges */
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ BMIter fiter;
+ BMFace *f2;
+ BM_ITER(f2, &fiter, bm, BM_FACES_OF_EDGE, l->e) {
+ if (BM_elem_flag_test(f2, BM_ELEM_SELECT))
+ break;
+ }
+
+ if (!f2)
+ {
+ BM_elem_select_set(bm, l->e, FALSE);
+ }
+ }
+
+ /* flush down to verts */
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ BMIter eiter;
+ BMEdge *e;
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, l->v) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT))
+ break;
+ }
+
+ if (!e) {
+ BM_elem_select_set(bm, l->v, FALSE);
+ }
+ }
+ }
+}
+
+/*
+ * BMESH SELECTMODE SET
+ *
+ * Sets the selection mode for the bmesh
+ *
+ */
+
+void BM_select_mode_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 = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges))
+ BM_elem_flag_disable(e, 0);
+ for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces))
+ BM_elem_flag_disable(f, 0);
+ BM_mesh_select_mode_flush(bm);
+ }
+ else if (bm->selectmode & SCE_SELECT_EDGE) {
+ for (v = BM_iter_new(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BM_iter_step(&verts))
+ BM_elem_flag_disable(v, 0);
+ for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
+ if (BM_elem_flag_test(&(e->head), BM_ELEM_SELECT)) {
+ BM_edge_select_set(bm, e, TRUE);
+ }
+ }
+ BM_mesh_select_mode_flush(bm);
+ }
+ else if (bm->selectmode & SCE_SELECT_FACE) {
+ for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges))
+ BM_elem_flag_disable(e, 0);
+ for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
+ if (BM_elem_flag_test(&(f->head), BM_ELEM_SELECT)) {
+ BM_face_select_set(bm, f, TRUE);
+ }
+ }
+ BM_mesh_select_mode_flush(bm);
+ }
+}
+
+
+int BM_mesh_count_flag(struct BMesh *bm, const char htype, const char hflag, int respecthide)
+{
+ BMHeader *head;
+ BMIter iter;
+ int tot = 0;
+
+ if (htype & BM_VERT) {
+ for (head = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); head; head = BM_iter_step(&iter)) {
+ if (respecthide && BM_elem_flag_test(head, BM_ELEM_HIDDEN)) continue;
+ if (BM_elem_flag_test(head, hflag)) tot++;
+ }
+ }
+ if (htype & BM_EDGE) {
+ for (head = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); head; head = BM_iter_step(&iter)) {
+ if (respecthide && BM_elem_flag_test(head, BM_ELEM_HIDDEN)) continue;
+ if (BM_elem_flag_test(head, hflag)) tot++;
+ }
+ }
+ if (htype & BM_FACE) {
+ for (head = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, NULL); head; head = BM_iter_step(&iter)) {
+ if (respecthide && BM_elem_flag_test(head, BM_ELEM_HIDDEN)) continue;
+ if (BM_elem_flag_test(head, hflag)) tot++;
+ }
+ }
+
+ return tot;
+}
+
+/* note: by design, this will not touch the editselection history stuff */
+void BM_elem_select_set(struct BMesh *bm, void *element, int select)
+{
+ BMHeader *head = element;
+
+ if (head->htype == BM_VERT) BM_vert_select_set(bm, (BMVert *)element, select);
+ else if (head->htype == BM_EDGE) BM_edge_select_set(bm, (BMEdge *)element, select);
+ else if (head->htype == BM_FACE) BM_face_select_set(bm, (BMFace *)element, select);
+}
+
+/* this replaces the active flag used in uv/face mode */
+void BM_active_face_set(BMesh *bm, BMFace *efa)
+{
+ bm->act_face = efa;
+}
+
+BMFace *BM_active_face_get(BMesh *bm, int sloppy)
+{
+ if (bm->act_face) {
+ return bm->act_face;
+ }
+ else if (sloppy) {
+ BMIter iter;
+ BMFace *f = NULL;
+ BMEditSelection *ese;
+
+ /* Find the latest non-hidden face from the BMEditSelection */
+ ese = bm->selected.last;
+ for ( ; ese; ese = ese->prev) {
+ if (ese->htype == BM_FACE) {
+ f = (BMFace *)ese->data;
+
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ f = NULL;
+ }
+ else {
+ break;
+ }
+ }
+ }
+ /* Last attempt: try to find any selected face */
+ if (f == NULL) {
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ break;
+ }
+ }
+ }
+ return f; /* can still be null */
+ }
+ return NULL;
+}
+
+/* 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 *bm, float r_center[3], BMEditSelection *ese)
+{
+ if (ese->htype == BM_VERT) {
+ BMVert *eve = ese->data;
+ copy_v3_v3(r_center, eve->co);
+ }
+ else if (ese->htype == BM_EDGE) {
+ BMEdge *eed = ese->data;
+ add_v3_v3v3(r_center, eed->v1->co, eed->v2->co);
+ mul_v3_fl(r_center, 0.5);
+ }
+ else if (ese->htype == BM_FACE) {
+ BMFace *efa = ese->data;
+ BM_face_center_bounds_calc(bm, efa, r_center);
+ }
+}
+
+void BM_editselection_normal(float r_normal[3], BMEditSelection *ese)
+{
+ if (ese->htype == BM_VERT) {
+ BMVert *eve = ese->data;
+ copy_v3_v3(r_normal, eve->no);
+ }
+ else if (ese->htype == 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(r_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, r_normal, plane);
+ cross_v3_v3v3(r_normal, plane, vec);
+ normalize_v3(r_normal);
+
+ }
+ else if (ese->htype == BM_FACE) {
+ BMFace *efa = ese->data;
+ copy_v3_v3(r_normal, efa->no);
+ }
+}
+
+/* ref - editmesh_lib.cL:EM_editselection_plane() */
+
+/* Calculate a plane that is rightangles to the edge/vert/faces normal
+ * also make the plane run along an axis that is related to the geometry,
+ * because this is used for the manipulators Y axis. */
+void BM_editselection_plane(BMesh *bm, float r_plane[3], BMEditSelection *ese)
+{
+ if (ese->htype == BM_VERT) {
+ BMVert *eve = ese->data;
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+
+ if (ese->prev) { /* use previously selected data to make a useful vertex plane */
+ BM_editselection_center(bm, vec, ese->prev);
+ sub_v3_v3v3(r_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.5f) vec[0] = 1.0f;
+ else if (eve->no[1] < 0.5f) vec[1] = 1.0f;
+ else vec[2] = 1.0f;
+ cross_v3_v3v3(r_plane, eve->no, vec);
+ }
+ }
+ else if (ese->htype == BM_EDGE) {
+ BMEdge *eed = ese->data;
+
+ /* the plane is simple, it runs along 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(r_plane, eed->v2->co, eed->v1->co);
+ }
+ else {
+ sub_v3_v3v3(r_plane, eed->v1->co, eed->v2->co);
+ }
+
+ }
+ else if (ese->htype == 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->len < 3) {
+ /* crappy fallback method */
+ if (efa->no[0] < 0.5f) vec[0] = 1.0f;
+ else if (efa->no[1] < 0.5f) vec[1] = 1.0f;
+ else vec[2] = 1.0f;
+ cross_v3_v3v3(r_plane, efa->no, vec);
+ }
+ else {
+ BMVert *verts[4] = {NULL};
+
+ BM_iter_as_array(bm, BM_VERTS_OF_FACE, efa, (void **)verts, 4);
+
+ if (efa->len == 4) {
+ float vecA[3], vecB[3];
+ sub_v3_v3v3(vecA, verts[3]->co, verts[2]->co);
+ sub_v3_v3v3(vecB, verts[0]->co, verts[1]->co);
+ add_v3_v3v3(r_plane, vecA, vecB);
+
+ sub_v3_v3v3(vecA, verts[0]->co, verts[3]->co);
+ sub_v3_v3v3(vecB, verts[1]->co, verts[2]->co);
+ add_v3_v3v3(vec, vecA, vecB);
+ /* use the biggest edge length */
+ if (dot_v3v3(r_plane, r_plane) < dot_v3v3(vec, vec)) {
+ copy_v3_v3(r_plane, vec);
+ }
+ }
+ else {
+ /* BMESH_TODO (not urgent, use longest ngon edge for alignment) */
+
+ /* start with v1-2 */
+ sub_v3_v3v3(r_plane, verts[0]->co, verts[1]->co);
+
+ /* test the edge between v2-3, use if longer */
+ sub_v3_v3v3(vec, verts[1]->co, verts[2]->co);
+ if (dot_v3v3(r_plane, r_plane) < dot_v3v3(vec, vec))
+ copy_v3_v3(r_plane, vec);
+
+ /* test the edge between v1-3, use if longer */
+ sub_v3_v3v3(vec, verts[2]->co, verts[0]->co);
+ if (dot_v3v3(r_plane, r_plane) < dot_v3v3(vec, vec)) {
+ copy_v3_v3(r_plane, vec);
+ }
+ }
+
+ }
+ }
+ normalize_v3(r_plane);
+}
+
+int BM_select_history_check(BMesh *bm, void *data)
+{
+ BMEditSelection *ese;
+
+ for (ese = bm->selected.first; ese; ese = ese->next) {
+ if (ese->data == data) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+void BM_select_history_remove(BMesh *bm, void *data)
+{
+ BMEditSelection *ese;
+ for (ese = bm->selected.first; ese; ese = ese->next) {
+ if (ese->data == data) {
+ BLI_freelinkN(&(bm->selected), ese);
+ break;
+ }
+ }
+}
+
+void BM_select_history_clear(BMesh *bm)
+{
+ BLI_freelistN(&bm->selected);
+ bm->selected.first = bm->selected.last = NULL;
+}
+
+void BM_select_history_store(BMesh *bm, void *data)
+{
+ BMEditSelection *ese;
+ if (!BM_select_history_check(bm, data)) {
+ ese = (BMEditSelection *) MEM_callocN(sizeof(BMEditSelection), "BMEdit Selection");
+ ese->htype = ((BMHeader *)data)->htype;
+ ese->data = data;
+ BLI_addtail(&(bm->selected), ese);
+ }
+}
+
+void BM_select_history_validate(BMesh *bm)
+{
+ BMEditSelection *ese, *nextese;
+
+ ese = bm->selected.first;
+
+ while (ese) {
+ nextese = ese->next;
+ if (!BM_elem_flag_test(ese->data, BM_ELEM_SELECT)) {
+ BLI_freelinkN(&(bm->selected), ese);
+ }
+ ese = nextese;
+ }
+}
+
+void BM_mesh_elem_flag_disable_all(BMesh *bm, const char htype, const char hflag)
+{
+ const char iter_types[3] = {BM_VERTS_OF_MESH,
+ BM_EDGES_OF_MESH,
+ BM_FACES_OF_MESH};
+ BMIter iter;
+ BMHeader *ele;
+ int i;
+
+ if (hflag & BM_ELEM_SELECT) {
+ BM_select_history_clear(bm);
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (htype & iter_types[i]) {
+ ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
+ for ( ; ele; ele = BM_iter_step(&iter)) {
+ if (hflag & BM_ELEM_SELECT) {
+ BM_elem_select_set(bm, ele, FALSE);
+ }
+ BM_elem_flag_disable(ele, hflag);
+ }
+ }
+ }
+}
+
+void BM_mesh_elem_flag_enable_all(BMesh *bm, const char htype, const char hflag)
+{
+ const char iter_types[3] = {BM_VERTS_OF_MESH,
+ BM_EDGES_OF_MESH,
+ BM_FACES_OF_MESH};
+ BMIter iter;
+ BMHeader *ele;
+ int i;
+
+ if (hflag & BM_ELEM_SELECT) {
+ BM_select_history_clear(bm);
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (htype & iter_types[i]) {
+ ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
+ for ( ; ele; ele = BM_iter_step(&iter)) {
+ if (hflag & BM_ELEM_SELECT) {
+ BM_elem_select_set(bm, ele, TRUE);
+ }
+ BM_elem_flag_enable(ele, hflag);
+ }
+ }
+ }
+}
+
+/***************** Mesh Hiding stuff *********** */
+
+#define BM_ELEM_HIDE_SET(ele, hide) \
+ (hide) ? BM_elem_flag_enable(ele, BM_ELEM_HIDDEN) : BM_elem_flag_disable(ele, BM_ELEM_HIDDEN);
+
+static void vert_flush_hide_set(BMesh *bm, BMVert *v)
+{
+ BMIter iter;
+ BMEdge *e;
+ int hide = TRUE;
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
+ hide = hide && BM_elem_flag_test(e, BM_ELEM_HIDDEN);
+ }
+
+ BM_ELEM_HIDE_SET(v, hide);
+}
+
+static void edge_flush_hide(BMesh *bm, BMEdge *e)
+{
+ BMIter iter;
+ BMFace *f;
+ int hide = TRUE;
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_EDGE, e) {
+ hide = hide && BM_elem_flag_test(f, BM_ELEM_HIDDEN);
+ }
+
+ BM_ELEM_HIDE_SET(e, hide);
+}
+
+void BM_vert_hide_set(BMesh *bm, BMVert *v, int hide)
+{
+ /* vert hiding: vert + surrounding edges and faces */
+ BMIter iter, fiter;
+ BMEdge *e;
+ BMFace *f;
+
+ BM_ELEM_HIDE_SET(v, hide);
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
+ BM_ELEM_HIDE_SET(e, hide);
+
+ BM_ITER(f, &fiter, bm, BM_FACES_OF_EDGE, e) {
+ BM_ELEM_HIDE_SET(f, hide);
+ }
+ }
+}
+
+void BM_edge_hide_set(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) {
+ BM_ELEM_HIDE_SET(f, hide);
+ }
+
+ BM_ELEM_HIDE_SET(e, hide);
+
+ /* hide vertices if necassary */
+ vert_flush_hide_set(bm, e->v1);
+ vert_flush_hide_set(bm, e->v2);
+}
+
+void BM_face_hide_set(BMesh *bm, BMFace *f, int hide)
+{
+ BMIter iter;
+ BMLoop *l;
+
+ BM_ELEM_HIDE_SET(f, hide);
+
+ 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_set(bm, l->v);
+ }
+}
+
+#undef BM_ELEM_HIDE_SET
+
+
+void BM_elem_hide_set(BMesh *bm, void *element, int hide)
+{
+ BMHeader *h = element;
+
+ /* Follow convention of always deselecting before
+ * hiding an element */
+ if (hide) {
+ BM_elem_select_set(bm, element, FALSE);
+ }
+
+ switch (h->htype) {
+ case BM_VERT:
+ BM_vert_hide_set(bm, element, hide);
+ break;
+ case BM_EDGE:
+ BM_edge_hide_set(bm, element, hide);
+ break;
+ case BM_FACE:
+ BM_face_hide_set(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..a432049e238
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -0,0 +1,625 @@
+/*
+ * ***** 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): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_mesh.c
+ * \ingroup bmesh
+ *
+ * BM mesh level functions.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_object_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_tessmesh.h"
+#include "BKE_customdata.h"
+#include "BKE_multires.h"
+
+#include "ED_mesh.h"
+
+#include "bmesh_private.h"
+
+/* used as an extern, defined in bmesh.h */
+int bm_mesh_allocsize_default[4] = {512, 512, 2048, 512};
+
+/* bmesh_error stub */
+void bmesh_error(void)
+{
+ printf("BM modelling error!\n");
+
+ /* This placeholder assert makes modelling errors easier to catch
+ * in the debugger, until bmesh_error is replaced with something
+ * better. */
+ BLI_assert(0);
+}
+
+static void bmesh_mempool_init(BMesh *bm, const int allocsize[4])
+{
+ bm->vpool = BLI_mempool_create(sizeof(BMVert), allocsize[0], allocsize[0], FALSE, TRUE);
+ bm->epool = BLI_mempool_create(sizeof(BMEdge), allocsize[1], allocsize[1], FALSE, TRUE);
+ bm->lpool = BLI_mempool_create(sizeof(BMLoop), allocsize[2], allocsize[2], FALSE, FALSE);
+ bm->fpool = BLI_mempool_create(sizeof(BMFace), allocsize[3], allocsize[3], FALSE, TRUE);
+
+#ifdef USE_BMESH_HOLES
+ bm->looplistpool = BLI_mempool_create(sizeof(BMLoopList), allocsize[3], allocsize[3], FALSE, FALSE);
+#endif
+
+ /* allocate one flag pool that we dont get rid of. */
+ bm->toolflagpool = BLI_mempool_create(sizeof(BMFlagLayer), 512, 512, FALSE, FALSE);
+}
+
+/*
+ * BMESH MAKE MESH
+ *
+ * Allocates a new BMesh structure.
+ * Returns -
+ * Pointer to a BM
+ *
+ */
+
+BMesh *BM_mesh_create(struct Object *ob, const int allocsize[4])
+{
+ /* allocate the structure */
+ BMesh *bm = MEM_callocN(sizeof(BMesh), __func__);
+
+ bm->ob = ob;
+
+ /* allocate the memory pools for the mesh elements */
+ bmesh_mempool_init(bm, allocsize);
+
+ /* allocate one flag pool that we dont get rid of. */
+ bm->stackdepth = 1;
+ bm->totflags = 1;
+
+ return bm;
+}
+
+/*
+ * BMESH FREE MESH
+ *
+ * Frees a BMesh structure.
+ */
+
+void BM_mesh_data_free(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMLoop *l;
+ BMFace *f;
+
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+ BMIter loops;
+
+ for (v = BM_iter_new(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BM_iter_step(&verts)) {
+ CustomData_bmesh_free_block(&(bm->vdata), &(v->head.data));
+ }
+ for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) {
+ CustomData_bmesh_free_block(&(bm->edata), &(e->head.data));
+ }
+ for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) {
+ CustomData_bmesh_free_block(&(bm->pdata), &(f->head.data));
+ for (l = BM_iter_new(&loops, bm, BM_LOOPS_OF_FACE, f); l; l = BM_iter_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);
+
+ /* destroy flag pool */
+ BLI_mempool_destroy(bm->toolflagpool);
+
+#ifdef USE_BMESH_HOLES
+ BLI_mempool_destroy(bm->looplistpool);
+#endif
+
+ /* These tables aren't used yet, so it's not stricly necessary
+ * to 'end' them (with 'e' param) but if someone tries to start
+ * using them, having these in place will save a lot of pain */
+ mesh_octree_table(NULL, NULL, NULL, 'e');
+ mesh_mirrtopo_table(NULL, 'e');
+
+ BLI_freelistN(&bm->selected);
+
+ BMO_error_clear(bm);
+}
+
+void BM_mesh_clear(BMesh *bm)
+{
+ Object *ob = bm->ob;
+
+ /* free old mesh */
+ BM_mesh_data_free(bm);
+ memset(bm, 0, sizeof(BMesh));
+
+ /* re-initialize mesh */
+ bm->ob = ob;
+
+ /* allocate the memory pools for the mesh elements */
+ bmesh_mempool_init(bm, bm_mesh_allocsize_default);
+
+ bm->stackdepth = 1;
+ bm->totflags = 1;
+}
+
+/*
+ * BMESH FREE MESH
+ *
+ * Frees a BMesh structure.
+ */
+
+void BM_mesh_free(BMesh *bm)
+{
+ BM_mesh_data_free(bm);
+ MEM_freeN(bm);
+}
+
+/*
+ * BMESH COMPUTE NORMALS
+ *
+ * Updates the normals of a mesh.
+ * Note that this can only be called
+ *
+ */
+
+void BM_mesh_normals_update(BMesh *bm)
+{
+ BMVert *v;
+ BMFace *f;
+ BMLoop *l;
+ BMEdge *e;
+ BMIter verts;
+ BMIter faces;
+ BMIter loops;
+ BMIter edges;
+ unsigned int maxlength = 0;
+ int index;
+ float (*projectverts)[3];
+ float (*edgevec)[3];
+
+ /* first, find out the largest face in mesh */
+ BM_ITER(f, &faces, bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(f, BM_ELEM_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_elem_flag_test(f, BM_ELEM_HIDDEN))
+ continue;
+#if 0 /* UNUSED */
+ if (f->head.flag & BM_NONORMCALC)
+ continue;
+#endif
+
+ bmesh_update_face_normal(bm, f, f->no, projectverts);
+ }
+
+ /* Zero out vertex normals */
+ BM_ITER(v, &verts, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(v, BM_ELEM_HIDDEN))
+ continue;
+
+ zero_v3(v->no);
+ }
+
+ /* compute normalized direction vectors for each edge. directions will be
+ * used below for calculating the weights of the face normals on the vertex
+ * normals */
+ index = 0;
+ edgevec = MEM_callocN(sizeof(float) * 3 * bm->totedge, "BM normal computation array");
+ BM_ITER(e, &edges, bm, BM_EDGES_OF_MESH, NULL) {
+ BM_elem_index_set(e, index); /* set_inline */
+
+ if (e->l) {
+ sub_v3_v3v3(edgevec[index], e->v2->co, e->v1->co);
+ normalize_v3(edgevec[index]);
+ }
+ else {
+ /* the edge vector will not be needed when the edge has no radial */
+ }
+
+ index++;
+ }
+ bm->elem_index_dirty &= ~BM_EDGE;
+
+ /* add weighted face normals to vertices */
+ BM_ITER(f, &faces, bm, BM_FACES_OF_MESH, NULL) {
+
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN))
+ continue;
+
+ BM_ITER(l, &loops, bm, BM_LOOPS_OF_FACE, f) {
+ float *e1diff, *e2diff;
+ float dotprod;
+ float fac;
+
+ /* calculate the dot product of the two edges that
+ * meet at the loop's vertex */
+ e1diff = edgevec[BM_elem_index_get(l->prev->e)];
+ e2diff = edgevec[BM_elem_index_get(l->e)];
+ dotprod = dot_v3v3(e1diff, e2diff);
+
+ /* edge vectors are calculated from e->v1 to e->v2, so
+ * adjust the dot product if one but not both loops
+ * actually runs from from e->v2 to e->v1 */
+ if ((l->prev->e->v1 == l->prev->v) ^ (l->e->v1 == l->v)) {
+ dotprod = -dotprod;
+ }
+
+ fac = saacos(-dotprod);
+
+ /* accumulate weighted face normal into the vertex's normal */
+ madd_v3_v3fl(l->v->no, f->no, fac);
+ }
+ }
+
+ /* normalize the accumulated vertex normals */
+ BM_ITER(v, &verts, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(v, BM_ELEM_HIDDEN))
+ continue;
+
+ if (normalize_v3(v->no) == 0.0f) {
+ normalize_v3_v3(v->no, v->co);
+ }
+ }
+
+ MEM_freeN(edgevec);
+ MEM_freeN(projectverts);
+}
+
+/*
+ This function ensures correct normals for the mesh, but
+ sets the flag BM_ELEM_TAG in flipped faces, to allow restoration
+ of original normals.
+
+ if undo is 0: calculate right normals
+ if undo is 1: restore original normals
+ */
+//keep in sycn with utils.c!
+#define FACE_FLIP 8
+static void bmesh_rationalize_normals(BMesh *bm, int undo)
+{
+ BMOperator bmop;
+ BMFace *f;
+ BMIter iter;
+
+ if (undo) {
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
+ BM_face_normal_flip(bm, f);
+ }
+ BM_elem_flag_disable(f, BM_ELEM_TAG);
+ }
+
+ return;
+ }
+
+ BMO_op_initf(bm, &bmop, "righthandfaces faces=%af doflip=%d", FALSE);
+
+ BMO_push(bm, &bmop);
+ bmesh_righthandfaces_exec(bm, &bmop);
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (BMO_elem_flag_test(bm, f, FACE_FLIP))
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
+ else BM_elem_flag_disable(f, BM_ELEM_TAG);
+ }
+
+ BMO_pop(bm);
+ BMO_op_finish(bm, &bmop);
+}
+
+static void bmesh_set_mdisps_space(BMesh *bm, int from, int to)
+{
+ /* switch multires data out of tangent space */
+ if (CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
+ Object *ob = bm->ob;
+ BMEditMesh *em = BMEdit_Create(bm, FALSE);
+ DerivedMesh *dm = CDDM_from_BMEditMesh(em, NULL, TRUE, FALSE);
+ MDisps *mdisps;
+ BMFace *f;
+ BMIter iter;
+ // int i = 0; // UNUSED
+
+ multires_set_space(dm, ob, from, to);
+
+ mdisps = CustomData_get_layer(&dm->loopData, CD_MDISPS);
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ MDisps *lmd = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MDISPS);
+
+ if (!lmd->disps) {
+ printf("%s: warning - 'lmd->disps' == NULL\n", __func__);
+ }
+
+ if (lmd->disps && lmd->totdisp == mdisps->totdisp) {
+ memcpy(lmd->disps, mdisps->disps, sizeof(float) * 3 * lmd->totdisp);
+ }
+ else if (mdisps->disps) {
+ if (lmd->disps)
+ MEM_freeN(lmd->disps);
+
+ lmd->disps = MEM_dupallocN(mdisps->disps);
+ lmd->totdisp = mdisps->totdisp;
+ }
+
+ mdisps++;
+ // i += 1;
+ }
+ }
+
+ dm->needsFree = 1;
+ dm->release(dm);
+
+ /* setting this to NULL prevents BMEdit_Free from freeing it */
+ em->bm = NULL;
+ BMEdit_Free(em);
+ MEM_freeN(em);
+ }
+}
+
+/*
+ * 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.
+ */
+void bmesh_begin_edit(BMesh *bm, int flag)
+{
+ bm->opflag = flag;
+
+ /* Most operators seem to be using BMO_OP_FLAG_UNTAN_MULTIRES to change the MDisps to
+ * absolute space during mesh edits. With this enabled, changes to the topology
+ * (loop cuts, edge subdivides, etc) are not reflected in the higher levels of
+ * the mesh at all, which doesn't seem right. Turning off completely for now,
+ * until this is shown to be better for certain types of mesh edits. */
+#if BMOP_UNTAN_MULTIRES_ENABLED
+ /* switch multires data out of tangent space */
+ if ((flag & BMO_OP_FLAG_UNTAN_MULTIRES) && CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
+ bmesh_set_mdisps_space(bm, MULTIRES_SPACE_TANGENT, MULTIRES_SPACE_ABSOLUTE);
+
+ /* ensure correct normals, if possible */
+ bmesh_rationalize_normals(bm, 0);
+ BM_mesh_normals_update(bm);
+ }
+ else if (flag & BMO_OP_FLAG_RATIONALIZE_NORMALS) {
+ bmesh_rationalize_normals(bm, 0);
+ }
+#else
+ if (flag & BMO_OP_FLAG_RATIONALIZE_NORMALS) {
+ bmesh_rationalize_normals(bm, 0);
+ }
+#endif
+}
+
+void bmesh_end_edit(BMesh *bm, int flag)
+{
+ /* BMO_OP_FLAG_UNTAN_MULTIRES disabled for now, see comment above in bmesh_begin_edit. */
+#if BMOP_UNTAN_MULTIRES_ENABLED
+ /* switch multires data into tangent space */
+ if ((flag & BMO_OP_FLAG_UNTAN_MULTIRES) && CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
+ /* set normals to their previous winding */
+ bmesh_rationalize_normals(bm, 1);
+ bmesh_set_mdisps_space(bm, MULTIRES_SPACE_ABSOLUTE, MULTIRES_SPACE_TANGENT);
+ }
+ else if (flag & BMO_OP_FLAG_RATIONALIZE_NORMALS) {
+ bmesh_rationalize_normals(bm, 1);
+ }
+#else
+ if (flag & BMO_OP_FLAG_RATIONALIZE_NORMALS) {
+ bmesh_rationalize_normals(bm, 1);
+ }
+#endif
+
+ bm->opflag = 0;
+
+ /* compute normals, clear temp flags and flush selections */
+ BM_mesh_normals_update(bm);
+ BM_mesh_select_mode_flush(bm);
+}
+
+void BM_mesh_elem_index_ensure(BMesh *bm, const char hflag)
+{
+ BMIter iter;
+ BMHeader *ele;
+
+#ifdef DEBUG
+ BM_ELEM_INDEX_VALIDATE(bm, "Should Never Fail!", __func__);
+#endif
+
+ if (hflag & BM_VERT) {
+ if (bm->elem_index_dirty & BM_VERT) {
+ int index = 0;
+ BM_ITER(ele, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BM_elem_index_set(ele, index); /* set_ok */
+ index++;
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+ BLI_assert(index == bm->totvert);
+ }
+ else {
+ // printf("%s: skipping vert index calc!\n", __func__);
+ }
+ }
+
+ if (hflag & BM_EDGE) {
+ if (bm->elem_index_dirty & BM_EDGE) {
+ int index = 0;
+ BM_ITER(ele, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ BM_elem_index_set(ele, index); /* set_ok */
+ index++;
+ }
+ bm->elem_index_dirty &= ~BM_EDGE;
+ BLI_assert(index == bm->totedge);
+ }
+ else {
+ // printf("%s: skipping edge index calc!\n", __func__);
+ }
+ }
+
+ if (hflag & BM_FACE) {
+ if (bm->elem_index_dirty & BM_FACE) {
+ int index = 0;
+ BM_ITER(ele, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BM_elem_index_set(ele, index); /* set_ok */
+ index++;
+ }
+ bm->elem_index_dirty &= ~BM_FACE;
+ BLI_assert(index == bm->totface);
+ }
+ else {
+ // printf("%s: skipping face index calc!\n", __func__);
+ }
+ }
+}
+
+
+/* array checking/setting macros */
+/* currently vert/edge/loop/face index data is being abused, but we should
+ * eventually be able to rely on it being valid. To this end, there are macros
+ * that validate them (so blender doesnt crash), but also print errors so we can
+ * fix the offending parts of the code, this way after some months we can
+ * confine this code for debug mode.
+ *
+ *
+ */
+
+void BM_mesh_elem_index_validate(BMesh *bm, const char *location, const char *func,
+ const char *msg_a, const char *msg_b)
+{
+ const char iter_types[3] = {BM_VERTS_OF_MESH,
+ BM_EDGES_OF_MESH,
+ BM_FACES_OF_MESH};
+
+ const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
+ const char *type_names[3] = {"vert", "edge", "face"};
+
+ BMIter iter;
+ BMHeader *ele;
+ int i;
+ int is_any_error = 0;
+
+ for (i = 0; i < 3; i++) {
+ const int is_dirty = (flag_types[i] & bm->elem_index_dirty);
+ int index = 0;
+ int is_error = FALSE;
+ int err_val = 0;
+ int err_idx = 0;
+
+ BM_ITER(ele, &iter, bm, iter_types[i], NULL) {
+ if (!is_dirty) {
+ if (BM_elem_index_get(ele) != index) {
+ err_val = BM_elem_index_get(ele);
+ err_idx = index;
+ is_error = TRUE;
+ }
+ }
+
+ BM_elem_index_set(ele, index); /* set_ok */
+ index++;
+ }
+
+ if ((is_error == TRUE) && (is_dirty == FALSE)) {
+ is_any_error = TRUE;
+ fprintf(stderr,
+ "Invalid Index: at %s, %s, %s[%d] invalid index %d, '%s', '%s'\n",
+ location, func, type_names[i], err_idx, err_val, msg_a, msg_b);
+ }
+ else if ((is_error == FALSE) && (is_dirty == TRUE)) {
+
+#if 0 /* mostly annoying */
+
+ /* dirty may have been incorrectly set */
+ fprintf(stderr,
+ "Invalid Dirty: at %s, %s (%s), dirty flag was set but all index values are correct, '%s', '%s'\n",
+ location, func, type_names[i], msg_a, msg_b);
+#endif
+ }
+ }
+
+#if 0 /* mostly annoying, even in debug mode */
+#ifdef DEBUG
+ if (is_any_error == 0) {
+ fprintf(stderr,
+ "Valid Index Success: at %s, %s, '%s', '%s'\n",
+ location, func, msg_a, msg_b);
+ }
+#endif
+#endif
+ (void) is_any_error; /* shut up the compiler */
+
+}
+
+BMVert *BM_vert_at_index(BMesh *bm, const int index)
+{
+ return BLI_mempool_findelem(bm->vpool, index);
+}
+
+BMEdge *BM_edge_at_index(BMesh *bm, const int index)
+{
+ return BLI_mempool_findelem(bm->epool, index);
+}
+
+BMFace *BM_face_at_index(BMesh *bm, const int index)
+{
+ return BLI_mempool_findelem(bm->fpool, index);
+}
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
new file mode 100644
index 00000000000..246c8a4655b
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -0,0 +1,769 @@
+/*
+ * ***** 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): Joseph Eagar, Geoffrey Bantle, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_mods.c
+ * \ingroup bmesh
+ *
+ * This file contains functions for locally modifying
+ * the topology of existing mesh data. (split, join, flip etc).
+ */
+
+#include "MEM_guardedalloc.h"
+
+
+#include "BLI_math.h"
+#include "BLI_array.h"
+#include "BLI_smallhash.h"
+
+#include "BKE_customdata.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+/**
+ * bmesh_dissolve_disk
+ *
+ * Turns the face region surrounding a manifold vertex into
+ * A single polygon.
+ *
+ *
+ * Example:
+ *
+ * |=========| |=========|
+ * | \ / | | |
+ * Before: | V | After: | |
+ * | / \ | | |
+ * |=========| |=========|
+ *
+ *
+ */
+#if 1
+int BM_vert_dissolve(BMesh *bm, BMVert *v)
+{
+ BMIter iter;
+ BMEdge *e;
+ int len = 0;
+
+ if (!v) {
+ return FALSE;
+ }
+
+ e = BM_iter_new(&iter, bm, BM_EDGES_OF_VERT, v);
+ for ( ; e; e = BM_iter_step(&iter)) {
+ len++;
+ }
+
+ if (len == 1) {
+ if (v->e)
+ BM_edge_kill(bm, v->e);
+ BM_vert_kill(bm, v);
+ return TRUE;
+ }
+
+ if (!BM_vert_is_manifold(bm, v)) {
+ if (!v->e) BM_vert_kill(bm, v);
+ else if (!v->e->l) {
+ BM_edge_kill(bm, v->e);
+ BM_vert_kill(bm, v);
+ }
+ else {
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ return BM_disk_dissolve(bm, v);
+}
+
+int BM_disk_dissolve(BMesh *bm, BMVert *v)
+{
+ BMFace *f, *f2;
+ BMEdge *e, *keepedge = NULL, *baseedge = NULL;
+ int len = 0;
+
+ if (!BM_vert_is_manifold(bm, v)) {
+ return FALSE;
+ }
+
+ if (v->e) {
+ /* v->e we keep, what else */
+ e = v->e;
+ 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. . */
+ BMLoop *loop = e->l;
+ if (loop->v == v) loop = loop->next;
+ if (!BM_face_split(bm, loop->f, v, loop->v, NULL, NULL))
+ return FALSE;
+
+ if (!BM_disk_dissolve(bm, v)) {
+ return FALSE;
+ }
+ return TRUE;
+ }
+ else if (keepedge == NULL && len == 2) {
+ /* collapse the verte */
+ e = BM_vert_collapse_faces(bm, v->e, v, 1.0, TRUE);
+
+ if (!e) {
+ return FALSE;
+ }
+
+ /* handle two-valenc */
+ f = e->l->f;
+ f2 = e->l->radial_next->f;
+
+ if (f != f2 && !BM_faces_join_pair(bm, f, f2, e)) {
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ if (keepedge) {
+ int 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_faces_join_pair(bm, e->l->f, 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 FALSE;
+ }
+ }
+
+ if (f) {
+ done = 0;
+ break;
+ }
+ e = bmesh_disk_nextedge(e, v);
+ } while (e != v->e);
+ }
+
+ /* collapse the verte */
+ e = BM_vert_collapse_faces(bm, baseedge, v, 1.0, TRUE);
+
+ if (!e) {
+ return FALSE;
+ }
+
+ /* get remaining two face */
+ f = e->l->f;
+ f2 = e->l->radial_next->f;
+
+ if (f != f2) {
+ /* join two remaining face */
+ if (!BM_faces_join_pair(bm, f, f2, e)) {
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+#else
+void BM_disk_dissolve(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 dissolv */
+ for (e = BM_iter_new(&iter, bm, BM_EDGES_OF_VERT, v); e;
+ e = BM_iter_step(&iter)) {
+ f = NULL;
+ len = bmesh_cycle_length(&(e->l->radial));
+ if (len == 2) {
+ f = BM_faces_join_pair(bm, e->l->f, ((BMLoop *)(e->l->radial_next))->f, e);
+ }
+ if (f) {
+ done = 0;
+ break;
+ }
+ };
+ }
+ BM_vert_collapse_faces(bm, v->e, v, 1.0, TRUE);
+ }
+}
+#endif
+
+/**
+ * BM_faces_join_pair
+ *
+ * Joins two adjacenct faces togather.
+ *
+ * Because this method calls to BM_faces_join to do its work, ff a pair
+ * of faces share multiple edges, the pair of faces will be joined at
+ * every edge (not just edge e). This part of the functionality might need
+ * to be reconsidered.
+ *
+ * If the windings do not match the winding of the new face will follow
+ * f1's winding (i.e. f2 will be reversed before the join).
+ *
+ * Returns:
+ * pointer to the combined face
+ */
+
+BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
+{
+ BMLoop *l1, *l2;
+ BMEdge *jed = NULL;
+ BMFace *faces[2] = {f1, f2};
+
+ jed = e;
+ if (!jed) {
+ BMLoop *l_first;
+ /* search for an edge that has both these faces in its radial cycl */
+ l1 = l_first = BM_FACE_FIRST_LOOP(f1);
+ do {
+ if (l1->radial_next->f == f2) {
+ jed = l1->e;
+ break;
+ }
+ } while ((l1 = l1->next) != l_first);
+ }
+
+ 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_faces_join(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_verts_connect(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf)
+{
+ BMIter iter, iter2;
+ BMVert *v;
+ BMLoop *nl;
+ BMFace *face;
+
+ /* be warned: this can do weird things in some ngon situation, see BM_LegalSplit */
+ for (face = BM_iter_new(&iter, bm, BM_FACES_OF_VERT, v1); face; face = BM_iter_step(&iter)) {
+ for (v = BM_iter_new(&iter2, bm, BM_VERTS_OF_FACE, face); v; v = BM_iter_step(&iter2)) {
+ if (v == v2) {
+ face = BM_face_split(bm, face, v1, v2, &nl, NULL);
+
+ if (nf) *nf = face;
+ return nl->e;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * BM_face_split
+ *
+ * Splits a single face into two.
+ *
+ * f - the original face
+ * v1 & v2 - vertices which define the split edge, must be different
+ * nl - pointer which will receive the BMLoop for the split edge in the new face
+ *
+ * Notes: the
+
+ * Returns -
+ * Pointer to the newly created face representing one side of the split
+ * if the split is successful (and the original original face will be the
+ * other side). NULL if the split fails.
+ *
+ */
+
+BMFace *BM_face_split(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **nl, BMEdge *UNUSED(example))
+{
+ const int has_mdisp = CustomData_has_layer(&bm->ldata, CD_MDISPS);
+ BMFace *nf, *of;
+
+ /* do we have a multires layer */
+ if (has_mdisp) {
+ of = BM_face_copy(bm, f, 0, 0);
+ }
+
+#ifdef USE_BMESH_HOLES
+ nf = bmesh_sfme(bm, f, v1, v2, nl, NULL);
+#else
+ nf = bmesh_sfme(bm, f, v1, v2, nl);
+#endif
+
+ if (nf) {
+ BM_elem_attrs_copy(bm, bm, f, nf);
+ copy_v3_v3(nf->no, f->no);
+
+ /* handle multires update */
+ if (has_mdisp && (nf != f)) {
+ BMLoop *l_iter;
+ BMLoop *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_loop_interp_from_face(bm, l_iter, of, FALSE, TRUE);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(nf);
+ do {
+ BM_loop_interp_from_face(bm, l_iter, of, FALSE, TRUE);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ BM_face_kill(bm, of);
+
+ BM_face_multires_bounds_smooth(bm, f);
+ BM_face_multires_bounds_smooth(bm, nf);
+ }
+ }
+
+ return nf;
+}
+
+/**
+ * BM_vert_collapse_faces
+ *
+ * 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.
+ *
+ * Note this function is very close to 'BM_vert_collapse_edges', both collapse
+ * a vertex and return a new edge. Except this takes a factor and merges
+ * custom data.
+ *
+ * BMESH_TODO:
+ * Insert error checking for KV valance.
+ *
+ * @param fac The factor along the edge
+ * @param join_faces When true the faces around the vertex will be joined
+ * otherwise collapse the vertex by merging the 2 edges this vert touches into one.
+ * @returns The New Edge
+ */
+
+BMEdge *BM_vert_collapse_faces(BMesh *bm, BMEdge *ke, BMVert *kv, float fac, const int join_faces)
+{
+ BMEdge *ne = NULL;
+ BMVert *tv = bmesh_edge_getothervert(ke, kv);
+
+ BMEdge *e2;
+ BMVert *tv2;
+
+ BMIter iter;
+ BMLoop *l_iter = NULL, *kvloop = NULL, *tvloop = NULL;
+
+ void *src[2];
+ float w[2];
+
+ /* Only intended to be called for 2-valence vertices */
+ BLI_assert(bmesh_disk_count(kv) <= 2);
+
+
+ /* first modify the face loop data */
+ w[0] = 1.0f - fac;
+ w[1] = fac;
+
+ if (ke->l) {
+ l_iter = ke->l;
+ do {
+ if (l_iter->v == tv && l_iter->next->v == kv) {
+ tvloop = l_iter;
+ kvloop = l_iter->next;
+
+ src[0] = kvloop->head.data;
+ src[1] = tvloop->head.data;
+ CustomData_bmesh_interp(&bm->ldata, src, w, NULL, 2, kvloop->head.data);
+ }
+ } while ((l_iter = l_iter->radial_next) != ke->l);
+ }
+
+ /* now interpolate the vertex data */
+ BM_data_interp_from_verts(bm, kv, tv, kv, fac);
+
+ e2 = bmesh_disk_nextedge(ke, kv);
+ tv2 = BM_edge_other_vert(e2, kv);
+
+ if (join_faces) {
+ BMFace **faces = NULL, *f;
+ BLI_array_staticdeclare(faces, 8);
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_VERT, kv) {
+ BLI_array_append(faces, f);
+ }
+
+ if (BLI_array_count(faces) >= 2) {
+ BMFace *f2 = BM_faces_join(bm, faces, BLI_array_count(faces));
+ if (f2) {
+ BMLoop *nl = NULL;
+ if (BM_face_split(bm, f2, tv, tv2, &nl, NULL)) {
+ ne = nl->e;
+ }
+ }
+ }
+
+ BLI_array_free(faces);
+
+ return ne;
+ }
+
+ /* single face or no faces */
+ /* same as BM_vert_collapse_edges() however we already
+ * have vars to perform this operation so dont call. */
+ bmesh_jekv(bm, ke, kv);
+ ne = BM_edge_exists(tv, tv2);
+
+ return ne;
+}
+
+
+/**
+ * BM_vert_collapse_edges
+ *
+ * Collapses a vertex onto another vertex it shares an edge with.
+ *
+ * Returns -
+ * The New Edge
+ */
+
+BMEdge *BM_vert_collapse_edges(BMesh *bm, BMEdge *ke, BMVert *kv)
+{
+ /* nice example implimentation but we want loops to have their customdata
+ * accounted for */
+#if 0
+ BMEdge *ne = NULL;
+
+ /* Collapse between 2 edges */
+
+ /* in this case we want to keep all faces and not join them,
+ * rather just get rid of the veretex - see bug [#28645] */
+ BMVert *tv = bmesh_edge_getothervert(ke, kv);
+ if (tv) {
+ BMEdge *e2 = bmesh_disk_nextedge(ke, kv);
+ if (e2) {
+ BMVert *tv2 = BM_edge_other_vert(e2, kv);
+ if (tv2) {
+ /* only action, other calls here only get the edge to return */
+ bmesh_jekv(bm, ke, kv);
+
+ ne = BM_edge_exists(tv, tv2);
+ }
+ }
+ }
+
+ return ne;
+#else
+ /* with these args faces are never joined, same as above
+ * but account for loop customdata */
+ return BM_vert_collapse_faces(bm, ke, kv, 1.0f, FALSE);
+#endif
+}
+
+#undef DO_V_INTERP
+
+/**
+ * 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_edge_split(BMesh *bm, BMVert *v, BMEdge *e, BMEdge **ne, float percent)
+{
+ BMVert *nv, *v2;
+ BMFace **oldfaces = NULL;
+ BMEdge *dummy;
+ BLI_array_staticdeclare(oldfaces, 32);
+ SmallHash hash;
+
+ /* we need this for handling multire */
+ if (!ne)
+ ne = &dummy;
+
+ /* do we have a multires layer */
+ if (CustomData_has_layer(&bm->ldata, CD_MDISPS) && e->l) {
+ BMLoop *l;
+ int i;
+
+ l = e->l;
+ do {
+ BLI_array_append(oldfaces, l->f);
+ l = l->radial_next;
+ } while (l != e->l);
+
+ /* create a hash so we can differentiate oldfaces from new face */
+ BLI_smallhash_init(&hash);
+
+ for (i = 0; i < BLI_array_count(oldfaces); i++) {
+ oldfaces[i] = BM_face_copy(bm, oldfaces[i], 1, 1);
+ BLI_smallhash_insert(&hash, (intptr_t)oldfaces[i], NULL);
+ }
+ }
+
+ 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);
+ madd_v3_v3v3fl(nv->co, v->co, nv->co, percent);
+
+ if (ne) {
+ (*ne)->head.hflag = e->head.hflag;
+ BM_elem_attrs_copy(bm, bm, e, *ne);
+ }
+
+ /* v->nv->v2 */
+ BM_data_interp_face_vert_edge(bm, v2, v, nv, e, percent);
+ BM_data_interp_from_verts(bm, v, v2, nv, percent);
+
+ if (CustomData_has_layer(&bm->ldata, CD_MDISPS) && e->l && nv) {
+ int i, j;
+
+ /* interpolate new/changed loop data from copied old face */
+ for (j = 0; j < 2; j++) {
+ for (i = 0; i < BLI_array_count(oldfaces); i++) {
+ BMEdge *e1 = j ? *ne : e;
+ BMLoop *l, *l2;
+
+ l = e1->l;
+ if (!l) {
+ bmesh_error();
+ break;
+ }
+
+ do {
+ if (!BLI_smallhash_haskey(&hash, (intptr_t)l->f)) {
+ BMLoop *l2_first;
+
+ l2 = l2_first = BM_FACE_FIRST_LOOP(l->f);
+ do {
+ BM_loop_interp_multires(bm, l2, oldfaces[i]);
+ } while ((l2 = l2->next) != l2_first);
+ }
+ l = l->radial_next;
+ } while (l != e1->l);
+ }
+ }
+
+ /* destroy the old face */
+ for (i = 0; i < BLI_array_count(oldfaces); i++) {
+ BM_face_verts_kill(bm, oldfaces[i]);
+ }
+
+ /* fix boundaries a bit, doesn't work too well quite ye */
+#if 0
+ for (j = 0; j < 2; j++) {
+ BMEdge *e1 = j ? *ne : e;
+ BMLoop *l, *l2;
+
+ l = e1->l;
+ if (!l) {
+ bmesh_error();
+ break;
+ }
+
+ do {
+ BM_face_multires_bounds_smooth(bm, l->f);
+ l = l->radial_next;
+ } while (l != e1->l);
+ }
+#endif
+
+ BLI_array_free(oldfaces);
+ BLI_smallhash_release(&hash);
+ }
+
+ return nv;
+}
+
+BMVert *BM_edge_split_n(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_edge_split(bm, e->v2, e, NULL, percent);
+ }
+ return nv;
+}
+
+int BM_face_validate(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 = BM_iter_new(&iter, bm, BM_LOOPS_OF_FACE, face); l; l = BM_iter_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_edge_rotate(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_face_count(e) != 2)
+ return NULL;
+
+ /* If either of e's vertices has valence 2, then
+ * dissolving the edge would leave a spur, so not allowed */
+ if (BM_vert_edge_count(e->v1) == 2 || BM_vert_edge_count(e->v2) == 2)
+ return NULL;
+
+ f = BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e);
+
+ if (f == NULL)
+ return NULL;
+
+ 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 = l1->prev;
+ l2 = l2->prev;
+ }
+ else {
+ l1 = l1->next;
+ l2 = l2->next;
+ }
+
+ if (!BM_face_split(bm, f, l1->v, l2->v, &nl, NULL))
+ return NULL;
+
+ return nl->e;
+}
+
+BMVert *BM_vert_rip ( BMesh *bm, BMFace *sf, BMVert *sv)
+{
+ return bmesh_urmv(bm, sf, sv);
+}
diff --git a/source/blender/bmesh/intern/bmesh_newcore.c b/source/blender/bmesh/intern/bmesh_newcore.c
new file mode 100644
index 00000000000..47b8536b3df
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_newcore.c
@@ -0,0 +1,2024 @@
+/*
+ * ***** 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): Joseph Eagar, Geoffrey Bantle, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_newcore.c
+ * \ingroup bmesh
+ *
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math_vector.h"
+
+#include "BKE_DerivedMesh.h"
+
+#include "BLI_listbase.h"
+#include "BLI_array.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+/* use so valgrinds memcheck alerts us when undefined index is used.
+ * TESTING ONLY! */
+// #define USE_DEBUG_INDEX_MEMCHECK
+
+#ifdef USE_DEBUG_INDEX_MEMCHECK
+#define DEBUG_MEMCHECK_INDEX_INVALIDATE(ele) \
+ { \
+ int undef_idx; \
+ BM_elem_index_set(ele, undef_idx); /* set_ok_invalid */ \
+ } \
+
+#endif
+
+BMVert *BM_vert_create(BMesh *bm, const float co[3], const struct BMVert *example)
+{
+ BMVert *v = BLI_mempool_calloc(bm->vpool);
+
+#ifdef USE_DEBUG_INDEX_MEMCHECK
+ DEBUG_MEMCHECK_INDEX_INVALIDATE(v)
+#else
+ BM_elem_index_set(v, -1); /* set_ok_invalid */
+#endif
+
+ bm->elem_index_dirty |= BM_VERT; /* may add to middle of the pool */
+
+ bm->totvert++;
+
+ v->head.htype = BM_VERT;
+
+ /* 'v->no' is handled by BM_elem_attrs_copy */
+ if (co) copy_v3_v3(v->co, co);
+
+ /* allocate flag */
+ v->oflags = BLI_mempool_calloc(bm->toolflagpool);
+
+ CustomData_bmesh_set_default(&bm->vdata, &v->head.data);
+
+ if (example) {
+ BM_elem_attrs_copy(bm, bm, (BMVert *)example, (BMVert *)v);
+ }
+
+ BM_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_exists(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_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *example, int nodouble)
+{
+ BMEdge *e;
+
+ if (nodouble && (e = BM_edge_exists(v1, v2)))
+ return (BMEdge *)e;
+
+ e = BLI_mempool_calloc(bm->epool);
+
+#ifdef USE_DEBUG_INDEX_MEMCHECK
+ DEBUG_MEMCHECK_INDEX_INVALIDATE(e)
+#else
+ BM_elem_index_set(e, -1); /* set_ok_invalid */
+#endif
+
+ bm->elem_index_dirty |= BM_EDGE; /* may add to middle of the pool */
+
+ bm->totedge++;
+
+ e->head.htype = BM_EDGE;
+
+ /* allocate flag */
+ e->oflags = BLI_mempool_calloc(bm->toolflagpool);
+
+ e->v1 = (BMVert *) v1;
+ e->v2 = (BMVert *) v2;
+
+
+ CustomData_bmesh_set_default(&bm->edata, &e->head.data);
+
+ bmesh_disk_append_edge(e, e->v1);
+ bmesh_disk_append_edge(e, e->v2);
+
+ if (example)
+ BM_elem_attrs_copy(bm, bm, (BMEdge *)example, (BMEdge *)e);
+
+ BM_CHECK_ELEMENT(bm, e);
+
+ return (BMEdge *) e;
+}
+
+static BMLoop *bmesh_create_loop(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f, const BMLoop *example)
+{
+ BMLoop *l = NULL;
+
+ l = BLI_mempool_calloc(bm->lpool);
+ l->next = l->prev = NULL;
+ l->v = v;
+ l->e = e;
+ l->f = f;
+ l->radial_next = l->radial_prev = NULL;
+ l->head.data = NULL;
+ l->head.htype = BM_LOOP;
+
+ bm->totloop++;
+
+ 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;
+}
+
+static BMLoop *bm_face_boundry_add(BMesh *bm, BMFace *f, BMVert *startv, BMEdge *starte)
+{
+#ifdef USE_BMESH_HOLES
+ BMLoopList *lst = BLI_mempool_calloc(bm->looplistpool);
+#endif
+ BMLoop *l = bmesh_create_loop(bm, startv, starte, f, NULL);
+
+ bmesh_radial_append(starte, l);
+
+#ifdef USE_BMESH_HOLES
+ lst->first = lst->last = l;
+ BLI_addtail(&f->loops, lst);
+#else
+ f->l_first = l;
+#endif
+
+ l->f = f;
+
+ return l;
+}
+
+BMFace *BM_face_copy(BMesh *bm, BMFace *f, int copyedges, int copyverts)
+{
+ BMEdge **edges = NULL;
+ BMVert **verts = NULL;
+ BLI_array_staticdeclare(edges, BM_NGON_STACK_SIZE);
+ BLI_array_staticdeclare(verts, BM_NGON_STACK_SIZE);
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ BMLoop *l2;
+ BMFace *f2;
+ int i;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (copyverts) {
+ BMVert *v = BM_vert_create(bm, l_iter->v->co, l_iter->v);
+ BLI_array_append(verts, v);
+ }
+ else {
+ BLI_array_append(verts, l_iter->v);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ i = 0;
+ do {
+ if (copyedges) {
+ BMEdge *e;
+ BMVert *v1, *v2;
+
+ if (l_iter->e->v1 == verts[i]) {
+ v1 = verts[i];
+ v2 = verts[(i + 1) % f->len];
+ }
+ else {
+ v2 = verts[i];
+ v1 = verts[(i + 1) % f->len];
+ }
+
+ e = BM_edge_create(bm, v1, v2, l_iter->e, FALSE);
+ BLI_array_append(edges, e);
+ }
+ else {
+ BLI_array_append(edges, l_iter->e);
+ }
+
+ i++;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ f2 = BM_face_create(bm, verts, edges, f->len, FALSE);
+
+ BM_elem_attrs_copy(bm, bm, f, f2);
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ l2 = BM_FACE_FIRST_LOOP(f2);
+ do {
+ BM_elem_attrs_copy(bm, bm, l_iter, l2);
+ l2 = l2->next;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ return f2;
+}
+
+BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len, int nodouble)
+{
+ BMFace *f = NULL;
+ BMLoop *l, *startl, *lastl;
+ int i, overlap;
+
+ if (len == 0) {
+ /* just return NULL for no */
+ return NULL;
+ }
+
+ if (nodouble) {
+ /* Check if face already exists */
+ overlap = BM_face_exists(bm, verts, len, &f);
+ if (overlap) {
+ return f;
+ }
+ else {
+ BLI_assert(f == NULL);
+ }
+ }
+
+ f = BLI_mempool_calloc(bm->fpool);
+
+#ifdef USE_DEBUG_INDEX_MEMCHECK
+ DEBUG_MEMCHECK_INDEX_INVALIDATE(f)
+#else
+ BM_elem_index_set(f, -1); /* set_ok_invalid */
+#endif
+
+ bm->elem_index_dirty |= BM_FACE; /* may add to middle of the pool */
+
+ bm->totface++;
+
+ f->head.htype = BM_FACE;
+
+ startl = lastl = bm_face_boundry_add(bm, (BMFace *)f, verts[0], edges[0]);
+
+ startl->v = (BMVert *)verts[0];
+ startl->e = (BMEdge *)edges[0];
+ for (i = 1; i < len; i++) {
+ l = bmesh_create_loop(bm, verts[i], edges[i], (BMFace *)f, edges[i]->l);
+
+ l->f = (BMFace *) f;
+ bmesh_radial_append(edges[i], l);
+
+ l->prev = lastl;
+ lastl->next = l;
+ lastl = l;
+ }
+
+ /* allocate flag */
+ f->oflags = BLI_mempool_calloc(bm->toolflagpool);
+
+ CustomData_bmesh_set_default(&bm->pdata, &f->head.data);
+
+ startl->prev = lastl;
+ lastl->next = startl;
+
+ f->len = len;
+
+#ifdef USE_BMESH_HOLES
+ f->totbounds = 0;
+#endif
+
+ BM_CHECK_ELEMENT(bm, f);
+
+ return (BMFace *) f;
+}
+
+int bmesh_check_element(BMesh *UNUSED(bm), void *element, const char htype)
+{
+ BMHeader *head = element;
+ int err = 0;
+
+ if (!element)
+ return 1;
+
+ if (head->htype != htype)
+ return 2;
+
+ switch (htype) {
+ case BM_VERT: {
+ BMVert *v = element;
+ if (v->e && v->e->head.htype != BM_EDGE) {
+ err |= 4;
+ }
+ break;
+ }
+ case BM_EDGE: {
+ BMEdge *e = element;
+ if (e->l && e->l->head.htype != BM_LOOP)
+ err |= 8;
+ if (e->l && e->l->f->head.htype != BM_FACE)
+ err |= 16;
+ if (e->v1_disk_link.prev == NULL ||
+ e->v2_disk_link.prev == NULL ||
+ e->v1_disk_link.next == NULL ||
+ e->v2_disk_link.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.htype != BM_FACE)
+ err |= 256;
+ if (l->e->head.htype != BM_EDGE)
+ err |= 512;
+ if (l->v->head.htype != BM_VERT)
+ err |= 1024;
+ if (!BM_vert_in_edge(l->e, l->v)) {
+ fprintf(stderr, "%s: fatal bmesh error (vert not in edge)! (bmesh internal error)\n", __func__);
+ 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 ye */
+ l2 = l;
+ i = 0;
+ do {
+ if (i >= BM_NGON_MAX) {
+ break;
+ }
+
+ i++;
+ } while ((l2 = l2->next) != 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_iter;
+ BMLoop *l_first;
+ int len = 0;
+
+#ifdef USE_BMESH_HOLES
+ if (!f->loops.first)
+#else
+ if (!f->l_first)
+#endif
+ {
+ err |= (1 << 16);
+ }
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (l_iter->f != f) {
+ fprintf(stderr, "%s: loop inside one face points to another! (bmesh internal error)\n", __func__);
+ err |= (1 << 17);
+ }
+
+ if (!l_iter->e)
+ err |= (1 << 18);
+ if (!l_iter->v)
+ err |= (1 << 19);
+ if (!BM_vert_in_edge(l_iter->e, l_iter->v) || !BM_vert_in_edge(l_iter->e, l_iter->next->v)) {
+ err |= (1 << 20);
+ }
+
+ if (!bmesh_radial_validate(bmesh_radial_length(l_iter), l_iter))
+ err |= (1 << 21);
+
+ if (!bmesh_disk_count(l_iter->v) || !bmesh_disk_count(l_iter->next->v))
+ err |= (1 << 22);
+
+ len++;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (len != f->len)
+ err |= (1 << 23);
+ }
+ }
+
+ if (err) {
+ bmesh_error();
+ }
+
+ return err;
+}
+
+/* low level function, only free's,
+ * does not change adjust surrounding geometry */
+static void bmesh_kill_only_vert(BMesh *bm, BMVert *v)
+{
+ bm->totvert--;
+ bm->elem_index_dirty |= BM_VERT;
+
+ BM_select_history_remove(bm, v);
+ if (v->head.data)
+ CustomData_bmesh_free_block(&bm->vdata, &v->head.data);
+
+ BLI_mempool_free(bm->toolflagpool, v->oflags);
+ BLI_mempool_free(bm->vpool, v);
+}
+
+static void bmesh_kill_only_edge(BMesh *bm, BMEdge *e)
+{
+ bm->totedge--;
+ bm->elem_index_dirty |= BM_EDGE;
+
+ BM_select_history_remove(bm, e);
+
+ if (e->head.data)
+ CustomData_bmesh_free_block(&bm->edata, &e->head.data);
+
+ BLI_mempool_free(bm->toolflagpool, e->oflags);
+ BLI_mempool_free(bm->epool, e);
+}
+
+static void bmesh_kill_only_face(BMesh *bm, BMFace *f)
+{
+ if (bm->act_face == f)
+ bm->act_face = NULL;
+
+ bm->totface--;
+ bm->elem_index_dirty |= BM_FACE;
+
+ BM_select_history_remove(bm, f);
+
+ if (f->head.data)
+ CustomData_bmesh_free_block(&bm->pdata, &f->head.data);
+
+ BLI_mempool_free(bm->toolflagpool, f->oflags);
+ BLI_mempool_free(bm->fpool, f);
+}
+
+static void bmesh_kill_only_loop(BMesh *bm, BMLoop *l)
+{
+ bm->totloop--;
+ if (l->head.data)
+ CustomData_bmesh_free_block(&bm->ldata, &l->head.data);
+
+ BLI_mempool_free(bm->lpool, l);
+}
+
+void BM_face_edges_kill(BMesh *bm, BMFace *f)
+{
+ BMEdge **edges = NULL;
+ BLI_array_staticdeclare(edges, BM_NGON_STACK_SIZE);
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ int i;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BLI_array_append(edges, l_iter->e);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ for (i = 0; i < BLI_array_count(edges); i++) {
+ BM_edge_kill(bm, edges[i]);
+ }
+
+ BLI_array_free(edges);
+}
+
+void BM_face_verts_kill(BMesh *bm, BMFace *f)
+{
+ BMVert **verts = NULL;
+ BLI_array_staticdeclare(verts, BM_NGON_STACK_SIZE);
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ int i;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BLI_array_append(verts, l_iter->v);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ for (i = 0; i < BLI_array_count(verts); i++) {
+ BM_vert_kill(bm, verts[i]);
+ }
+
+ BLI_array_free(verts);
+}
+
+void BM_face_kill(BMesh *bm, BMFace *f)
+{
+#ifdef USE_BMESH_HOLES
+ BMLoopList *ls, *ls_next;
+#endif
+
+ BM_CHECK_ELEMENT(bm, f);
+
+#ifdef USE_BMESH_HOLES
+ for (ls = f->loops.first; ls; ls = ls_next)
+#else
+ if (f->l_first)
+#endif
+ {
+ BMLoop *l_iter, *l_next, *l_first;
+
+#ifdef USE_BMESH_HOLES
+ ls_next = ls->next;
+ l_iter = l_first = ls->first;
+#else
+ l_iter = l_first = f->l_first;
+#endif
+
+ do {
+ l_next = l_iter->next;
+
+ bmesh_radial_remove_loop(l_iter, l_iter->e);
+ bmesh_kill_only_loop(bm, l_iter);
+
+ } while ((l_iter = l_next) != l_first);
+
+#ifdef USE_BMESH_HOLES
+ BLI_mempool_free(bm->looplistpool, ls);
+#endif
+ }
+
+ bmesh_kill_only_face(bm, f);
+}
+
+void BM_edge_kill(BMesh *bm, BMEdge *e)
+{
+
+ 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;
+ if (lnext->f == l->f) {
+ BM_face_kill(bm, l->f);
+ break;
+ }
+
+ BM_face_kill(bm, l->f);
+
+ if (l == lnext)
+ break;
+ l = lnext;
+ } while (l != startl);
+ }
+
+ bmesh_kill_only_edge(bm, e);
+}
+
+void BM_vert_kill(BMesh *bm, BMVert *v)
+{
+ if (v->e) {
+ BMEdge *e, *nexte;
+
+ e = v->e;
+ while (v->e) {
+ nexte = bmesh_disk_nextedge(e, v);
+ BM_edge_kill(bm, e);
+ e = nexte;
+ }
+ }
+
+ bmesh_kill_only_vert(bm, 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.
+ *
+ * BMESH_TODO: reinsert validation code.
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+ */
+
+static int bmesh_loop_length(BMLoop *l)
+{
+ BMLoop *l_first = l;
+ int i = 0;
+
+ do {
+ i++;
+ } while ((l = l->next) != l_first);
+
+ return i;
+}
+
+static int bmesh_loop_reverse_loop(BMesh *bm, BMFace *f
+#ifdef USE_BMESH_HOLES
+ , BMLoopList *lst
+#endif
+ )
+{
+
+#ifdef USE_BMESH_HOLES
+ BMLoop *l_first = lst->first;
+#else
+ BMLoop *l_first = f->l_first;
+#endif
+
+ BMLoop *l_iter, *oldprev, *oldnext;
+ BMEdge **edar = NULL;
+ MDisps *md;
+ BLI_array_staticdeclare(edar, BM_NGON_STACK_SIZE);
+ int i, j, edok, len = 0, do_disps = CustomData_has_layer(&bm->ldata, CD_MDISPS);
+
+ len = bmesh_loop_length(l_first);
+
+ for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) {
+ BMEdge *curedge = l_iter->e;
+ bmesh_radial_remove_loop(l_iter, curedge);
+ BLI_array_append(edar, curedge);
+ }
+
+ /* actually reverse the loop */
+ for (i = 0, l_iter = l_first; i < len; i++) {
+ oldnext = l_iter->next;
+ oldprev = l_iter->prev;
+ l_iter->next = oldprev;
+ l_iter->prev = oldnext;
+ l_iter = oldnext;
+
+ if (do_disps) {
+ float (*co)[3];
+ int x, y, sides;
+
+ md = CustomData_bmesh_get(&bm->ldata, l_iter->head.data, CD_MDISPS);
+ if (!md->totdisp || !md->disps)
+ continue;
+
+ sides = (int)sqrt(md->totdisp);
+ co = md->disps;
+
+ for (x = 0; x < sides; x++) {
+ for (y = 0; y < x; y++) {
+ swap_v3_v3(co[y * sides + x], co[sides * x + y]);
+ }
+ }
+ }
+ }
+
+ if (len == 2) { /* two edged face */
+ /* do some verification here! */
+ l_first->e = edar[1];
+ l_first->next->e = edar[0];
+ }
+ else {
+ for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) {
+ edok = 0;
+ for (j = 0; j < len; j++) {
+ edok = bmesh_verts_in_edge(l_iter->v, l_iter->next->v, edar[j]);
+ if (edok) {
+ l_iter->e = edar[j];
+ break;
+ }
+ }
+ }
+ }
+ /* rebuild radia */
+ for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next)
+ bmesh_radial_append(l_iter->e, l_iter);
+
+ /* validate radia */
+ for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) {
+ BM_CHECK_ELEMENT(bm, l_iter);
+ BM_CHECK_ELEMENT(bm, l_iter->e);
+ BM_CHECK_ELEMENT(bm, l_iter->v);
+ BM_CHECK_ELEMENT(bm, l_iter->f);
+ }
+
+ BLI_array_free(edar);
+
+ BM_CHECK_ELEMENT(bm, f);
+
+ return 1;
+}
+
+int bmesh_loop_reverse(BMesh *bm, BMFace *f)
+{
+#ifdef USE_BMESH_HOLES
+ return bmesh_loop_reverse_loop(bm, f, f->loops.first);
+#else
+ return bmesh_loop_reverse_loop(bm, f);
+#endif
+}
+
+static void bmesh_systag_elements(BMesh *UNUSED(bm), void *veles, int tot, int flag)
+{
+ BMHeader **eles = veles;
+ int i;
+
+ for (i = 0; i < tot; i++) {
+ BM_ELEM_API_FLAG_ENABLE((BMElemF *)eles[i], flag);
+ }
+}
+
+static void bmesh_clear_systag_elements(BMesh *UNUSED(bm), void *veles, int tot, int flag)
+{
+ BMHeader **eles = veles;
+ int i;
+
+ for (i = 0; i < tot; i++) {
+ BM_ELEM_API_FLAG_DISABLE((BMElemF *)eles[i], flag);
+ }
+}
+
+#define FACE_MARK (1 << 10)
+
+static int count_flagged_radial(BMesh *bm, BMLoop *l, int flag)
+{
+ BMLoop *l2 = l;
+ int i = 0, c = 0;
+
+ do {
+ if (!l2) {
+ bmesh_error();
+ goto error;
+ }
+
+ i += BM_ELEM_API_FLAG_TEST(l2->f, flag) ? 1 : 0;
+ l2 = bmesh_radial_nextloop(l2);
+ if (c >= BM_LOOP_RADIAL_MAX) {
+ bmesh_error();
+ goto error;
+ }
+ c++;
+ } while (l2 != l);
+
+ return i;
+
+error:
+ BMO_error_raise(bm, bm->currentop, BMERR_MESH_ERROR, NULL);
+ return 0;
+}
+
+static int UNUSED_FUNCTION(count_flagged_disk)(BMVert *v, int flag)
+{
+ BMEdge *e = v->e;
+ int i = 0;
+
+ if (!e)
+ return 0;
+
+ do {
+ i += BM_ELEM_API_FLAG_TEST(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 FALSE;
+
+ do {
+ BMLoop *l = e->l;
+
+ if (!l) {
+ return FALSE;
+ }
+
+ if (bmesh_radial_length(l) == 1)
+ return FALSE;
+
+ do {
+ if (!BM_ELEM_API_FLAG_TEST(l->f, flag))
+ return FALSE;
+
+ l = l->radial_next;
+ } while (l != e->l);
+
+ e = bmesh_disk_nextedge(e, v);
+ } while (e != v->e);
+
+ return TRUE;
+}
+
+/* Midlevel Topology Manipulation Functions */
+
+/*
+ * BM_faces_join
+ *
+ * Joins a collected group of faces into one. Only restriction on
+ * the input data is that the faces must be connected to each other.
+ *
+ * If a pair of faces share multiple edges, the pair of
+ * faces will be joined at every edge.
+ *
+ * Returns a pointer to the combined face.
+ */
+BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface)
+{
+ BMFace *f, *newf;
+#ifdef USE_BMESH_HOLES
+ BMLoopList *lst;
+ ListBase holes = {NULL, NULL};
+#endif
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ BMEdge **edges = NULL;
+ BMEdge **deledges = NULL;
+ BMVert **delverts = NULL;
+ BLI_array_staticdeclare(edges, BM_NGON_STACK_SIZE);
+ BLI_array_staticdeclare(deledges, BM_NGON_STACK_SIZE);
+ BLI_array_staticdeclare(delverts, BM_NGON_STACK_SIZE);
+ BMVert *v1 = NULL, *v2 = NULL;
+ const 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_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ int rlen = count_flagged_radial(bm, l_iter, _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_iter->e);
+
+ if (!v1) {
+ v1 = l_iter->v;
+ v2 = BM_edge_other_vert(l_iter->e, l_iter->v);
+ }
+ tote++;
+ }
+ else if (rlen == 2) {
+ int d1, d2;
+
+ d1 = disk_is_flagged(l_iter->e->v1, _FLAG_JF);
+ d2 = disk_is_flagged(l_iter->e->v2, _FLAG_JF);
+
+ if (!d1 && !d2 && !BM_ELEM_API_FLAG_TEST(l_iter->e, _FLAG_JF)) {
+ /* don't remove an edge it makes up the side of another face
+ * else this will remove the face as well - campbell */
+ if (BM_edge_face_count(l_iter->e) <= 2) {
+ BLI_array_append(deledges, l_iter->e);
+ BM_ELEM_API_FLAG_ENABLE(l_iter->e, _FLAG_JF);
+ }
+ }
+ else {
+ if (d1 && !BM_ELEM_API_FLAG_TEST(l_iter->e->v1, _FLAG_JF)) {
+ BLI_array_append(delverts, l_iter->e->v1);
+ BM_ELEM_API_FLAG_ENABLE(l_iter->e->v1, _FLAG_JF);
+ }
+
+ if (d2 && !BM_ELEM_API_FLAG_TEST(l_iter->e->v2, _FLAG_JF)) {
+ BLI_array_append(delverts, l_iter->e->v2);
+ BM_ELEM_API_FLAG_ENABLE(l_iter->e->v2, _FLAG_JF);
+ }
+ }
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+#ifdef USE_BMESH_HOLES
+ for (lst = f->loops.first; lst; lst = lst->next) {
+ if (lst == f->loops.first) continue;
+
+ BLI_remlink(&f->loops, lst);
+ BLI_addtail(&holes, lst);
+ }
+#endif
+
+ }
+
+ /* create region fac */
+ newf = BM_face_create_ngon(bm, v1, v2, edges, tote, FALSE);
+ if (!newf || BMO_error_occurred(bm)) {
+ if (!BMO_error_occurred(bm))
+ err = "Invalid boundary region to join faces";
+ goto error;
+ }
+
+ /* copy over loop data */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(newf);
+ do {
+ BMLoop *l2 = l_iter->radial_next;
+
+ do {
+ if (BM_ELEM_API_FLAG_TEST(l2->f, _FLAG_JF))
+ break;
+ l2 = l2->radial_next;
+ } while (l2 != l_iter);
+
+ if (l2 != l_iter) {
+ /* I think this is correct */
+ if (l2->v != l_iter->v) {
+ l2 = l2->next;
+ }
+
+ BM_elem_attrs_copy(bm, bm, l2, l_iter);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ BM_elem_attrs_copy(bm, bm, faces[0], newf);
+
+#ifdef USE_BMESH_HOLES
+ /* add hole */
+ BLI_movelisttolist(&newf->loops, &holes);
+#endif
+
+ /* update loop face pointer */
+#ifdef USE_BMESH_HOLES
+ for (lst = newf->loops.first; lst; lst = lst->next)
+#endif
+ {
+#ifdef USE_BMESH_HOLES
+ l_iter = l_first = lst->first;
+#else
+ l_iter = l_first = BM_FACE_FIRST_LOOP(newf);
+#endif
+ do {
+ l_iter->f = newf;
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ bmesh_clear_systag_elements(bm, faces, totface, _FLAG_JF);
+ BM_ELEM_API_FLAG_DISABLE(newf, _FLAG_JF);
+
+ /* handle multires data */
+ if (CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
+ l_iter = l_first = BM_FACE_FIRST_LOOP(newf);
+ do {
+ for (i = 0; i < totface; i++) {
+ BM_loop_interp_multires(bm, l_iter, faces[i]);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ /* delete old geometr */
+ for (i = 0; i < BLI_array_count(deledges); i++) {
+ BM_edge_kill(bm, deledges[i]);
+ }
+
+ for (i = 0; i < BLI_array_count(delverts); i++) {
+ BM_vert_kill(bm, delverts[i]);
+ }
+
+ BLI_array_free(edges);
+ BLI_array_free(deledges);
+ BLI_array_free(delverts);
+
+ BM_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_error_raise(bm, bm->currentop, BMERR_DISSOLVEFACES_FAILED, err);
+ }
+ return NULL;
+}
+
+static BMFace *bmesh_addpolylist(BMesh *bm, BMFace *UNUSED(example))
+{
+ BMFace *f;
+#ifdef USE_BMESH_HOLES
+ BMLoopList *lst;
+#endif
+
+ f = BLI_mempool_calloc(bm->fpool);
+#ifdef USE_BMESH_HOLES
+ lst = BLI_mempool_calloc(bm->looplistpool);
+#endif
+
+ f->head.htype = BM_FACE;
+#ifdef USE_BMESH_HOLES
+ BLI_addtail(&f->loops, lst);
+#endif
+
+#ifdef USE_DEBUG_INDEX_MEMCHECK
+ DEBUG_MEMCHECK_INDEX_INVALIDATE(f)
+#else
+ BM_elem_index_set(f, -1); /* set_ok_invalid */
+#endif
+
+ bm->elem_index_dirty |= BM_FACE; /* may add to middle of the pool */
+
+ bm->totface++;
+
+ /* allocate flag */
+ f->oflags = BLI_mempool_calloc(bm->toolflagpool);
+
+ CustomData_bmesh_set_default(&bm->pdata, &f->head.data);
+
+ f->len = 0;
+
+#ifdef USE_BMESH_HOLES
+ f->totbounds = 1;
+#endif
+
+ 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
+#ifdef USE_BMESH_HOLES
+ , ListBase *holes
+#endif
+ )
+{
+#ifdef USE_BMESH_HOLES
+ BMLoopList *lst, *lst2;
+#endif
+
+ BMFace *f2;
+ BMLoop *l_iter, *l_first;
+ BMLoop *v1loop = NULL, *v2loop = NULL, *f1loop = NULL, *f2loop = NULL;
+ BMEdge *e;
+ int i, len, f1len, f2len;
+
+ /* verify that v1 and v2 are in face */
+ len = f->len;
+ for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f); i < len; i++, l_iter = l_iter->next) {
+ if (l_iter->v == v1) v1loop = l_iter;
+ else if (l_iter->v == v2) v2loop = l_iter;
+ }
+
+ if (!v1loop || !v2loop) {
+ return NULL;
+ }
+
+ /* allocate new edge between v1 and v2 */
+ e = BM_edge_create(bm, v1, v2, NULL, FALSE);
+
+ 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;
+
+#ifdef USE_BMESH_HOLES
+ lst = f->loops.first;
+ lst2 = f2->loops.first;
+
+ lst2->first = lst2->last = f2loop;
+ lst->first = lst->last = f1loop;
+#else
+ f2->l_first = f2loop;
+ f->l_first = f1loop;
+#endif
+
+ /* validate both loop */
+ /* 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 */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f2);
+ f2len = 0;
+ do {
+ l_iter->f = f2;
+ f2len++;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ /* link up the new loops into the new edges radia */
+ bmesh_radial_append(e, f1loop);
+ bmesh_radial_append(e, f2loop);
+
+ f2->len = f2len;
+
+ f1len = 0;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ f1len++;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ f->len = f1len;
+
+ if (rl) *rl = f2loop;
+
+#ifdef USE_BMESH_HOLES
+ 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);
+ }
+ }
+#endif
+
+ BM_CHECK_ELEMENT(bm, e);
+ BM_CHECK_ELEMENT(bm, f);
+ BM_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, valence1 = 0, valence2 = 0;
+
+ if (bmesh_vert_in_edge(e, tv) == 0) {
+ return NULL;
+ }
+ ov = bmesh_edge_getothervert(e, tv);
+
+ /* count valence of v1 */
+ valence1 = bmesh_disk_count(ov);
+
+ /* count valence of v2 */
+ valence2 = bmesh_disk_count(tv);
+
+ nv = BM_vert_create(bm, tv->co, tv);
+ ne = BM_edge_create(bm, nv, tv, e, FALSE);
+
+ 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 cycl */
+ bmesh_disk_append_edge(e, nv);
+
+ /* add ne to nv's disk cycl */
+ bmesh_disk_append_edge(ne, nv);
+
+ /* add ne to tv's disk cycl */
+ bmesh_disk_append_edge(ne, tv);
+
+ /* verify disk cycle */
+ edok = bmesh_disk_validate(valence1, ov->e, ov);
+ if (!edok) bmesh_error();
+ edok = bmesh_disk_validate(valence2, tv->e, tv);
+ if (!edok) bmesh_error();
+ edok = bmesh_disk_validate(2, nv->e, nv);
+ if (!edok) bmesh_error();
+
+ /* Split the radial cycle if presen */
+ 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 loo */
+ if (bmesh_verts_in_edge(nl->v, nl->next->v, e)) {
+ nl->e = e;
+ l->e = ne;
+
+ /* append l into ne's rad cycl */
+ 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, nl->next->v, ne)) {
+ nl->e = ne;
+ l->e = e;
+
+ /* append l into ne's rad cycl */
+ 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 cycl */
+ 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 */
+ 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 (l->prev->e != ne && l->next->e != ne) {
+ bmesh_error();
+ }
+ edok = bmesh_verts_in_edge(l->v, l->next->v, e);
+ if (!edok) bmesh_error();
+ if (l->v == l->next->v) bmesh_error();
+ if (l->e == l->next->e) bmesh_error();
+
+ /* verify loop cycle for kloop-> */
+ BM_CHECK_ELEMENT(bm, l);
+ BM_CHECK_ELEMENT(bm, l->v);
+ BM_CHECK_ELEMENT(bm, l->e);
+ BM_CHECK_ELEMENT(bm, l->f);
+ }
+ /* verify loop->v and loop->next->v pointers for n */
+ 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 (l->prev->e != e && l->next->e != e) bmesh_error();
+ edok = bmesh_verts_in_edge(l->v, l->next->v, ne);
+ if (!edok) bmesh_error();
+ if (l->v == l->next->v) bmesh_error();
+ if (l->e == l->next->e) bmesh_error();
+
+ BM_CHECK_ELEMENT(bm, l);
+ BM_CHECK_ELEMENT(bm, l->v);
+ BM_CHECK_ELEMENT(bm, l->e);
+ BM_CHECK_ELEMENT(bm, l->f);
+ }
+ }
+
+ BM_CHECK_ELEMENT(bm, ne);
+ BM_CHECK_ELEMENT(bm, nv);
+ BM_CHECK_ELEMENT(bm, ov);
+ BM_CHECK_ELEMENT(bm, e);
+ BM_CHECK_ELEMENT(bm, tv);
+
+ if (re) *re = ne;
+ return nv;
+}
+
+/**
+ * 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;
+ BMLoop *killoop, *l;
+ int len, radlen = 0, halt = 0, i, valence1, valence2, edok;
+
+ if (bmesh_vert_in_edge(ke, kv) == 0) {
+ return FALSE;
+ }
+
+ len = bmesh_disk_count(kv);
+
+ 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 edge */
+
+ if (halt) {
+ return FALSE;
+ }
+ else {
+ /* For verification later, count valence of ov and t */
+ valence1 = bmesh_disk_count(ov);
+ valence2 = bmesh_disk_count(tv);
+
+ /* remove oe from kv's disk cycl */
+ bmesh_disk_remove_edge(oe, kv);
+ /* relink oe->kv to be oe->t */
+ bmesh_edge_swapverts(oe, kv, tv);
+ /* append oe to tv's disk cycl */
+ bmesh_disk_append_edge(oe, tv);
+ /* remove ke from tv's disk cycl */
+ bmesh_disk_remove_edge(ke, tv);
+
+ /* deal with radial cycle of k */
+ radlen = bmesh_radial_length(ke->l);
+ if (ke->l) {
+ /* first step, fix the neighboring loops of all loops in ke's radial cycl */
+ for (i = 0, killoop = ke->l; i < radlen; i++, killoop = bmesh_radial_nextloop(killoop)) {
+ /* relink loops and fix vertex pointer */
+ if (killoop->next->v == kv) {
+ killoop->next->v = tv;
+ }
+
+ killoop->next->prev = killoop->prev;
+ killoop->prev->next = killoop->next;
+ if (BM_FACE_FIRST_LOOP(killoop->f) == killoop) {
+ BM_FACE_FIRST_LOOP(killoop->f) = killoop->next;
+ }
+ killoop->next = NULL;
+ killoop->prev = NULL;
+
+ /* fix len attribute of fac */
+ killoop->f->len--;
+ }
+ /* second step, remove all the hanging loops attached to k */
+ radlen = bmesh_radial_length(ke->l);
+
+ if (LIKELY(radlen)) {
+ BMLoop **loops = NULL;
+ BLI_array_fixedstack_declare(loops, BM_NGON_STACK_SIZE, radlen, __func__);
+
+ killoop = ke->l;
+
+ /* this should be wrapped into a bme_free_radial function to be used by bmesh_KF as well.. */
+ for (i = 0; i < radlen; i++) {
+ loops[i] = killoop;
+ killoop = bmesh_radial_nextloop(killoop);
+ }
+ for (i = 0; i < radlen; i++) {
+ bm->totloop--;
+ BLI_mempool_free(bm->lpool, loops[i]);
+ }
+ BLI_array_fixedstack_free(loops);
+ }
+
+ /* Validate radial cycle of o */
+ edok = bmesh_radial_validate(radlen, oe->l);
+ if (!edok) {
+ bmesh_error();
+ }
+ }
+
+ /* deallocate edg */
+ bmesh_kill_only_edge(bm, ke);
+
+ /* deallocate verte */
+ bmesh_kill_only_vert(bm, kv);
+
+ /* Validate disk cycle lengths of ov, tv are unchange */
+ edok = bmesh_disk_validate(valence1, ov->e, ov);
+ if (!edok) bmesh_error();
+ edok = bmesh_disk_validate(valence2, tv->e, tv);
+ if (!edok) bmesh_error();
+
+ /* Validate loop cycle of all faces attached to o */
+ for (i = 0, l = oe->l; i < radlen; i++, l = bmesh_radial_nextloop(l)) {
+ if (l->e != oe) bmesh_error();
+ edok = bmesh_verts_in_edge(l->v, l->next->v, oe);
+ if (!edok) bmesh_error();
+ edok = bmesh_loop_validate(l->f);
+ if (!edok) bmesh_error();
+
+ BM_CHECK_ELEMENT(bm, l);
+ BM_CHECK_ELEMENT(bm, l->v);
+ BM_CHECK_ELEMENT(bm, l->e);
+ BM_CHECK_ELEMENT(bm, l->f);
+ }
+
+ BM_CHECK_ELEMENT(bm, ov);
+ BM_CHECK_ELEMENT(bm, tv);
+ BM_CHECK_ELEMENT(bm, oe);
+
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * 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
+ */
+BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
+{
+ BMLoop *l_iter, *f1loop = NULL, *f2loop = NULL;
+ int newlen = 0, i, f1len = 0, f2len = 0, radlen = 0, edok, shared;
+ BMIter iter;
+
+ /* can't join a face to itsel */
+ if (f1 == f2) {
+ return NULL;
+ }
+
+ /* verify that e is in both f1 and f2 */
+ f1len = f1->len;
+ f2len = f2->len;
+ BM_ITER(l_iter, &iter, bm, BM_LOOPS_OF_FACE, f1) {
+ if (l_iter->e == e) {
+ f1loop = l_iter;
+ break;
+ }
+ }
+ BM_ITER(l_iter, &iter, bm, BM_LOOPS_OF_FACE, f2) {
+ if (l_iter->e == e) {
+ f2loop = l_iter;
+ break;
+ }
+ }
+ if (!(f1loop && f2loop)) {
+ return NULL;
+ }
+
+ /* validate that edge is 2-manifold edg */
+ radlen = bmesh_radial_length(f1loop);
+ 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(f1loop->next->e, f2) ||
+ bmesh_radial_find_face(f1loop->prev->e, f2) ||
+ bmesh_radial_find_face(f2loop->next->e, f1) ||
+ bmesh_radial_find_face(f2loop->prev->e, f1) )
+ {
+ return NULL;
+ }
+
+ /* validate only one shared edg */
+ shared = BM_face_share_edges(f1, f2);
+ if (shared > 1) {
+ return NULL;
+ }
+
+ /* validate no internal join */
+ for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f1); i < f1len; i++, l_iter = l_iter->next) {
+ BM_elem_flag_disable(l_iter->v, BM_ELEM_TAG);
+ }
+ for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f2); i < f2len; i++, l_iter = l_iter->next) {
+ BM_elem_flag_disable(l_iter->v, BM_ELEM_TAG);
+ }
+
+ for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f1); i < f1len; i++, l_iter = l_iter->next) {
+ if (l_iter != f1loop) {
+ BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
+ }
+ }
+ for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f2); i < f2len; i++, l_iter = l_iter->next) {
+ if (l_iter != f2loop) {
+ /* as soon as a duplicate is found, bail out */
+ if (BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) {
+ return NULL;
+ }
+ }
+ }
+
+ /* join the two loop */
+ f1loop->prev->next = f2loop->next;
+ f2loop->next->prev = f1loop->prev;
+
+ f1loop->next->prev = f2loop->prev;
+ f2loop->prev->next = f1loop->next;
+
+ /* if f1loop was baseloop, make f1loop->next the base. */
+ if (BM_FACE_FIRST_LOOP(f1) == f1loop)
+ BM_FACE_FIRST_LOOP(f1) = f1loop->next;
+
+ /* increase length of f1 */
+ f1->len += (f2->len - 2);
+
+ /* make sure each loop points to the proper fac */
+ newlen = f1->len;
+ for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f1); i < newlen; i++, l_iter = l_iter->next)
+ l_iter->f = f1;
+
+ /* 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_mempool_free(bm->toolflagpool, f1loop->e->oflags);
+ BLI_mempool_free(bm->epool, f1loop->e);
+ bm->totedge--;
+ BLI_mempool_free(bm->lpool, f1loop);
+ bm->totloop--;
+ BLI_mempool_free(bm->lpool, f2loop);
+ bm->totloop--;
+ BLI_mempool_free(bm->toolflagpool, f2->oflags);
+ BLI_mempool_free(bm->fpool, f2);
+ bm->totface--;
+ /* account for both above */
+ bm->elem_index_dirty |= BM_EDGE | BM_FACE;
+
+ BM_CHECK_ELEMENT(bm, f1);
+
+ /* validate the new loop cycle */
+ edok = bmesh_loop_validate(f1);
+ if (!edok) bmesh_error();
+
+ return f1;
+}
+
+/*
+ * BMESH SPLICE VERT
+ *
+ * merges two verts into one (v into vtarget).
+ */
+static int bmesh_splicevert(BMesh *bm, BMVert *v, BMVert *vtarget)
+{
+ BMEdge *e;
+ BMLoop *l;
+ BMIter liter;
+
+ /* verts already spliced */
+ if (v == vtarget) {
+ return FALSE;
+ }
+
+ /* retarget all the loops of v to vtarget */
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_VERT, v) {
+ l->v = vtarget;
+ }
+
+ /* move all the edges from v's disk to vtarget's disk */
+ e = v->e;
+ while (e != NULL) {
+ bmesh_disk_remove_edge(e, v);
+ bmesh_edge_swapverts(e, v, vtarget);
+ bmesh_disk_append_edge(e, vtarget);
+ e = v->e;
+ }
+
+ BM_CHECK_ELEMENT(bm, v);
+ BM_CHECK_ELEMENT(bm, vtarget);
+
+ /* v is unused now, and can be killed */
+ BM_vert_kill(bm, v);
+
+ return TRUE;
+}
+
+/* BMESH CUT VERT
+ *
+ * cut all disjoint fans that meet at a vertex, making a unique
+ * vertex for each region. returns an array of all resulting
+ * vertices.
+ */
+static int bmesh_cutvert(BMesh *bm, BMVert *v, BMVert ***vout, int *len)
+{
+ BMEdge **stack = NULL;
+ BLI_array_declare(stack);
+ BMVert **verts = NULL;
+ GHash *visithash;
+ BMIter eiter, liter;
+ BMLoop *l;
+ BMEdge *e;
+ int i, maxindex;
+ BMLoop *nl;
+
+ visithash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh_cutvert visithash");
+
+ maxindex = 0;
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ if (BLI_ghash_haskey(visithash, e)) {
+ continue;
+ }
+
+ /* Prime the stack with this unvisited edge */
+ BLI_array_append(stack, e);
+
+ /* Considering only edges and faces incident on vertex v, walk
+ * the edges & faces and assign an index to each connected set */
+ while ((e = BLI_array_pop(stack))) {
+ BLI_ghash_insert(visithash, e, SET_INT_IN_POINTER(maxindex));
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_EDGE, e) {
+ nl = (l->v == v) ? l->prev : l->next;
+ if (!BLI_ghash_haskey(visithash, nl->e)) {
+ BLI_array_append(stack, nl->e);
+ }
+ }
+ }
+
+ maxindex++;
+ }
+
+ /* Make enough verts to split v for each group */
+ verts = MEM_callocN(sizeof(BMVert *) * maxindex, "bmesh_cutvert");
+ verts[0] = v;
+ for (i = 1; i < maxindex; i++) {
+ verts[i] = BM_vert_create(bm, v->co, v);
+ }
+
+ /* Replace v with the new verts in each group */
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_VERT, v) {
+ i = GET_INT_FROM_POINTER(BLI_ghash_lookup(visithash, l->e));
+ if (i == 0) {
+ continue;
+ }
+
+ /* Loops here should alway refer to an edge that has v as an
+ * endpoint. For each appearance of this vert in a face, there
+ * will actually be two iterations: one for the loop heading
+ * towards vertex v, and another for the loop heading out from
+ * vertex v. Only need to swap the vertex on one of those times,
+ * on the outgoing loop. */
+ if (l->v == v) {
+ l->v = verts[i];
+ }
+ }
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ i = GET_INT_FROM_POINTER(BLI_ghash_lookup(visithash, e));
+ if (i == 0) {
+ continue;
+ }
+
+ BLI_assert(e->v1 == v || e->v2 == v);
+ bmesh_disk_remove_edge(e, v);
+ bmesh_edge_swapverts(e, v, verts[i]);
+ bmesh_disk_append_edge(e, verts[i]);
+ }
+
+ BLI_ghash_free(visithash, NULL, NULL);
+ BLI_array_free(stack);
+
+ for (i = 0; i < maxindex; i++) {
+ BM_CHECK_ELEMENT(bm, verts[i]);
+ }
+
+ if (len != NULL) {
+ *len = maxindex;
+ }
+
+ if (vout != NULL) {
+ *vout = verts;
+ }
+ else {
+ MEM_freeN(verts);
+ }
+
+ return TRUE;
+}
+
+/* BMESH SPLICE EDGE
+ *
+ * splice two unique edges which share the same two vertices into one edge.
+ *
+ * edges must already have the same vertices
+ */
+static int UNUSED_FUNCTION(bmesh_spliceedge)(BMesh *bm, BMEdge *e, BMEdge *etarget)
+{
+ BMLoop *l;
+
+ if (!BM_vert_in_edge(e, etarget->v1) || !BM_vert_in_edge(e, etarget->v2)) {
+ /* not the same vertices can't splice */
+ return FALSE;
+ }
+
+ while (e->l) {
+ l = e->l;
+ BLI_assert(BM_vert_in_edge(etarget, l->v));
+ BLI_assert(BM_vert_in_edge(etarget, l->next->v));
+ bmesh_radial_remove_loop(l, e);
+ bmesh_radial_append(etarget, l);
+ }
+
+ BLI_assert(bmesh_radial_length(e->l) == 0);
+
+ BM_CHECK_ELEMENT(bm, e);
+ BM_CHECK_ELEMENT(bm, etarget);
+
+ BM_edge_kill(bm, e);
+
+ return TRUE;
+}
+
+/*
+ * BMESH CUT EDGE
+ *
+ * Cuts a single edge into two edge: the original edge and
+ * a new edge that has only "cutl" in its radial.
+ *
+ * Does nothing if cutl is already the only loop in the
+ * edge radial.
+ */
+static int bmesh_cutedge(BMesh *bm, BMEdge *e, BMLoop *cutl)
+{
+ BMEdge *ne;
+ int radlen;
+
+ BLI_assert(cutl->e == e);
+ BLI_assert(e->l);
+
+ radlen = bmesh_radial_length(e->l);
+ if (radlen < 2) {
+ /* no cut required */
+ return TRUE;
+ }
+
+ if (cutl == e->l) {
+ e->l = cutl->radial_next;
+ }
+
+ ne = BM_edge_create(bm, e->v1, e->v2, e, FALSE);
+ bmesh_radial_remove_loop(cutl, e);
+ bmesh_radial_append(ne, cutl);
+ cutl->e = ne;
+
+ BLI_assert(bmesh_radial_length(e->l) == radlen - 1);
+ BLI_assert(bmesh_radial_length(ne->l) == 1);
+
+ BM_CHECK_ELEMENT(bm, ne);
+ BM_CHECK_ELEMENT(bm, e);
+
+ return TRUE;
+}
+
+/*
+ * BMESH UNGLUE REGION MAKE VERT
+ *
+ * Disconnects a face from its vertex fan at loop sl.
+ */
+static BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *sl)
+{
+ BMVert **vtar;
+ int len, i;
+ BMVert *nv = NULL;
+ BMVert *sv = sl->v;
+
+ /* peel the face from the edge radials on both sides of the
+ * loop vert, disconnecting the face from its fan */
+ bmesh_cutedge(bm, sl->e, sl);
+ bmesh_cutedge(bm, sl->prev->e, sl->prev);
+
+ if (bmesh_disk_count(sv) == 2) {
+ /* If there are still only two edges out of sv, then
+ * this whole URMV was just a no-op, so exit now. */
+ return sv;
+ }
+
+ /* Update the disk start, so that v->e points to an edge
+ * not touching the split loop. This is so that bmesh_cutvert
+ * will leave the original sv on some *other* fan (not the
+ * one-face fan that holds the unglue face). */
+ while (sv->e == sl->e || sv->e == sl->prev->e) {
+ sv->e = bmesh_disk_nextedge(sv->e, sv);
+ }
+
+ /* Split all fans connected to the vert, duplicating it for
+ * each fans. */
+ bmesh_cutvert(bm, sv, &vtar, &len);
+
+ /* There should have been at least two fans cut apart here,
+ * otherwise the early exit would have kicked in. */
+ BLI_assert(len >= 2);
+
+ nv = sl->v;
+
+ /* Desired result here is that a new vert should always be
+ * created for the unglue face. This is so we can glue any
+ * extras back into the original vert. */
+ BLI_assert(nv != sv);
+ BLI_assert(sv == vtar[0]);
+
+ /* If there are more than two verts as a result, glue together
+ * all the verts except the one this URMV intended to create */
+ if (len > 2) {
+ for (i = 0; i < len; i++) {
+ if (vtar[i] == nv) {
+ break;
+ }
+ }
+
+ if (i != len) {
+ /* Swap the single vert that was needed for the
+ * unglue into the last array slot */
+ SWAP(BMVert *, vtar[i], vtar[len - 1]);
+
+ /* And then glue the rest back together */
+ for (i = 1; i < len - 1; i++) {
+ bmesh_splicevert(bm, vtar[i], vtar[0]);
+ }
+ }
+ }
+
+ MEM_freeN(vtar);
+
+ return nv;
+}
+
+/*
+ * BMESH UNGLUE REGION MAKE VERT
+ *
+ * Disconnects sf from the vertex fan at sv
+ */
+BMVert *bmesh_urmv(BMesh *bm, BMFace *sf, BMVert *sv)
+{
+ BMLoop *l_first;
+ BMLoop *l_iter;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(sf);
+ do {
+ if (l_iter->v == sv) {
+ break;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (l_iter->v != sv) {
+ /* sv is not part of sf */
+ return NULL;
+ }
+
+ return bmesh_urmv_loop(bm, l_iter);
+}
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
new file mode 100644
index 00000000000..19e9971619a
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -0,0 +1,1145 @@
+/*
+ * ***** 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): Joseph Eagar, Geoffrey Bantle, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_opdefines.c
+ * \ingroup bmesh
+ *
+ * BMesh operator definitions.
+ *
+ * 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) so long as the comment next to the
+ * slot definition tells you what types of elements are in it.
+ *
+ */
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+/* 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.
+ *
+ * {BMO_OP_SLOT_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.
+ */
+static BMOpDefine def_vertexsmooth = {
+ "vertexsmooth",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "verts"}, //input vertices
+ {BMO_OP_SLOT_INT, "mirror_clip_x"}, //set vertices close to the x axis before the operation to 0
+ {BMO_OP_SLOT_INT, "mirror_clip_y"}, //set vertices close to the y axis before the operation to 0
+ {BMO_OP_SLOT_INT, "mirror_clip_z"}, //set vertices close to the z axis before the operation to 0
+ {BMO_OP_SLOT_FLT, "clipdist"}, //clipping threshod for the above three slots
+ {0} /* null-terminating sentine */,
+ },
+ bmesh_vertexsmooth_exec,
+ 0
+};
+
+/*
+ * Right-Hand Faces
+ *
+ * Computes an "outside" normal for the specified input faces.
+ */
+
+static BMOpDefine def_righthandfaces = {
+ "righthandfaces",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "faces"},
+ {BMO_OP_SLOT_INT, "doflip"}, //internal flag, used by bmesh_rationalize_normals
+ {0} /* null-terminating sentine */,
+ },
+ bmesh_righthandfaces_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES,
+};
+
+/*
+ * 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.
+ */
+static BMOpDefine def_regionextend = {
+ "regionextend",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "geom"}, //input geometry
+ {BMO_OP_SLOT_ELEMENT_BUF, "geomout"}, //output slot, computed boundary geometry.
+ {BMO_OP_SLOT_INT, "constrict"}, //find boundary inside the regions, not outside.
+ {BMO_OP_SLOT_INT, "usefaces"}, //extend from faces instead of edges
+ {0} /* null-terminating sentine */,
+ },
+ bmesh_regionextend_exec,
+ 0
+};
+
+/*
+ * Edge Rotate
+ *
+ * Rotates edges topologically. Also known as "spin edge" to some people.
+ * Simple example: [/] becomes [|] then [\].
+ */
+static BMOpDefine def_edgerotate = {
+ "edgerotate",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "edges"}, //input edges
+ {BMO_OP_SLOT_ELEMENT_BUF, "edgeout"}, //newly spun edges
+ {BMO_OP_SLOT_INT, "ccw"}, //rotate edge counter-clockwise if true, othewise clockwise
+ {0} /* null-terminating sentine */,
+ },
+ bmesh_edgerotate_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES
+};
+
+/*
+ * Reverse Faces
+ *
+ * Reverses the winding (vertex order) of faces. This has the effect of
+ * flipping the normal.
+ */
+static BMOpDefine def_reversefaces = {
+ "reversefaces",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "faces"}, //input faces
+ {0} /* null-terminating sentine */,
+ },
+ bmesh_reversefaces_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES,
+};
+
+/*
+ * Edge Bisect
+ *
+ * Splits input edges (but doesn't do anything else).
+ * This creates a 2-valence vert.
+ */
+static BMOpDefine def_edgebisect = {
+ "edgebisect",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "edges"}, //input edges
+ {BMO_OP_SLOT_INT, "numcuts"}, //number of cuts
+ {BMO_OP_SLOT_ELEMENT_BUF, "outsplit"}, //newly created vertices and edges
+ {0} /* null-terminating sentine */,
+ },
+ esplit_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES
+};
+
+/*
+ * 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).
+ */
+
+static BMOpDefine def_mirror = {
+ "mirror",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "geom"}, //input geometry
+ {BMO_OP_SLOT_MAT, "mat"}, //matrix defining the mirror transformation
+ {BMO_OP_SLOT_FLT, "mergedist"}, //maximum distance for merging. does no merging if 0.
+ {BMO_OP_SLOT_ELEMENT_BUF, "newout"}, //output geometry, mirrored
+ {BMO_OP_SLOT_INT, "axis"}, //the axis to use, 0, 1, or 2 for x, y, z
+ {BMO_OP_SLOT_INT, "mirror_u"}, //mirror UVs across the u axis
+ {BMO_OP_SLOT_INT, "mirror_v"}, //mirror UVs across the v axis
+ {0, /* null-terminating sentine */}},
+ 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.
+ */
+static BMOpDefine def_finddoubles = {
+ "finddoubles",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "verts"}, //input vertices
+ {BMO_OP_SLOT_ELEMENT_BUF, "keepverts"}, //list of verts to keep
+ {BMO_OP_SLOT_FLT, "dist"}, //minimum distance
+ {BMO_OP_SLOT_MAPPING, "targetmapout"},
+ {0, /* null-terminating sentine */}},
+ bmesh_finddoubles_exec,
+ 0,
+};
+
+/*
+ * Remove Doubles
+ *
+ * Finds groups of vertices closer then dist and merges them together,
+ * using the weld verts bmop.
+ */
+static BMOpDefine def_removedoubles = {
+ "removedoubles",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "verts"}, //input verts
+ {BMO_OP_SLOT_FLT, "dist"}, //minimum distance
+ {0, /* null-terminating sentine */}},
+ bmesh_removedoubles_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES,
+};
+
+/*
+ * 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.
+ */
+static BMOpDefine def_automerge = {
+ "automerge",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "verts"}, //input verts
+ {BMO_OP_SLOT_FLT, "dist"}, //minimum distance
+ {0, /* null-terminating sentine */}},
+ bmesh_automerge_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES,
+};
+
+/*
+ * Collapse Connected
+ *
+ * Collapses connected vertices
+ */
+static BMOpDefine def_collapse = {
+ "collapse",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "edges"}, /* input edge */
+ {0, /* null-terminating sentine */}},
+ bmesh_collapse_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES,
+};
+
+
+/*
+ * Facedata point Merge
+ *
+ * Merge uv/vcols at a specific vertex.
+ */
+static BMOpDefine def_pointmerge_facedata = {
+ "pointmerge_facedata",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "verts"}, /* input vertice */
+ {BMO_OP_SLOT_ELEMENT_BUF, "snapv"}, /* snap verte */
+ {0, /* null-terminating sentine */}},
+ 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).
+ */
+static BMOpDefine def_vert_average_facedata = {
+ "vert_average_facedata",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "verts"}, /* input vertice */
+ {0, /* null-terminating sentine */}},
+ bmesh_vert_average_facedata_exec,
+ 0,
+};
+
+/*
+ * Point Merge
+ *
+ * Merge verts together at a point.
+ */
+static BMOpDefine def_pointmerge = {
+ "pointmerge",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "verts"}, /* input vertice */
+ {BMO_OP_SLOT_VEC, "mergeco"},
+ {0, /* null-terminating sentine */}},
+ bmesh_pointmerge_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES,
+};
+
+/*
+ * Collapse Connected UVs
+ *
+ * Collapses connected UV vertices.
+ */
+static BMOpDefine def_collapse_uvs = {
+ "collapse_uvs",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "edges"}, /* input edge */
+ {0, /* null-terminating sentine */}},
+ 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.
+ */
+static BMOpDefine def_weldverts = {
+ "weldverts",
+ {{BMO_OP_SLOT_MAPPING, "targetmap"}, /* maps welded vertices to verts they should weld to */
+ {0, /* null-terminating sentine */}},
+ bmesh_weldverts_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES,
+};
+
+/*
+ * Make Vertex
+ *
+ * Creates a single vertex; this bmop was necassary
+ * for click-create-vertex.
+ */
+static BMOpDefine def_makevert = {
+ "makevert",
+ {{BMO_OP_SLOT_VEC, "co"}, //the coordinate of the new vert
+ {BMO_OP_SLOT_ELEMENT_BUF, "newvertout"}, //the new vert
+ {0, /* null-terminating sentine */}},
+ bmesh_makevert_exec,
+ 0,
+};
+
+/*
+ * Join Triangles
+ *
+ * Tries to intelligently join triangles according
+ * to various settings and stuff.
+ */
+static BMOpDefine def_join_triangles = {
+ "join_triangles",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "faces"}, //input geometry.
+ {BMO_OP_SLOT_ELEMENT_BUF, "faceout"}, //joined faces
+ {BMO_OP_SLOT_INT, "compare_sharp"},
+ {BMO_OP_SLOT_INT, "compare_uvs"},
+ {BMO_OP_SLOT_INT, "compare_vcols"},
+ {BMO_OP_SLOT_INT, "compare_materials"},
+ {BMO_OP_SLOT_FLT, "limit"},
+ {0, /* null-terminating sentine */}},
+ bmesh_jointriangles_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES,
+};
+
+/*
+ * 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.
+ */
+static BMOpDefine def_contextual_create = {
+ "contextual_create",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "geom"}, //input geometry.
+ {BMO_OP_SLOT_ELEMENT_BUF, "faceout"}, //newly-made face(s)
+ {0, /* null-terminating sentine */}},
+ bmesh_contextual_create_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES,
+};
+
+/*
+ * Bridge edge loops with faces
+ */
+static BMOpDefine def_bridge_loops = {
+ "bridge_loops",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "edges"}, /* input edge */
+ {BMO_OP_SLOT_ELEMENT_BUF, "faceout"}, /* new face */
+ {0, /* null-terminating sentine */}},
+ bmesh_bridge_loops_exec,
+ 0,
+};
+
+static BMOpDefine def_edgenet_fill = {
+ "edgenet_fill",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "edges"}, /* input edge */
+ {BMO_OP_SLOT_MAPPING, "restrict"}, /* restricts edges to groups. maps edges to integer */
+ {BMO_OP_SLOT_INT, "use_restrict"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "excludefaces"}, /* list of faces to ignore for manifold check */
+ {BMO_OP_SLOT_MAPPING, "faceout_groupmap"}, /* maps new faces to the group numbers they came fro */
+ {BMO_OP_SLOT_ELEMENT_BUF, "faceout"}, /* new face */
+ {0, /* null-terminating sentine */}},
+ 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).
+ */
+static BMOpDefine def_edgenet_prepare = {
+ "edgenet_prepare",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "edges"}, //input edges
+ {BMO_OP_SLOT_ELEMENT_BUF, "edgeout"}, //new edges
+ {0, /* null-terminating sentine */}},
+ bmesh_edgenet_prepare,
+ 0,
+};
+
+/*
+ * Rotate
+ *
+ * Rotate vertices around a center, using a 3x3 rotation
+ * matrix. Equivilent of the old rotateflag function.
+ */
+static BMOpDefine def_rotate = {
+ "rotate",
+ {{BMO_OP_SLOT_VEC, "cent"}, //center of rotation
+ {BMO_OP_SLOT_MAT, "mat"}, //matrix defining rotation
+ {BMO_OP_SLOT_ELEMENT_BUF, "verts"}, //input vertices
+ {0, /* null-terminating sentine */}},
+ bmesh_rotate_exec,
+ 0,
+};
+
+/*
+ * Translate
+ *
+ * Translate vertices by an offset. Equivelent of the
+ * old translateflag function.
+ */
+static BMOpDefine def_translate = {
+ "translate",
+ {{BMO_OP_SLOT_VEC, "vec"}, //translation offset
+ {BMO_OP_SLOT_ELEMENT_BUF, "verts"}, //input vertices
+ {0, /* null-terminating sentine */}},
+ bmesh_translate_exec,
+ 0,
+};
+
+/*
+ * Scale
+ *
+ * Scales vertices by an offset.
+ */
+static BMOpDefine def_scale = {
+ "scale",
+ {{BMO_OP_SLOT_VEC, "vec"}, //scale factor
+ {BMO_OP_SLOT_ELEMENT_BUF, "verts"}, //input vertices
+ {0, /* null-terminating sentine */}},
+ bmesh_scale_exec,
+ 0,
+};
+
+
+/*
+ * Transform
+ *
+ * Transforms a set of vertices by a matrix. Multiplies
+ * the vertex coordinates with the matrix.
+ */
+static BMOpDefine def_transform = {
+ "transform",
+ {{BMO_OP_SLOT_MAT, "mat"}, //transform matrix
+ {BMO_OP_SLOT_ELEMENT_BUF, "verts"}, //input vertices
+ {0, /* null-terminating sentine */}},
+ bmesh_transform_exec,
+ 0,
+};
+
+/*
+ * Object Load BMesh
+ *
+ * Loads a bmesh into an object/mesh. This is a "private"
+ * bmop.
+ */
+static BMOpDefine def_object_load_bmesh = {
+ "object_load_bmesh",
+ {{BMO_OP_SLOT_PNT, "scene"},
+ {BMO_OP_SLOT_PNT, "object"},
+ {0, /* null-terminating sentine */}},
+ object_load_bmesh_exec,
+ 0,
+};
+
+
+/*
+ * BMesh to Mesh
+ *
+ * Converts a bmesh to a Mesh. This is reserved for exiting editmode.
+ */
+static BMOpDefine def_bmesh_to_mesh = {
+ "bmesh_to_mesh",
+ {{BMO_OP_SLOT_PNT, "mesh"}, //pointer to a mesh structure to fill in
+ {BMO_OP_SLOT_PNT, "object"}, //pointer to an object structure
+ {BMO_OP_SLOT_INT, "notesselation"}, //don't calculate mfaces
+ {0, /* null-terminating sentine */}},
+ 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.
+ */
+static BMOpDefine def_mesh_to_bmesh = {
+ "mesh_to_bmesh",
+ {{BMO_OP_SLOT_PNT, "mesh"}, //pointer to a Mesh structure
+ {BMO_OP_SLOT_PNT, "object"}, //pointer to an Object structure
+ {BMO_OP_SLOT_INT, "set_shapekey"}, //load active shapekey coordinates into verts
+ {0, /* null-terminating sentine */}},
+ mesh_to_bmesh_exec,
+ 0
+};
+
+/*
+ * Individual Face Extrude
+ *
+ * Extrudes faces individually.
+ */
+static BMOpDefine def_extrude_indivface = {
+ "extrude_face_indiv",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "faces"}, //input faces
+ {BMO_OP_SLOT_ELEMENT_BUF, "faceout"}, //output faces
+ {BMO_OP_SLOT_ELEMENT_BUF, "skirtout"}, //output skirt geometry, faces and edges
+ {0} /* null-terminating sentine */},
+ 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.
+ */
+static BMOpDefine def_extrude_onlyedge = {
+ "extrude_edge_only",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "edges"}, //input vertices
+ {BMO_OP_SLOT_ELEMENT_BUF, "geomout"}, //output geometry
+ {0} /* null-terminating sentine */},
+ bmesh_extrude_onlyedge_exec,
+ 0
+};
+
+/*
+ * Individual Vertex Extrude
+ *
+ * Extrudes wire edges from vertices.
+ */
+static BMOpDefine def_extrudeverts_indiv = {
+ "extrude_vert_indiv",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "verts"}, //input vertices
+ {BMO_OP_SLOT_ELEMENT_BUF, "edgeout"}, //output wire edges
+ {BMO_OP_SLOT_ELEMENT_BUF, "vertout"}, //output vertices
+ {0} /* null-terminating sentine */},
+ extrude_vert_indiv_exec,
+ 0
+};
+
+static BMOpDefine def_connectverts = {
+ "connectverts",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "verts"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "edgeout"},
+ {0} /* null-terminating sentine */},
+ connectverts_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES
+};
+
+static BMOpDefine def_extrudefaceregion = {
+ "extrudefaceregion",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "edgefacein"},
+ {BMO_OP_SLOT_MAPPING, "exclude"},
+ {BMO_OP_SLOT_INT, "alwayskeeporig"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "geomout"},
+ {0} /* null-terminating sentine */},
+ extrude_edge_context_exec,
+ 0
+};
+
+static BMOpDefine def_dissolvevertsop = {
+ "dissolveverts",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "verts"},
+ {0} /* null-terminating sentine */},
+ dissolveverts_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES
+};
+
+static BMOpDefine def_dissolveedgessop = {
+ "dissolveedges",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "edges"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "regionout"},
+ {BMO_OP_SLOT_INT, "use_verts"}, // dissolve verts left between only 2 edges.
+ {0} /* null-terminating sentine */},
+ dissolveedges_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES
+};
+
+static BMOpDefine def_dissolveedgeloopsop = {
+ "dissolveedgeloop",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "edges"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "regionout"},
+ {0} /* null-terminating sentine */},
+ dissolve_edgeloop_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES
+};
+
+static BMOpDefine def_dissolvefacesop = {
+ "dissolvefaces",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "faces"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "regionout"},
+ {BMO_OP_SLOT_INT, "use_verts"}, // dissolve verts left between only 2 edges.
+ {0} /* null-terminating sentine */},
+ dissolvefaces_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES
+};
+
+static BMOpDefine def_dissolvelimitop = {
+ "dissolvelimit",
+ {{BMO_OP_SLOT_FLT, "angle_limit"}, /* total rotation angle (degrees) */
+ {BMO_OP_SLOT_ELEMENT_BUF, "verts"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "edges"},
+ {0} /* null-terminating sentine */},
+ dissolvelimit_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES
+};
+
+static BMOpDefine def_triangop = {
+ "triangulate",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "faces"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "edgeout"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "faceout"},
+ {BMO_OP_SLOT_MAPPING, "facemap"},
+ {0} /* null-terminating sentine */},
+ triangulate_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES
+};
+
+static BMOpDefine def_subdop = {
+ "esubd",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "edges"},
+ {BMO_OP_SLOT_INT, "numcuts"},
+ {BMO_OP_SLOT_FLT, "smooth"},
+ {BMO_OP_SLOT_FLT, "fractal"},
+ {BMO_OP_SLOT_INT, "beauty"},
+ {BMO_OP_SLOT_INT, "seed"},
+ {BMO_OP_SLOT_MAPPING, "custompatterns"},
+ {BMO_OP_SLOT_MAPPING, "edgepercents"},
+
+ /* these next three can have multiple types of elements in them */
+ {BMO_OP_SLOT_ELEMENT_BUF, "outinner"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "outsplit"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "geomout"}, /* contains all output geometr */
+
+ {BMO_OP_SLOT_INT, "quadcornertype"}, //quad corner type, see bmesh_operators.h
+ {BMO_OP_SLOT_INT, "gridfill"}, //fill in fully-selected faces with a grid
+ {BMO_OP_SLOT_INT, "singleedge"}, //tesselate the case of one edge selected in a quad or triangle
+
+ {0} /* null-terminating sentine */,
+ },
+ esubdivide_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES
+};
+
+static BMOpDefine def_delop = {
+ "del",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "geom"}, {BMO_OP_SLOT_INT, "context"},
+ {0} /* null-terminating sentine */},
+ delop_exec,
+ 0
+};
+
+static BMOpDefine def_dupeop = {
+ "dupe",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "geom"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "origout"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "newout"},
+ /* facemap maps from source faces to dupe
+ * faces, and from dupe faces to source faces */
+ {BMO_OP_SLOT_MAPPING, "facemap"},
+ {BMO_OP_SLOT_MAPPING, "boundarymap"},
+ {BMO_OP_SLOT_MAPPING, "isovertmap"},
+ {BMO_OP_SLOT_PNT, "dest"}, /* destination bmesh, if NULL will use current on */
+ {0} /* null-terminating sentine */},
+ dupeop_exec,
+ 0
+};
+
+static BMOpDefine def_splitop = {
+ "split",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "geom"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "geomout"},
+ {BMO_OP_SLOT_MAPPING, "boundarymap"},
+ {BMO_OP_SLOT_MAPPING, "isovertmap"},
+ {BMO_OP_SLOT_PNT, "dest"}, /* destination bmesh, if NULL will use current on */
+ {0} /* null-terminating sentine */},
+ splitop_exec,
+ 0
+};
+
+/*
+ * Spin
+ *
+ * Extrude or duplicate geometry a number of times,
+ * rotating and possibly translating after each step
+ */
+static BMOpDefine def_spinop = {
+ "spin",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "geom"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "lastout"}, /* result of last step */
+ {BMO_OP_SLOT_VEC, "cent"}, /* rotation center */
+ {BMO_OP_SLOT_VEC, "axis"}, /* rotation axis */
+ {BMO_OP_SLOT_VEC, "dvec"}, /* translation delta per step */
+ {BMO_OP_SLOT_FLT, "ang"}, /* total rotation angle (degrees) */
+ {BMO_OP_SLOT_INT, "steps"}, /* number of steps */
+ {BMO_OP_SLOT_INT, "dupli"}, /* duplicate or extrude? */
+ {0} /* null-terminating sentine */},
+ spinop_exec,
+ 0
+};
+
+
+/*
+ * Similar faces search
+ *
+ * Find similar faces (area/material/perimeter, ...).
+ */
+static BMOpDefine def_similarfaces = {
+ "similarfaces",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "faces"}, /* input faces */
+ {BMO_OP_SLOT_ELEMENT_BUF, "faceout"}, /* output faces */
+ {BMO_OP_SLOT_INT, "type"}, /* type of selection */
+ {BMO_OP_SLOT_FLT, "thresh"}, /* threshold of selection */
+ {0} /* null-terminating sentine */},
+ bmesh_similarfaces_exec,
+ 0
+};
+
+/*
+ * Similar edges search
+ *
+ * Find similar edges (length, direction, edge, seam, ...).
+ */
+static BMOpDefine def_similaredges = {
+ "similaredges",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "edges"}, /* input edges */
+ {BMO_OP_SLOT_ELEMENT_BUF, "edgeout"}, /* output edges */
+ {BMO_OP_SLOT_INT, "type"}, /* type of selection */
+ {BMO_OP_SLOT_FLT, "thresh"}, /* threshold of selection */
+ {0} /* null-terminating sentine */},
+ bmesh_similaredges_exec,
+ 0
+};
+
+/*
+ * Similar vertices search
+ *
+ * Find similar vertices (normal, face, vertex group, ...).
+ */
+static BMOpDefine def_similarverts = {
+ "similarverts",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "verts"}, /* input vertices */
+ {BMO_OP_SLOT_ELEMENT_BUF, "vertout"}, /* output vertices */
+ {BMO_OP_SLOT_INT, "type"}, /* type of selection */
+ {BMO_OP_SLOT_FLT, "thresh"}, /* threshold of selection */
+ {0} /* null-terminating sentine */},
+ bmesh_similarverts_exec,
+ 0
+};
+
+/*
+ * uv rotation
+ * cycle the uvs
+ */
+static BMOpDefine def_meshrotateuvs = {
+ "meshrotateuvs",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "faces"}, /* input faces */
+ {BMO_OP_SLOT_INT, "dir"}, /* direction */
+ {0} /* null-terminating sentine */},
+ bmesh_rotateuvs_exec,
+ 0
+};
+
+/*
+ * uv reverse
+ * reverse the uvs
+ */
+static BMOpDefine def_meshreverseuvs = {
+ "meshreverseuvs",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "faces"}, /* input faces */
+ {0} /* null-terminating sentine */},
+ bmesh_reverseuvs_exec,
+ 0
+};
+
+/*
+ * color rotation
+ * cycle the colors
+ */
+static BMOpDefine def_meshrotatecolors = {
+ "meshrotatecolors",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "faces"}, /* input faces */
+ {BMO_OP_SLOT_INT, "dir"}, /* direction */
+ {0} /* null-terminating sentine */},
+ bmesh_rotatecolors_exec,
+ 0
+};
+
+/*
+ * color reverse
+ * reverse the colors
+ */
+static BMOpDefine def_meshreversecolors = {
+ "meshreversecolors",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "faces"}, /* input faces */
+ {0} /* null-terminating sentine */},
+ bmesh_reversecolors_exec,
+ 0
+};
+
+/*
+ * Similar vertices search
+ *
+ * Find similar vertices (normal, face, vertex group, ...).
+ */
+static BMOpDefine def_vertexshortestpath = {
+ "vertexshortestpath",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "startv"}, /* start vertex */
+ {BMO_OP_SLOT_ELEMENT_BUF, "endv"}, /* end vertex */
+ {BMO_OP_SLOT_ELEMENT_BUF, "vertout"}, /* output vertices */
+ {BMO_OP_SLOT_INT, "type"}, /* type of selection */
+ {0} /* null-terminating sentine */},
+ bmesh_vertexshortestpath_exec,
+ 0
+};
+
+/*
+ * Edge Split
+ *
+ * Disconnects faces along input edges.
+ */
+static BMOpDefine def_edgesplit = {
+ "edgesplit",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "edges"}, /* input edges */
+ {BMO_OP_SLOT_ELEMENT_BUF, "edgeout1"}, /* old output disconnected edges */
+ {BMO_OP_SLOT_ELEMENT_BUF, "edgeout2"}, /* new output disconnected edges */
+ {0} /* null-terminating sentine */},
+ bmesh_edgesplitop_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES
+};
+
+/*
+ * Create Grid
+ *
+ * Creates a grid with a variable number of subdivisions
+ */
+static BMOpDefine def_create_grid = {
+ "create_grid",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "vertout"}, //output verts
+ {BMO_OP_SLOT_INT, "xsegments"}, //number of x segments
+ {BMO_OP_SLOT_INT, "ysegments"}, //number of y segments
+ {BMO_OP_SLOT_FLT, "size"}, //size of the grid
+ {BMO_OP_SLOT_MAT, "mat"}, //matrix to multiply the new geometry with
+ {0, /* null-terminating sentine */}},
+ bmesh_create_grid_exec,
+ 0,
+};
+
+/*
+ * Create UV Sphere
+ *
+ * Creates a grid with a variable number of subdivisions
+ */
+static BMOpDefine def_create_uvsphere = {
+ "create_uvsphere",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "vertout"}, //output verts
+ {BMO_OP_SLOT_INT, "segments"}, //number of u segments
+ {BMO_OP_SLOT_INT, "revolutions"}, //number of v segment
+ {BMO_OP_SLOT_FLT, "diameter"}, //diameter
+ {BMO_OP_SLOT_MAT, "mat"}, //matrix to multiply the new geometry with--
+ {0, /* null-terminating sentine */}},
+ bmesh_create_uvsphere_exec,
+ 0,
+};
+
+/*
+ * Create Ico Sphere
+ *
+ * Creates a grid with a variable number of subdivisions
+ */
+static BMOpDefine def_create_icosphere = {
+ "create_icosphere",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "vertout"}, //output verts
+ {BMO_OP_SLOT_INT, "subdivisions"}, //how many times to recursively subdivide the sphere
+ {BMO_OP_SLOT_FLT, "diameter"}, //diameter
+ {BMO_OP_SLOT_MAT, "mat"}, //matrix to multiply the new geometry with
+ {0, /* null-terminating sentine */}},
+ bmesh_create_icosphere_exec,
+ 0,
+};
+
+/*
+ * Create Suzanne
+ *
+ * Creates a monkey. Be wary.
+ */
+static BMOpDefine def_create_monkey = {
+ "create_monkey",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "vertout"}, //output verts
+ {BMO_OP_SLOT_MAT, "mat"}, //matrix to multiply the new geometry with--
+ {0, /* null-terminating sentine */}},
+ bmesh_create_monkey_exec,
+ 0,
+};
+
+/*
+ * Create Cone
+ *
+ * Creates a cone with variable depth at both ends
+ */
+static BMOpDefine def_create_cone = {
+ "create_cone",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "vertout"}, //output verts
+ {BMO_OP_SLOT_INT, "cap_ends"}, //wheter or not to fill in the ends with faces
+ {BMO_OP_SLOT_INT, "cap_tris"}, //fill ends with triangles instead of ngons
+ {BMO_OP_SLOT_INT, "segments"},
+ {BMO_OP_SLOT_FLT, "diameter1"}, //diameter of one end
+ {BMO_OP_SLOT_FLT, "diameter2"}, //diameter of the opposite
+ {BMO_OP_SLOT_FLT, "depth"}, //distance between ends
+ {BMO_OP_SLOT_MAT, "mat"}, //matrix to multiply the new geometry with--
+ {0, /* null-terminating sentine */}},
+ bmesh_create_cone_exec,
+ 0,
+};
+
+/*
+ * Creates a circle
+ */
+static BMOpDefine def_create_circle = {
+ "create_circle",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "vertout"}, //output verts
+ {BMO_OP_SLOT_INT, "cap_ends"}, //wheter or not to fill in the ends with faces
+ {BMO_OP_SLOT_INT, "cap_tris"}, //fill ends with triangles instead of ngons
+ {BMO_OP_SLOT_INT, "segments"},
+ {BMO_OP_SLOT_FLT, "diameter"}, //diameter of one end
+ {BMO_OP_SLOT_MAT, "mat"}, //matrix to multiply the new geometry with--
+ {0, /* null-terminating sentine */}},
+ bmesh_create_circle_exec,
+ 0,
+};
+
+/*
+ * Create Cone
+ *
+ * Creates a cone with variable depth at both ends
+ */
+static BMOpDefine def_create_cube = {
+ "create_cube",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "vertout"}, //output verts
+ {BMO_OP_SLOT_FLT, "size"}, //size of the cube
+ {BMO_OP_SLOT_MAT, "mat"}, //matrix to multiply the new geometry with--
+ {0, /* null-terminating sentine */}},
+ bmesh_create_cube_exec,
+ 0,
+};
+
+/*
+ * Bevel
+ *
+ * Bevels edges and vertices
+ */
+static BMOpDefine def_bevel = {
+ "bevel",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "geom"}, /* input edges and vertices */
+ {BMO_OP_SLOT_ELEMENT_BUF, "face_spans"}, /* new geometry */
+ {BMO_OP_SLOT_ELEMENT_BUF, "face_holes"}, /* new geometry */
+ {BMO_OP_SLOT_INT, "use_lengths"}, /* grab edge lengths from a PROP_FLT customdata laye */
+ {BMO_OP_SLOT_INT, "use_even"}, /* corner vert placement: use shell/angle calculations */
+ {BMO_OP_SLOT_INT, "use_dist"}, /* corner vert placement: evaluate percent as a distance,
+ * modifier uses this. We could do this as another float setting */
+ {BMO_OP_SLOT_INT, "lengthlayer"}, /* which PROP_FLT layer to us */
+ {BMO_OP_SLOT_FLT, "percent"}, /* percentage to expand bevelled edge */
+ {0} /* null-terminating sentine */},
+ bmesh_bevel_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES
+};
+
+/*
+ * Beautify Fill
+ *
+ * Makes triangle a bit nicer
+ */
+static BMOpDefine def_beautify_fill = {
+"beautify_fill",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "faces"}, /* input faces */
+ {BMO_OP_SLOT_ELEMENT_BUF, "constrain_edges"}, /* edges that can't be flipped */
+ {BMO_OP_SLOT_ELEMENT_BUF, "geomout"}, /* new flipped faces and edges */
+ {0} /* null-terminating sentine */},
+ bmesh_beautify_fill_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES
+};
+
+/*
+ * Triangle Fill
+ *
+ * Fill edges with triangles
+ */
+static BMOpDefine def_triangle_fill = {
+ "triangle_fill",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "edges"}, /* input edges */
+ {BMO_OP_SLOT_ELEMENT_BUF, "geomout"}, /* new faces and edges */
+ {0} /* null-terminating sentine */},
+ bmesh_triangle_fill_exec,
+ BMO_OP_FLAG_UNTAN_MULTIRES
+};
+
+/*
+ * Solidify
+ *
+ * Turns a mesh into a shell with thickness
+ */
+static BMOpDefine def_solidify = {
+ "solidify",
+ {{BMO_OP_SLOT_ELEMENT_BUF, "geom"},
+ {BMO_OP_SLOT_FLT, "thickness"},
+ {BMO_OP_SLOT_ELEMENT_BUF, "geomout"},
+ {0}},
+ bmesh_solidify_face_region_exec,
+ 0
+};
+
+BMOpDefine *opdefines[] = {
+ &def_splitop,
+ &def_spinop,
+ &def_dupeop,
+ &def_delop,
+ &def_subdop,
+ &def_triangop,
+ &def_dissolvefacesop,
+ &def_dissolveedgessop,
+ &def_dissolveedgeloopsop,
+ &def_dissolvevertsop,
+ &def_dissolvelimitop,
+ &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_cube,
+ &def_create_circle,
+ &def_create_cone,
+ &def_join_triangles,
+ &def_bevel,
+ &def_beautify_fill,
+ &def_triangle_fill,
+ &def_bridge_loops,
+ &def_solidify,
+};
+
+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..66222c39c68
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -0,0 +1,1376 @@
+/*
+ * ***** 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): Joseph Eagar, Geoffrey Bantle, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_operators.c
+ * \ingroup bmesh
+ *
+ * BMesh operator access.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_mempool.h"
+#include "BLI_listbase.h"
+#include "BLI_array.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+/* forward declarations */
+static void bmo_flag_layer_alloc(BMesh *bm);
+static void bmo_flag_layer_free(BMesh *bm);
+static void bmo_flag_layer_clear(BMesh *bm);
+static int bmesh_name_to_slotcode(BMOpDefine *def, const char *name);
+static int bmesh_name_to_slotcode_check(BMOpDefine *def, const char *name);
+static int bmesh_opname_to_opcode(const char *opname);
+
+static const char *bmo_error_messages[] = {
+ NULL,
+ "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",
+ "Internal mesh error",
+};
+
+
+/* operator slot type information - size of one element of the type given. */
+const int BMO_OPSLOT_TYPEINFO[] = {
+ 0,
+ sizeof(int),
+ sizeof(float),
+ sizeof(void *),
+ 0, /* unused */
+ 0, /* unused */
+ 0, /* unused */
+ sizeof(void *), /* pointer buffer */
+ sizeof(BMOElemMapping)
+};
+
+/* Dummy slot so there is something to return when slot name lookup fails */
+static BMOpSlot BMOpEmptySlot = {0};
+
+void BMO_op_flag_enable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
+{
+ op->flag |= op_flag;
+}
+
+void BMO_op_flag_disable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
+{
+ op->flag &= ~op_flag;
+}
+
+/*
+ * BMESH OPSTACK PUSH
+ *
+ * Pushes the opstack down one level
+ * and allocates a new flag layer if
+ * appropriate.
+ */
+void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
+{
+ bm->stackdepth++;
+
+ /* add flag layer, if appropriate */
+ if (bm->stackdepth > 1)
+ bmo_flag_layer_alloc(bm);
+ else
+ bmo_flag_layer_clear(bm);
+}
+
+/*
+ * BMESH OPSTACK POP
+ *
+ * Pops the opstack one level
+ * and frees a flag layer if appropriate
+ * BMESH_TODO: investigate NOT freeing flag
+ * layers.
+ */
+void BMO_pop(BMesh *bm)
+{
+ if (bm->stackdepth > 1)
+ bmo_flag_layer_free(bm);
+
+ bm->stackdepth--;
+}
+
+/*
+ * BMESH OPSTACK INIT OP
+ *
+ * Initializes an operator structure
+ * to a certain type
+ */
+void BMO_op_init(BMesh *bm, BMOperator *op, const char *opname)
+{
+ int i, opcode = bmesh_opname_to_opcode(opname);
+
+#ifdef DEBUG
+ BM_ELEM_INDEX_VALIDATE(bm, "pre bmo", opname);
+#else
+ (void)bm;
+#endif
+
+ if (opcode == -1) {
+ opcode = 0; /* error!, already printed, have a better way to handle this? */
+ }
+
+ memset(op, 0, sizeof(BMOperator));
+ op->type = opcode;
+ op->flag = opdefines[opcode]->flag;
+
+ /* 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_op_exec(BMesh *bm, BMOperator *op)
+{
+
+ BMO_push(bm, op);
+
+ if (bm->stackdepth == 2)
+ bmesh_begin_edit(bm, op->flag);
+ op->exec(bm, op);
+
+ if (bm->stackdepth == 2)
+ bmesh_end_edit(bm, op->flag);
+
+ BMO_pop(bm);
+}
+
+/*
+ * BMESH OPSTACK FINISH OP
+ *
+ * Does housekeeping chores related to finishing
+ * up an operator.
+ */
+void BMO_op_finish(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 == BMO_OP_SLOT_MAPPING) {
+ if (slot->data.ghash)
+ BLI_ghash_free(slot->data.ghash, NULL, NULL);
+ }
+ }
+
+ BLI_memarena_free(op->arena);
+
+#ifdef DEBUG
+ BM_ELEM_INDEX_VALIDATE(bm, "post bmo", opdefines[op->type]->name);
+#else
+ (void)bm;
+#endif
+}
+
+/*
+ * BMESH OPSTACK HAS SLOT
+ *
+ * Returns 1 if the named slot exists on the given operator,
+ * otherwise returns 0.
+ */
+int BMO_slot_exists(BMOperator *op, const char *slotname)
+{
+ int slotcode = bmesh_name_to_slotcode(opdefines[op->type], slotname);
+ return (slotcode >= 0);
+}
+
+/*
+ * BMESH OPSTACK GET SLOT
+ *
+ * Returns a pointer to the slot of
+ * type 'slotcode'
+ */
+BMOpSlot *BMO_slot_get(BMOperator *op, const char *slotname)
+{
+ int slotcode = bmesh_name_to_slotcode_check(opdefines[op->type], slotname);
+
+ if (slotcode < 0) {
+ return &BMOpEmptySlot;
+ }
+
+ return &(op->slots[slotcode]);
+}
+
+/*
+ * BMESH OPSTACK COPY SLOT
+ *
+ * Copies data from one slot to another
+ */
+void BMO_slot_copy(BMOperator *source_op, BMOperator *dest_op, const char *src, const char *dst)
+{
+ BMOpSlot *source_slot = BMO_slot_get(source_op, src);
+ BMOpSlot *dest_slot = BMO_slot_get(dest_op, dst);
+
+ if (source_slot == dest_slot)
+ return;
+
+ if (source_slot->slottype != dest_slot->slottype)
+ return;
+
+ if (dest_slot->slottype > BMO_OP_SLOT_VEC) {
+ if (dest_slot->slottype != BMO_OP_SLOT_MAPPING) {
+ /* do buffer copy */
+ dest_slot->data.buf = NULL;
+ dest_slot->len = source_slot->len;
+ if (dest_slot->len) {
+ const int slot_alloc_size = BMO_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len;
+ dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, slot_alloc_size);
+ memcpy(dest_slot->data.buf, source_slot->data.buf, slot_alloc_size);
+ }
+ }
+ else {
+ GHashIterator it;
+ BMOElemMapping *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_slot_float_set(BMOperator *op, const char *slotname, const float f)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_FLT))
+ return;
+
+ slot->data.f = f;
+}
+
+void BMO_slot_int_set(BMOperator *op, const char *slotname, const int i)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_INT))
+ return;
+
+ slot->data.i = i;
+}
+
+/* only supports square mats */
+void BMO_slot_mat_set(struct BMOperator *op, const char *slotname, const float *mat, int size)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_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, (float (*)[3])mat);
+ }
+ else {
+ fprintf(stderr, "%s: invalid size argument %d (bmesh internal error)\n", __func__, size);
+
+ memset(slot->data.p, 0, sizeof(float) * 4 * 4);
+ }
+}
+
+void BMO_slot_mat4_get(struct BMOperator *op, const char *slotname, float r_mat[4][4])
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_MAT))
+ return;
+
+ copy_m4_m4(r_mat, (float (*)[4])slot->data.p);
+}
+
+void BMO_slot_mat3_set(struct BMOperator *op, const char *slotname, float r_mat[3][3])
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_MAT))
+ return;
+
+ copy_m3_m4(r_mat, slot->data.p);
+}
+
+void BMO_slot_ptr_set(BMOperator *op, const char *slotname, void *p)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_PNT))
+ return;
+
+ slot->data.p = p;
+}
+
+void BMO_slot_vec_set(BMOperator *op, const char *slotname, const float vec[3])
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_VEC))
+ return;
+
+ copy_v3_v3(slot->data.vec, vec);
+}
+
+
+float BMO_slot_float_get(BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_FLT))
+ return 0.0f;
+
+ return slot->data.f;
+}
+
+int BMO_slot_int_get(BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_INT))
+ return 0;
+
+ return slot->data.i;
+}
+
+
+void *BMO_slot_ptr_get(BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_PNT))
+ return NULL;
+
+ return slot->data.p;
+}
+
+void BMO_slot_vec_get(BMOperator *op, const char *slotname, float r_vec[3])
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ if (!(slot->slottype == BMO_OP_SLOT_VEC))
+ return;
+
+ copy_v3_v3(r_vec, slot->data.vec);
+}
+
+/*
+ * BMO_COUNTFLAG
+ *
+ * Counts the number of elements of a certain type that
+ * have a specific flag set.
+ *
+ */
+
+int BMO_mesh_flag_count(BMesh *bm, const short oflag, const char htype)
+{
+ BMIter elements;
+ int count = 0;
+ BMElemF *ele_f;
+
+ if (htype & BM_VERT) {
+ for (ele_f = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); ele_f; ele_f = BM_iter_step(&elements)) {
+ if (BMO_elem_flag_test(bm, ele_f, oflag))
+ count++;
+ }
+ }
+ if (htype & BM_EDGE) {
+ for (ele_f = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); ele_f; ele_f = BM_iter_step(&elements)) {
+ if (BMO_elem_flag_test(bm, ele_f, oflag))
+ count++;
+ }
+ }
+ if (htype & BM_FACE) {
+ for (ele_f = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); ele_f; ele_f = BM_iter_step(&elements)) {
+ if (BMO_elem_flag_test(bm, ele_f, oflag))
+ count++;
+ }
+ }
+
+ return count;
+}
+
+void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag)
+{
+ const char iter_types[3] = {BM_VERTS_OF_MESH,
+ BM_EDGES_OF_MESH,
+ BM_FACES_OF_MESH};
+
+ const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
+
+ BMIter iter;
+ BMElemF *ele;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (htype & flag_types[i]) {
+ BM_ITER(ele, &iter, bm, iter_types[i], NULL) {
+ BMO_elem_flag_disable(bm, ele, oflag);
+ }
+ }
+ }
+}
+
+int BMO_slot_buf_count(struct BMesh *UNUSED(bm), struct BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+
+ /* check if its actually a buffer */
+ if (!(slot->slottype > BMO_OP_SLOT_VEC))
+ return 0;
+
+ return slot->len;
+}
+
+int BMO_slot_map_count(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+
+ /* check if its actually a buffer */
+ if (!(slot->slottype == BMO_OP_SLOT_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;
+ ssize_t allocsize;
+
+ /* check if its actually a buffer */
+ if (!(slot->slottype > BMO_OP_SLOT_VEC))
+ return NULL;
+
+ if (slot->flag & BMOS_DYNAMIC_ARRAY) {
+ if (slot->len >= slot->size) {
+ slot->size = (slot->size + 1 + totadd) * 2;
+
+ allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size;
+
+ tmp = slot->data.buf;
+ slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
+ memcpy(slot->data.buf, tmp, allocsize);
+ MEM_freeN(tmp);
+ }
+
+ slot->len += totadd;
+ }
+ else {
+ slot->flag |= BMOS_DYNAMIC_ARRAY;
+ slot->len += totadd;
+ slot->size = slot->len + 2;
+
+ allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len;
+
+ tmp = slot->data.buf;
+ slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
+ memcpy(slot->data.buf, tmp, allocsize);
+ }
+
+ return slot->data.buf;
+}
+#endif
+
+void BMO_slot_map_to_flag(struct BMesh *bm, struct BMOperator *op,
+ const char *slotname, const short oflag)
+{
+ GHashIterator it;
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ BMElemF *ele_f;
+
+ /* sanity check */
+ if (slot->slottype != BMO_OP_SLOT_MAPPING) return;
+ if (!slot->data.ghash) return;
+
+ BLI_ghashIterator_init(&it, slot->data.ghash);
+ for ( ; (ele_f = BLI_ghashIterator_getKey(&it)); BLI_ghashIterator_step(&it)) {
+ BMO_elem_flag_enable(bm, ele_f, oflag);
+ }
+}
+
+static void *bmo_slot_buffer_alloc(BMOperator *op, const char *slotname, int len)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+
+ /* check if its actually a buffer */
+ if (!(slot->slottype > BMO_OP_SLOT_VEC))
+ return NULL;
+
+ slot->len = len;
+ if (len)
+ slot->data.buf = BLI_memarena_alloc(op->arena, BMO_OPSLOT_TYPEINFO[slot->slottype] * len);
+ return slot->data.buf;
+}
+
+/*
+ * BMO_ALL_TO_SLOT
+ *
+ * Copies all elements of a certain type into an operator slot.
+ *
+ */
+
+static void BMO_slot_from_all(BMesh *bm, BMOperator *op, const char *slotname, const char htype)
+{
+ BMIter elements;
+ BMHeader *e;
+ BMOpSlot *output = BMO_slot_get(op, slotname);
+ int totelement = 0, i = 0;
+
+ if (htype & BM_VERT) totelement += bm->totvert;
+ if (htype & BM_EDGE) totelement += bm->totedge;
+ if (htype & BM_FACE) totelement += bm->totface;
+
+ if (totelement) {
+ bmo_slot_buffer_alloc(op, slotname, totelement);
+
+ if (htype & BM_VERT) {
+ for (e = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
+ ((BMHeader **)output->data.p)[i] = e;
+ i++;
+ }
+ }
+
+ if (htype & BM_EDGE) {
+ for (e = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
+ ((BMHeader **)output->data.p)[i] = e;
+ i++;
+ }
+ }
+
+ if (htype & BM_FACE) {
+ for (e = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BM_iter_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_slot_from_hflag(BMesh *bm, BMOperator *op, const char *slotname,
+ const char hflag, const char htype)
+{
+ BMIter elements;
+ BMHeader *e;
+ BMOpSlot *output = BMO_slot_get(op, slotname);
+ int totelement = 0, i = 0;
+
+ totelement = BM_mesh_count_flag(bm, htype, hflag, 1);
+
+ if (totelement) {
+ bmo_slot_buffer_alloc(op, slotname, totelement);
+
+ if (htype & BM_VERT) {
+ for (e = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, hflag)) {
+ ((BMHeader **)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+
+ if (htype & BM_EDGE) {
+ for (e = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, hflag)) {
+ ((BMHeader **)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+
+ if (htype & BM_FACE) {
+ for (e = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BM_iter_step(&elements)) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && BM_elem_flag_test(e, hflag)) {
+ ((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_slot_from_flag(BMesh *bm, BMOperator *op, const char *slotname,
+ const short oflag, const char htype)
+{
+ BMIter elements;
+ BMHeader *ele;
+ BMOpSlot *output = BMO_slot_get(op, slotname);
+ int totelement = BMO_mesh_flag_count(bm, oflag, htype), i = 0;
+
+ if (totelement) {
+ bmo_slot_buffer_alloc(op, slotname, totelement);
+
+ if (htype & BM_VERT) {
+ for (ele = BM_iter_new(&elements, bm, BM_VERTS_OF_MESH, bm); ele; ele = BM_iter_step(&elements)) {
+ if (BMO_elem_flag_test(bm, (BMElemF *)ele, oflag)) {
+ ((BMHeader **)output->data.p)[i] = ele;
+ i++;
+ }
+ }
+ }
+
+ if (htype & BM_EDGE) {
+ for (ele = BM_iter_new(&elements, bm, BM_EDGES_OF_MESH, bm); ele; ele = BM_iter_step(&elements)) {
+ if (BMO_elem_flag_test(bm, (BMElemF *)ele, oflag)) {
+ ((BMHeader **)output->data.p)[i] = ele;
+ i++;
+ }
+ }
+ }
+
+ if (htype & BM_FACE) {
+ for (ele = BM_iter_new(&elements, bm, BM_FACES_OF_MESH, bm); ele; ele = BM_iter_step(&elements)) {
+ if (BMO_elem_flag_test(bm, (BMElemF *)ele, oflag)) {
+ ((BMHeader **)output->data.p)[i] = ele;
+ i++;
+ }
+ }
+ }
+ }
+ else {
+ output->len = 0;
+ }
+}
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Header Flags elements in a slots buffer, automatically
+ * using the selection API where appropriate.
+ */
+void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOperator *op, const char *slotname,
+ const char hflag, const char htype)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for (i = 0; i < slot->len; i++) {
+ if (!(htype & data[i]->htype))
+ continue;
+
+ if (hflag & BM_ELEM_SELECT) {
+ BM_elem_select_set(bm, data[i], TRUE);
+ }
+ BM_elem_flag_enable(data[i], hflag);
+ }
+}
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Removes flags from elements in a slots buffer, automatically
+ * using the selection API where appropriate.
+ */
+void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOperator *op, const char *slotname,
+ const char hflag, const char htype)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for (i = 0; i < slot->len; i++) {
+ if (!(htype & data[i]->htype))
+ continue;
+
+ if (hflag & BM_ELEM_SELECT) {
+ BM_elem_select_set(bm, data[i], FALSE);
+ }
+
+ BM_elem_flag_disable(data[i], hflag);
+ }
+}
+int BMO_vert_edge_flags_count(BMesh *bm, BMVert *v, const short oflag)
+{
+ int count = 0;
+
+ if (v->e) {
+ BMEdge *curedge;
+ const int len = bmesh_disk_count(v);
+ int i;
+
+ for (i = 0, curedge = v->e; i < len; i++) {
+ if (BMO_elem_flag_test(bm, curedge, oflag))
+ count++;
+ curedge = bmesh_disk_nextedge(curedge, v);
+ }
+ }
+
+ return count;
+}
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Flags elements in a slots buffer
+ */
+void BMO_slot_buffer_flag_enable(BMesh *bm, BMOperator *op, const char *slotname,
+ const short oflag, const char htype)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for (i = 0; i < slot->len; i++) {
+ if (!(htype & data[i]->htype))
+ continue;
+
+ BMO_elem_flag_enable(bm, (BMElemF *)data[i], oflag);
+ }
+}
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Removes flags from elements in a slots buffer
+ */
+void BMO_slot_buffer_flag_disable(BMesh *bm, BMOperator *op, const char *slotname,
+ const short oflag, const char htype)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for (i = 0; i < slot->len; i++) {
+ if (!(htype & data[i]->htype))
+ continue;
+
+ BMO_elem_flag_disable(bm, (BMElemF *)data[i], oflag);
+ }
+}
+
+
+/*
+ *
+ * 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.
+ *
+ * BMESH_TODO:
+ * Investigate not freeing flag layers until
+ * all operators have been executed. This would
+ * save a lot of realloc potentially.
+ */
+static void bmo_flag_layer_alloc(BMesh *bm)
+{
+ BMElemF *ele;
+ /* set the index values since we are looping over all data anyway,
+ * may save time later on */
+ int i;
+
+ BMIter iter;
+ BLI_mempool *oldpool = bm->toolflagpool; /* old flag pool */
+ BLI_mempool *newpool;
+ void *oldflags;
+
+ /* store memcpy size for reuse */
+ const size_t old_totflags_size = (bm->totflags * sizeof(BMFlagLayer));
+
+ bm->totflags++;
+
+ /* allocate new flag poo */
+ bm->toolflagpool = newpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512, FALSE, FALSE);
+
+ /* now go through and memcpy all the flags. Loops don't get a flag layer at this time.. */
+ for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ oldflags = ele->oflags;
+ ele->oflags = BLI_mempool_calloc(newpool);
+ memcpy(ele->oflags, oldflags, old_totflags_size);
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+ for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ oldflags = ele->oflags;
+ ele->oflags = BLI_mempool_calloc(newpool);
+ memcpy(ele->oflags, oldflags, old_totflags_size);
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+ for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ oldflags = ele->oflags;
+ ele->oflags = BLI_mempool_calloc(newpool);
+ memcpy(ele->oflags, oldflags, old_totflags_size);
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+
+ bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
+
+ BLI_mempool_destroy(oldpool);
+}
+
+static void bmo_flag_layer_free(BMesh *bm)
+{
+ BMElemF *ele;
+ /* set the index values since we are looping over all data anyway,
+ * may save time later on */
+ int i;
+
+ BMIter iter;
+ BLI_mempool *oldpool = bm->toolflagpool;
+ BLI_mempool *newpool;
+ void *oldflags;
+
+ /* store memcpy size for reuse */
+ const size_t new_totflags_size = ((bm->totflags - 1) * sizeof(BMFlagLayer));
+
+ /* de-increment the totflags first.. */
+ bm->totflags--;
+ /* allocate new flag poo */
+ bm->toolflagpool = newpool = BLI_mempool_create(new_totflags_size, 512, 512, TRUE, FALSE);
+
+ /* now go through and memcpy all the flag */
+ for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ oldflags = ele->oflags;
+ ele->oflags = BLI_mempool_calloc(newpool);
+ memcpy(ele->oflags, oldflags, new_totflags_size);
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+ for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ oldflags = ele->oflags;
+ ele->oflags = BLI_mempool_calloc(newpool);
+ memcpy(ele->oflags, oldflags, new_totflags_size);
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+ for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ oldflags = ele->oflags;
+ ele->oflags = BLI_mempool_calloc(newpool);
+ memcpy(ele->oflags, oldflags, new_totflags_size);
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+
+ bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
+
+ BLI_mempool_destroy(oldpool);
+}
+
+static void bmo_flag_layer_clear(BMesh *bm)
+{
+ BMElemF *ele;
+ /* set the index values since we are looping over all data anyway,
+ * may save time later on */
+ int i;
+
+ BMIter iter;
+ const int totflags_offset = bm->totflags - 1;
+
+ /* now go through and memcpy all the flag */
+ for (ele = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+ for (ele = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+ for (ele = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, bm), i = 0; ele; ele = BM_iter_step(&iter), i++) {
+ memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
+ BM_elem_index_set(ele, i); /* set_inline */
+ }
+
+ bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
+}
+
+void *BMO_slot_elem_first(BMOperator *op, const char *slotname)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+
+ if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
+ return NULL;
+
+ return slot->data.buf ? *(void **)slot->data.buf : NULL;
+}
+
+void *BMO_iter_new(BMOIter *iter, BMesh *UNUSED(bm), BMOperator *op,
+ const char *slotname, const char restrictmask)
+{
+ BMOpSlot *slot = BMO_slot_get(op, slotname);
+
+ memset(iter, 0, sizeof(BMOIter));
+
+ iter->slot = slot;
+ iter->cur = 0;
+ iter->restrictmask = restrictmask;
+
+ if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
+ if (iter->slot->data.ghash) {
+ BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
+ }
+ else {
+ return NULL;
+ }
+ }
+
+ return BMO_iter_step(iter);
+}
+
+void *BMO_iter_step(BMOIter *iter)
+{
+ if (iter->slot->slottype == BMO_OP_SLOT_ELEMENT_BUF) {
+ BMHeader *h;
+
+ if (iter->cur >= iter->slot->len) {
+ return NULL;
+ }
+
+ h = ((void **)iter->slot->data.buf)[iter->cur++];
+ while (!(iter->restrictmask & h->htype)) {
+ if (iter->cur >= iter->slot->len) {
+ return NULL;
+ }
+
+ h = ((void **)iter->slot->data.buf)[iter->cur++];
+ }
+
+ return h;
+ }
+ else if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
+ struct BMOElemMapping *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 mapping */
+void *BMO_iter_map_value(BMOIter *iter)
+{
+ return iter->val;
+}
+
+void *BMO_iter_map_value_p(BMOIter *iter)
+{
+ return *((void **)iter->val);
+}
+
+float BMO_iter_map_value_f(BMOIter *iter)
+{
+ return *((float *)iter->val);
+}
+
+/* error syste */
+typedef struct BMOpError {
+ struct BMOpError *next, *prev;
+ int errorcode;
+ BMOperator *op;
+ const char *msg;
+} BMOpError;
+
+void BMO_error_clear(BMesh *bm)
+{
+ while (BMO_error_pop(bm, NULL, NULL));
+}
+
+void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
+{
+ BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
+
+ err->errorcode = errcode;
+ if (!msg) msg = bmo_error_messages[errcode];
+ err->msg = msg;
+ err->op = owner;
+
+ BLI_addhead(&bm->errorstack, err);
+}
+
+int BMO_error_occurred(BMesh *bm)
+{
+ return bm->errorstack.first != NULL;
+}
+
+/* returns error code or 0 if no erro */
+int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
+{
+ BMOpError *err = bm->errorstack.first;
+ if (!err) {
+ return 0;
+ }
+
+ if (msg) *msg = err->msg;
+ if (op) *op = err->op;
+
+ return err->errorcode;
+}
+
+int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op)
+{
+ int errorcode = BMO_error_get(bm, msg, op);
+
+ if (errorcode) {
+ BMOpError *err = bm->errorstack.first;
+
+ BLI_remlink(&bm->errorstack, bm->errorstack.first);
+ MEM_freeN(err);
+ }
+
+ return errorcode;
+}
+
+/* example:
+ * BMO_CallOp(bm, "del %d %hv", DEL_ONLYFACES, BM_ELEM_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 NEXT_CHAR(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 (!strncmp(name, def->slottypes[i].name, MAX_SLOTNAME)) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static int bmesh_name_to_slotcode_check(BMOpDefine *def, const char *name)
+{
+ int i = bmesh_name_to_slotcode(def, name);
+ if (i < 0) {
+ fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, name);
+ }
+
+ return i;
+}
+
+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)) {
+ return i;
+ }
+ }
+
+ fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname);
+ return -1;
+}
+
+int BMO_op_vinitf(BMesh *bm, BMOperator *op, const char *_fmt, va_list vlist)
+{
+ BMOpDefine *def;
+ char *opname, *ofmt, *fmt;
+ char slotname[64] = {0};
+ int i /*, n = strlen(fmt) */, stop /*, slotcode = -1 */, ret, type, state;
+ int noslot = 0;
+
+
+ /* basic useful info to help find where bmop formatting strings fail */
+ int lineno = -1;
+# define GOTO_ERROR { lineno = __LINE__; goto error; }
+
+
+ /* we muck around in here, so dup i */
+ fmt = ofmt = BLI_strdup(_fmt);
+
+ /* find operator nam */
+ i = strcspn(fmt, " \t");
+
+ opname = fmt;
+ if (!opname[i]) noslot = 1;
+ opname[i] = '\0';
+
+ fmt += i + (noslot ? 0 : 1);
+
+ i = bmesh_opname_to_opcode(opname);
+
+ if (i == -1) {
+ MEM_freeN(ofmt);
+ return FALSE;
+ }
+
+ BMO_op_init(bm, op, opname);
+ def = opdefines[i];
+
+ i = 0;
+ state = 1; /* 0: not inside slotcode name, 1: inside slotcode name */
+
+ while (*fmt) {
+ if (state) {
+ /* jump past leading whitespac */
+ i = strspn(fmt, " \t");
+ fmt += i;
+
+ /* ignore trailing whitespac */
+ 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;
+
+ BLI_strncpy(slotname, fmt, sizeof(slotname));
+
+ state = 0;
+ fmt += i;
+ }
+ else {
+ switch (*fmt) {
+ case ' ':
+ case '\t':
+ case '=':
+ case '%':
+ break;
+ case 'm': {
+ int size, c;
+
+ c = NEXT_CHAR(fmt);
+ fmt++;
+
+ if (c == '3') size = 3;
+ else if (c == '4') size = 4;
+ else GOTO_ERROR;
+
+ BMO_slot_mat_set(op, slotname, va_arg(vlist, void *), size);
+ state = 1;
+ break;
+ }
+ case 'v': {
+ BMO_slot_vec_set(op, slotname, va_arg(vlist, float *));
+ state = 1;
+ break;
+ }
+ case 'e': {
+ BMHeader *ele = va_arg(vlist, void *);
+ BMOpSlot *slot = BMO_slot_get(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_slot_copy(op2, op, slotname2, slotname);
+ state = 1;
+ break;
+ }
+ case 'i':
+ case 'd':
+ BMO_slot_int_set(op, slotname, va_arg(vlist, int));
+ state = 1;
+ break;
+ case 'p':
+ BMO_slot_ptr_set(op, slotname, va_arg(vlist, void *));
+ state = 1;
+ break;
+ case 'f':
+ case 'h':
+ case 'a':
+ type = *fmt;
+
+ if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\t' || NEXT_CHAR(fmt) == '\0') {
+ BMO_slot_float_set(op, slotname, va_arg(vlist, double));
+ }
+ else {
+ ret = 0;
+ stop = 0;
+ while (1) {
+ switch (NEXT_CHAR(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_slot_from_hflag(bm, op, slotname, va_arg(vlist, int), ret);
+ }
+ else if (type == 'a') {
+ BMO_slot_from_all(bm, op, slotname, ret);
+ }
+ else {
+ BMO_slot_from_flag(bm, op, slotname, va_arg(vlist, int), ret);
+ }
+ }
+
+ state = 1;
+ break;
+ default:
+ fprintf(stderr,
+ "%s: unrecognized bmop format char: %c, %d in '%s'\n",
+ __func__, *fmt, (int)(fmt - ofmt), ofmt);
+ break;
+ }
+ }
+ fmt++;
+ }
+
+ MEM_freeN(ofmt);
+ return TRUE;
+error:
+
+ /* non urgent todo - explain exactly what is failing */
+ fprintf(stderr,
+ "%s: error parsing formatting string, %d in '%s'\n see - %s:%d\n",
+ __func__, (int)(fmt - ofmt), _fmt, __FILE__, lineno);
+ MEM_freeN(ofmt);
+
+ BMO_op_finish(bm, op);
+ return FALSE;
+
+#undef GOTO_ERROR
+
+}
+
+
+int BMO_op_initf(BMesh *bm, BMOperator *op, const char *fmt, ...)
+{
+ va_list list;
+
+ va_start(list, fmt);
+ if (!BMO_op_vinitf(bm, op, fmt, list)) {
+ printf("%s: failed\n", __func__);
+ va_end(list);
+ return FALSE;
+ }
+ va_end(list);
+
+ return TRUE;
+}
+
+int BMO_op_callf(BMesh *bm, const char *fmt, ...)
+{
+ va_list list;
+ BMOperator op;
+
+ va_start(list, fmt);
+ if (!BMO_op_vinitf(bm, &op, fmt, list)) {
+ printf("%s: failed, format is:\n \"%s\"\n", __func__, fmt);
+ va_end(list);
+ return FALSE;
+ }
+
+ BMO_op_exec(bm, &op);
+ BMO_op_finish(bm, &op);
+
+ va_end(list);
+ return TRUE;
+}
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..4cc338bfdd0
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_operators_private.h
@@ -0,0 +1,106 @@
+/*
+ * ***** 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): Joseph Eagar, Geoffrey Bantle, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_OPERATORS_PRIVATE_H__
+#define __BMESH_OPERATORS_PRIVATE_H__
+
+/** \file blender/bmesh/intern/bmesh_operators_private.h
+ * \ingroup bmesh
+ */
+
+struct BMesh;
+struct BMOperator;
+
+void BMO_push(BMesh *bm, BMOperator *op);
+void BMO_pop(BMesh *bm);
+
+void splitop_exec(BMesh *bm, BMOperator *op);
+void spinop_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 dissolvelimit_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);
+void bmesh_bevel_exec(BMesh *bm, BMOperator *op);
+void bmesh_beautify_fill_exec(BMesh *bm, BMOperator *op);
+void bmesh_triangle_fill_exec(BMesh *bm, BMOperator *op);
+void bmesh_create_circle_exec(BMesh *bm, BMOperator *op);
+void bmesh_bridge_loops_exec(BMesh *bm, BMOperator *op);
+void bmesh_solidify_face_region_exec(BMesh *bm, BMOperator *op);
+
+#endif /* __BMESH_OPERATORS_PRIVATE_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
new file mode 100644
index 00000000000..07945466a0c
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -0,0 +1,1069 @@
+/*
+ * ***** 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): Joseph Eagar, Geoffrey Bantle, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_polygon.c
+ * \ingroup bmesh
+ *
+ * This file contains code for dealing
+ * with polygons (normal/area calculation,
+ * tesselation, etc)
+ *
+ * BMESH_TODO:
+ * - Add in Tesselator frontend that creates
+ * BMTriangles from copied faces
+ *
+ * - Add in Function that checks for and flags
+ * degenerate faces.
+ */
+
+#include "BLI_math.h"
+#include "BLI_array.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+/*
+ * TEST EDGE SIDE and POINT IN TRIANGLE
+ *
+ * Point in triangle tests stolen from scanfill.c.
+ * Used for tesselator
+ *
+ */
+
+static short testedgeside(const double v1[2], const double v2[2], const double v3[2])
+{
+ /* 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 FALSE;
+ }
+ else if (inp == 0) {
+ if (v1[0] == v3[0] && v1[1] == v3[1]) return FALSE;
+ if (v2[0] == v3[0] && v2[1] == v3[1]) return FALSE;
+ }
+ return TRUE;
+}
+
+static short testedgesidef(const float v1[2], const float v2[2], const float v3[2])
+{
+ /* 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 FALSE;
+ }
+ else if (inp == 0) {
+ if (v1[0] == v3[0] && v1[1] == v3[1]) return FALSE;
+ if (v2[0] == v3[0] && v2[1] == v3[1]) return FALSE;
+ }
+ return TRUE;
+}
+
+static int point_in_triangle(const double v1[2], const double v2[2], const double v3[2], const double pt[2])
+{
+ if (testedgeside(v1, v2, pt) && testedgeside(v2, v3, pt) && testedgeside(v3, v1, pt)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * COMPUTE POLY NORMAL
+ *
+ * Computes the normal of a planar
+ * polygon See Graphics Gems for
+ * computing newell normal.
+ *
+ */
+
+static void compute_poly_normal(float normal[3], float (*verts)[3], int nverts)
+{
+
+ float u[3], v[3], w[3]; /*, *w, v1[3], v2[3]; */
+ float n[3] = {0.0f, 0.0f, 0.0f} /*, l, v1[3], v2[3] */;
+ /* double l2; */
+ int i /*, s = 0 */;
+
+ /* this fixes some weird numerical erro */
+ add_v3_fl(verts[0], 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
+ sub_v3_v3v3(v1, w, v);
+ sub_v3_v3v3(v2, v, u);
+ normalize_v3(v1);
+ normalize_v3(v2);
+
+ l = dot_v3v3(v1, v2);
+ if (fabsf(l - 1.0) < 0.1f) {
+ 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]);
+ }
+
+ if (normalize_v3_v3(normal, n) == 0.0f) {
+ normal[2] = 1.0f; /* other axis set to 0.0 */
+ }
+
+#if 0
+ l = len_v3(n);
+ /* 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;
+ }
+
+ mul_v3_fl(n, l);
+
+ copy_v3_v3(normal, n);
+#endif
+}
+
+/*
+ * 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 *r_area, float (*verts)[3], int nverts)
+{
+ int i, j;
+ float atmp = 0.0f, xtmp = 0.0f, ytmp = 0.0f, ai;
+
+ zero_v3(center);
+
+ if (nverts < 3)
+ return FALSE;
+
+ 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 (r_area)
+ *r_area = atmp / 2.0f;
+
+ if (atmp != 0) {
+ center[0] = xtmp / (3.0f * atmp);
+ center[1] = xtmp / (3.0f * atmp);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+float BM_face_area_calc(BMesh *bm, BMFace *f)
+{
+ BMLoop *l;
+ BMIter iter;
+ float (*verts)[3];
+ float center[3];
+ float area = 0.0f;
+ int i;
+
+ BLI_array_fixedstack_declare(verts, BM_NGON_STACK_SIZE, f->len, __func__);
+
+ i = 0;
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
+ copy_v3_v3(verts[i], l->v->co);
+ i++;
+ }
+
+ compute_poly_center(center, &area, verts, f->len);
+
+ BLI_array_fixedstack_free(verts);
+
+ return area;
+}
+
+/*
+ * computes center of face in 3d. uses center of bounding box.
+ */
+void BM_face_center_bounds_calc(BMesh *bm, BMFace *f, float r_cent[3])
+{
+ BMIter iter;
+ BMLoop *l;
+ float min[3], max[3];
+ int i;
+
+ INIT_MINMAX(min, max);
+ l = BM_iter_new(&iter, bm, BM_LOOPS_OF_FACE, f);
+ for (i = 0; l; l = BM_iter_step(&iter), i++) {
+ DO_MINMAX(l->v->co, min, max);
+ }
+
+ mid_v3_v3v3(r_cent, min, max);
+}
+
+void BM_face_center_mean_calc(BMesh *bm, BMFace *f, float r_cent[3])
+{
+ BMIter iter;
+ BMLoop *l;
+ int i;
+
+ zero_v3(r_cent);
+
+ l = BM_iter_new(&iter, bm, BM_LOOPS_OF_FACE, f);
+ for (i = 0; l; l = BM_iter_step(&iter), i++) {
+ add_v3_v3(r_cent, l->v->co);
+ }
+
+ if (f->len) mul_v3_fl(r_cent, 1.0f / (float)f->len);
+}
+
+/*
+ * 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], mag, avgn[3];
+ float *v1, *v2, *v3;
+ int i;
+
+ if (nverts < 3)
+ return;
+
+ zero_v3(avgn);
+ zero_v3(avgc);
+
+ 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);
+
+ add_v3_v3(avgn, norm);
+ }
+
+ /* what was this bit for */
+ if (is_zero_v3(avgn)) {
+ avgn[0] = 0.0f;
+ avgn[1] = 0.0f;
+ avgn[2] = 1.0f;
+ }
+ else {
+ /* XXX, why is this being divided and _then_ normalized
+ * division could be removed? - campbell */
+ avgn[0] /= nverts;
+ avgn[1] /= nverts;
+ avgn[2] /= nverts;
+ normalize_v3(avgn);
+ }
+
+ for (i = 0; i < nverts; i++) {
+ v1 = verts[i];
+ mag = dot_v3v3(v1, avgn);
+ madd_v3_v3fl(v1, avgn, -mag);
+ }
+}
+
+/*
+ * 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.
+ */
+#if 0 /* needs BLI math double versions of these functions */
+static void shrink_edged(double *v1, double *v2, double fac)
+{
+ double mid[3];
+
+ mid_v3_v3v3(mid, v1, v2);
+
+ 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);
+}
+#endif
+
+static void shrink_edgef(float v1[3], float v2[3], const float fac)
+{
+ float mid[3];
+
+ mid_v3_v3v3(mid, v1, v2);
+
+ 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(const float normal[3], float (*verts)[3], const 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, normal, up);
+
+ angle = saacos(dot_v3v3(normal, up));
+
+ if (angle == 0.0) 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_normal_update(BMesh *bm, BMFace *f)
+{
+ if (f->len >= 3) {
+ float (*proj)[3];
+
+ BLI_array_fixedstack_declare(proj, BM_NGON_STACK_SIZE, f->len, __func__);
+
+ bmesh_update_face_normal(bm, f, f->no, proj);
+
+ BLI_array_fixedstack_free(proj);
+ }
+}
+/* same as BM_face_normal_update but takes vertex coords */
+void BM_face_normal_update_vcos(BMesh *bm, BMFace *f, float no[3], float (*vertexCos)[3])
+{
+ if (f->len >= 3) {
+ float (*proj)[3];
+
+ BLI_array_fixedstack_declare(proj, BM_NGON_STACK_SIZE, f->len, __func__);
+
+ bmesh_update_face_normal_vertex_cos(bm, f, no, proj, vertexCos);
+
+ BLI_array_fixedstack_free(proj);
+ }
+}
+
+void BM_edge_normals_update(BMesh *bm, BMEdge *e)
+{
+ BMIter iter;
+ BMFace *f;
+
+ f = BM_iter_new(&iter, bm, BM_FACES_OF_EDGE, e);
+ for ( ; f; f = BM_iter_step(&iter)) {
+ BM_face_normal_update(bm, f);
+ }
+
+ BM_vert_normal_update(bm, e->v1);
+ BM_vert_normal_update(bm, e->v2);
+}
+
+void BM_vert_normal_update(BMesh *bm, BMVert *v)
+{
+ /* TODO, we can normalize each edge only once, then compare with previous edge */
+
+ BMIter eiter, liter;
+ BMEdge *e;
+ BMLoop *l;
+ float vec1[3], vec2[3], fac;
+ int len = 0;
+
+ zero_v3(v->no);
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_EDGE, e) {
+ if (l->v == v) {
+ /* Same calculation used in BM_mesh_normals_update */
+ sub_v3_v3v3(vec1, l->v->co, l->prev->v->co);
+ sub_v3_v3v3(vec2, l->next->v->co, l->v->co);
+ normalize_v3(vec1);
+ normalize_v3(vec2);
+
+ fac = saacos(-dot_v3v3(vec1, vec2));
+
+ madd_v3_v3fl(v->no, l->f->no, fac);
+
+ len++;
+ }
+ }
+ }
+
+ if (len) {
+ normalize_v3(v->no);
+ }
+}
+
+void BM_vert_normal_update_all(BMesh *bm, BMVert *v)
+{
+ BMIter iter;
+ BMFace *f;
+ int len = 0;
+
+ f = BM_iter_new(&iter, bm, BM_FACES_OF_VERT, v);
+ for ( ; f; f = BM_iter_step(&iter), len++) {
+ BM_face_normal_update(bm, f);
+ }
+
+ BM_vert_normal_update(bm, v);
+}
+
+void bmesh_update_face_normal(BMesh *bm, BMFace *f, float no[3],
+ float (*projectverts)[3])
+{
+ BMLoop *l;
+
+ /* common cases first */
+ switch (f->len) {
+ case 4:
+ {
+ BMVert *v1 = (l = BM_FACE_FIRST_LOOP(f))->v;
+ BMVert *v2 = (l = l->next)->v;
+ BMVert *v3 = (l = l->next)->v;
+ BMVert *v4 = (l->next)->v;
+ normal_quad_v3(no, v1->co, v2->co, v3->co, v4->co);
+ break;
+ }
+ case 3:
+ {
+ BMVert *v1 = (l = BM_FACE_FIRST_LOOP(f))->v;
+ BMVert *v2 = (l = l->next)->v;
+ BMVert *v3 = (l->next)->v;
+ normal_tri_v3(no, v1->co, v2->co, v3->co);
+ break;
+ }
+ case 0:
+ {
+ zero_v3(no);
+ break;
+ }
+ default:
+ {
+ BMIter iter;
+ int i = 0;
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
+ copy_v3_v3(projectverts[i], l->v->co);
+ i += 1;
+ }
+ compute_poly_normal(no, projectverts, f->len);
+ break;
+ }
+ }
+}
+/* exact same as 'bmesh_update_face_normal' but accepts vertex coords */
+void bmesh_update_face_normal_vertex_cos(BMesh *bm, BMFace *f, float no[3],
+ float (*projectverts)[3], float (*vertexCos)[3])
+{
+ BMLoop *l;
+
+ /* must have valid index data */
+ BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
+
+ /* common cases first */
+ switch (f->len) {
+ case 4:
+ {
+ BMVert *v1 = (l = BM_FACE_FIRST_LOOP(f))->v;
+ BMVert *v2 = (l = l->next)->v;
+ BMVert *v3 = (l = l->next)->v;
+ BMVert *v4 = (l->next)->v;
+ normal_quad_v3(no,
+ vertexCos[BM_elem_index_get(v1)],
+ vertexCos[BM_elem_index_get(v2)],
+ vertexCos[BM_elem_index_get(v3)],
+ vertexCos[BM_elem_index_get(v4)]);
+ break;
+ }
+ case 3:
+ {
+ BMVert *v1 = (l = BM_FACE_FIRST_LOOP(f))->v;
+ BMVert *v2 = (l = l->next)->v;
+ BMVert *v3 = (l->next)->v;
+ normal_tri_v3(no,
+ vertexCos[BM_elem_index_get(v1)],
+ vertexCos[BM_elem_index_get(v2)],
+ vertexCos[BM_elem_index_get(v3)]);
+ break;
+ }
+ case 0:
+ {
+ zero_v3(no);
+ break;
+ }
+ default:
+ {
+ BMIter iter;
+ int i = 0;
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
+ copy_v3_v3(projectverts[i], vertexCos[BM_elem_index_get(l->v)]);
+ i += 1;
+ }
+ compute_poly_normal(no, projectverts, f->len);
+ break;
+ }
+ }
+}
+
+/*
+ * BMESH FLIP NORMAL
+ *
+ * Reverses the winding of a face.
+ * Note that this updates the calculated
+ * normal.
+ */
+void BM_face_normal_flip(BMesh *bm, BMFace *f)
+{
+ bmesh_loop_reverse(bm, f);
+ negate_v3(f->no);
+}
+
+/* detects if two line segments cross each other (intersects).
+ * note, there could be more winding cases then there needs to be. */
+static int UNUSED_FUNCTION(linecrosses)(const double v1[2], const double v2[2], const double v3[2], const double v4[2])
+{
+ 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. */
+static int linecrossesf(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
+{
+ int w1, w2, w3, w4, w5 /*, re */;
+ float mv1[2], mv2[2], mv3[2], mv4[2];
+
+ /* now test windin */
+ 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);
+
+ if (w1 == w2 && w2 == w3 && w3 == w4 && w4 == w5) {
+ return TRUE;
+ }
+
+#define GETMIN2_AXIS(a, b, ma, mb, axis) ma[axis] = MIN2(a[axis], b[axis]), mb[axis] = MAX2(a[axis], b[axis])
+#define GETMIN2(a, b, ma, mb) GETMIN2_AXIS(a, b, ma, mb, 0); GETMIN2_AXIS(a, b, ma, mb, 1);
+
+ GETMIN2(v1, v2, mv1, mv2);
+ GETMIN2(v3, v4, mv3, mv4);
+
+ /* do an interval test on the x and y axe */
+ /* first do x axi */
+#define T FLT_EPSILON * 15
+ if ( ABS(v1[1] - v2[1]) < T &&
+ ABS(v3[1] - v4[1]) < T &&
+ ABS(v1[1] - v3[1]) < T)
+ {
+ return (mv4[0] >= mv1[0] && mv3[0] <= mv2[0]);
+ }
+
+ /* now do y axi */
+ if ( ABS(v1[0] - v2[0]) < T &&
+ ABS(v3[0] - v4[0]) < T &&
+ ABS(v1[0] - v3[0]) < T)
+ {
+ return (mv4[1] >= mv1[1] && mv3[1] <= mv2[1]);
+ }
+
+ return FALSE;
+}
+
+/*
+ * BM POINT IN FACE
+ *
+ * Projects co onto face f, and returns true if it is inside
+ * the face bounds. Note that this uses a best-axis projection
+ * test, instead of projecting co directly into f's orientation
+ * space, so there might be accuracy issues.
+ */
+int BM_face_point_inside_test(BMesh *bm, BMFace *f, const float co[3])
+{
+ int ax, ay;
+ float co2[3], cent[3] = {0.0f, 0.0f, 0.0f}, out[3] = {FLT_MAX * 0.5f, FLT_MAX * 0.5f, 0};
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ int crosses = 0;
+ float eps = 1.0f + (float)FLT_EPSILON * 150.0f;
+
+ if (dot_v3v3(f->no, f->no) <= FLT_EPSILON * 10)
+ BM_face_normal_update(bm, f);
+
+ /* find best projection of face XY, XZ or YZ: barycentric weights of
+ * the 2d projected coords are the same and faster to compute
+ *
+ * this probably isn't all that accurate, but it has the advantage of
+ * being fast (especially compared to projecting into the face orientation)
+ */
+ axis_dominant_v3(&ax, &ay, f->no);
+
+ co2[0] = co[ax];
+ co2[1] = co[ay];
+ co2[2] = 0;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ cent[0] += l_iter->v->co[ax];
+ cent[1] += l_iter->v->co[ay];
+ } while ((l_iter = l_iter->next) != l_first);
+
+ mul_v2_fl(cent, 1.0f / (float)f->len);
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ float v1[3], v2[3];
+
+ v1[0] = (l_iter->prev->v->co[ax] - cent[ax]) * eps + cent[ax];
+ v1[1] = (l_iter->prev->v->co[ay] - cent[ay]) * eps + cent[ay];
+ v1[2] = 0.0f;
+
+ v2[0] = (l_iter->v->co[ax] - cent[ax]) * eps + cent[ax];
+ v2[1] = (l_iter->v->co[ay] - cent[ay]) * eps + cent[ay];
+ v2[2] = 0.0f;
+
+ crosses += linecrossesf(v1, v2, co2, out) != 0;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ return crosses % 2 != 0;
+}
+
+static int goodline(float (*projectverts)[3], BMFace *f, int v1i,
+ int v2i, int v3i, int UNUSED(nvert))
+{
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ 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 FALSE;
+ }
+
+ //for (i = 0; i < nvert; i++) {
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ i = BM_elem_index_get(l_iter->v);
+ if (i == v1i || i == v2i || i == v3i) {
+ continue;
+ }
+
+ VECCOPY(pv1, projectverts[BM_elem_index_get(l_iter->v)]);
+ VECCOPY(pv2, projectverts[BM_elem_index_get(l_iter->next->v)]);
+
+ //if (linecrosses(pv1, pv2, v1, v3)) return FALSE;
+
+ if ( point_in_triangle(v1, v2, v3, pv1) ||
+ point_in_triangle(v3, v2, v1, pv1))
+ {
+ return FALSE;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ return TRUE;
+}
+/*
+ * FIND EAR
+ *
+ * Used by tesselator to find
+ * the next triangle to 'clip off'
+ * of a polygon while tesselating.
+ *
+ */
+
+static BMLoop *find_ear(BMesh *UNUSED(bm), BMFace *f, float (*verts)[3], const int nvert)
+{
+ BMVert *v1, *v2, *v3;
+ BMLoop *bestear = NULL;
+
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ /* float angle, bestangle = 180.0f; */
+ int isear /*, i = 0 */;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ isear = 1;
+
+ v1 = l_iter->prev->v;
+ v2 = l_iter->v;
+ v3 = l_iter->next->v;
+
+ if (BM_edge_exists(v1, v3)) {
+ isear = 0;
+ }
+ else if (!goodline(verts, f, BM_elem_index_get(v1), BM_elem_index_get(v2), BM_elem_index_get(v3), nvert)) {
+ isear = 0;
+ }
+
+ if (isear) {
+#if 0
+ 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;
+#endif
+
+ bestear = l_iter;
+ break;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ 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_face_triangulate(BMesh *bm, BMFace *f, float (*projectverts)[3],
+ const short newedge_oflag, const short newface_oflag, BMFace **newfaces)
+{
+ int i, done, nvert, nf_i = 0;
+ BMLoop *newl, *nextloop;
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ /* BMVert *v; */ /* UNUSED */
+
+ /* copy vertex coordinates to vertspace arra */
+ i = 0;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ copy_v3_v3(projectverts[i], l_iter->v->co);
+ BM_elem_index_set(l_iter->v, i); /* set dirty! */
+ i++;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ bm->elem_index_dirty |= BM_VERT; /* see above */
+
+ ///bmesh_update_face_normal(bm, f, f->no, 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_iter = find_ear(bm, f, projectverts, nvert);
+ if (l_iter) {
+ done = 0;
+ /* v = l->v; */ /* UNUSED */
+ f = BM_face_split(bm, l_iter->f, l_iter->prev->v,
+ l_iter->next->v,
+ &newl, NULL);
+ copy_v3_v3(f->no, l_iter->f->no);
+
+ if (!f) {
+ fprintf(stderr, "%s: triangulator failed to split face! (bmesh internal error)\n", __func__);
+ break;
+ }
+
+ BMO_elem_flag_enable(bm, newl->e, newedge_oflag);
+ BMO_elem_flag_enable(bm, f, newface_oflag);
+
+ 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_iter = BM_FACE_FIRST_LOOP(f);
+ while (l_iter->f->len > 3) {
+ nextloop = l_iter->next->next;
+ f = BM_face_split(bm, l_iter->f, l_iter->v, nextloop->v,
+ &newl, NULL);
+ if (!f) {
+ printf("triangle fan step of triangulator failed.\n");
+
+ /* NULL-terminat */
+ if (newfaces) newfaces[nf_i] = NULL;
+ return;
+ }
+
+ if (newfaces) newfaces[nf_i++] = f;
+
+ BMO_elem_flag_enable(bm, newl->e, newedge_oflag);
+ BMO_elem_flag_enable(bm, f, newface_oflag);
+ l_iter = nextloop;
+ }
+ }
+
+ /* NULL-terminat */
+ 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_face_legal_splits(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 (*projverts)[3];
+ float (*edgeverts)[3];
+ float fac1 = 1.0000001f, fac2 = 0.9f; //9999f; //0.999f;
+ int i, j, a = 0, clen;
+
+ BLI_array_fixedstack_declare(projverts, BM_NGON_STACK_SIZE, f->len, "projvertsb");
+ BLI_array_fixedstack_declare(edgeverts, BM_NGON_STACK_SIZE * 2, len * 2, "edgevertsb");
+
+ i = 0;
+ l = BM_iter_new(&iter, bm, BM_LOOPS_OF_FACE, f);
+ for ( ; l; l = BM_iter_step(&iter)) {
+ BM_elem_index_set(l, i); /* set_loop */
+ copy_v3_v3(projverts[i], l->v->co);
+ i++;
+ }
+
+ for (i = 0; i < len; i++) {
+ copy_v3_v3(v1, loops[i][0]->v->co);
+ copy_v3_v3(v2, loops[i][1]->v->co);
+
+ shrink_edgef(v1, v2, fac2);
+
+ copy_v3_v3(edgeverts[a], v1);
+ a++;
+ copy_v3_v3(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);
+
+ for (i = 0, l = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l = l->next) {
+ 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;
+
+ //copy_v3_v3(l->v->co, p1);
+ }
+
+ 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++) {
+ copy_v3_v3(v2, edgeverts[i * 2]);
+ copy_v3_v3(v3, edgeverts[i * 2 + 1]);
+
+ mid_v3_v3v3(mid, v2, v3);
+
+ clen = 0;
+ for (j = 0; j < f->len; j++) {
+ p1 = projverts[j];
+ p2 = projverts[(j + 1) % f->len];
+
+ copy_v3_v3(v1, p1);
+ copy_v3_v3(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 test */
+ for (i = 0; i < f->len; i++) {
+ p1 = projverts[i];
+ p2 = projverts[(i + 1) % f->len];
+
+ copy_v3_v3(v1, p1);
+ copy_v3_v3(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];
+
+ copy_v3_v3(v1, p1);
+ copy_v3_v3(v2, p2);
+
+ shrink_edgef(v1, v2, fac1);
+
+ if (linecrossesf(v1, v2, p3, p4)) {
+ loops[i][0] = NULL;
+ }
+ }
+ }
+
+ BLI_array_fixedstack_free(projverts);
+ BLI_array_fixedstack_free(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..694d68549cd
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -0,0 +1,98 @@
+/*
+ * ***** 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): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_PRIVATE_H__
+#define __BMESH_PRIVATE_H__
+
+/** \file blender/bmesh/intern/bmesh_private.h
+ * \ingroup bmesh
+ *
+ * Private function prototypes for bmesh public API.
+ * This file is a grab-bag of functions from various
+ * parts of the bmesh internals.
+ */
+
+struct Link;
+struct BMLoop;
+
+/* returns positive nonzero on error */
+int bmesh_check_element(BMesh *bm, void *element, const char htype);
+
+#define BM_CHECK_ELEMENT(bm, el) \
+ if (bmesh_check_element(bm, el, ((BMHeader*)el)->htype)) { \
+ printf("check_element failure, with code %i on line %i in file\n" \
+ " \"%s\"\n\n", \
+ bmesh_check_element(bm, el, ((BMHeader*)el)->htype), \
+ __LINE__, __FILE__); \
+ }
+
+#define BM_EDGE_DISK_LINK_GET(e, v) ( \
+ ((v) == ((BMEdge*)(e))->v1) ? \
+ &((e)->v1_disk_link) : \
+ &((e)->v2_disk_link) \
+ )
+
+int bmesh_radial_length(struct BMLoop *l);
+int bmesh_disk_count(BMVert *v);
+
+/* 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);
+
+/* NOTE: ensure different parts of the API do not conflict
+ * on using these internal flags!*/
+#define _FLAG_JF 1 /* join faces */
+#define _FLAG_MF 2 /* make face */
+
+#define BM_ELEM_API_FLAG_ENABLE(element, f) ((element)->oflags[0].pflag |= (f))
+#define BM_ELEM_API_FLAG_DISABLE(element, f) ((element)->oflags[0].pflag &= ~(f))
+#define BM_ELEM_API_FLAG_TEST(element, f) ((element)->oflags[0].pflag & (f))
+
+/* Polygon Utilities ? FIXME... where do these each go? */
+/* newedgeflag sets a flag layer flag, obviously not the header flag. */
+void BM_face_triangulate(BMesh *bm, BMFace *f, float (*projectverts)[3],
+ const short newedge_oflag, const short newface_oflag, BMFace **newfaces);
+void bmesh_update_face_normal(struct BMesh *bm, struct BMFace *f, float no[3],
+ float (*projectverts)[3]);
+void bmesh_update_face_normal_vertex_cos(struct BMesh *bm, struct BMFace *f, float no[3],
+ float (*projectverts)[3], float (*vertexCos)[3]);
+
+void compute_poly_plane(float (*verts)[3], int nverts);
+void poly_rotate_plane(const float normal[3], float (*verts)[3], const int nverts);
+void bmesh_flip_normal(struct BMesh *bm, struct BMFace *f);
+
+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 /* __BMESH_PRIVATE_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
new file mode 100644
index 00000000000..089bc79e25d
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -0,0 +1,658 @@
+/*
+ * ***** 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): Joseph Eagar, Geoffrey Bantle, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_queries.c
+ * \ingroup bmesh
+ *
+ * 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.
+ */
+
+#include "BLI_math.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#define BM_OVERLAP (1 << 13)
+
+/*
+ * BMESH COUNT ELEMENT
+ *
+ * Return the amount of element of
+ * type 'type' in a given bmesh.
+ */
+
+int BM_mesh_elem_count(BMesh *bm, const char htype)
+{
+ if (htype == BM_VERT) return bm->totvert;
+ else if (htype == BM_EDGE) return bm->totedge;
+ else if (htype == 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_face_other_loop(BMEdge *e, BMFace *f, BMVert *v)
+{
+ BMLoop *l_iter;
+ BMLoop *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+
+ do {
+ if (l_iter->e == e) {
+ break;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ return l_iter->v == v ? l_iter->prev : l_iter->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)
+{
+ BMLoop *l_iter, *l_first;
+
+#ifdef USE_BMESH_HOLES
+ BMLoopList *lst;
+ for (lst = f->loops.first; lst; lst = lst->next)
+#endif
+ {
+#ifdef USE_BMESH_HOLES
+ l_iter = l_first = lst->first;
+#else
+ l_iter = l_first = f->l_first;
+#endif
+ do {
+ if (l_iter->v == v) {
+ return TRUE;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ return FALSE;
+}
+
+/*
+ * 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)
+{
+ BMLoop *l_iter, *l_first;
+
+#ifdef USE_BMESH_HOLES
+ BMLoopList *lst;
+#endif
+
+ int i, count = 0;
+
+ for (i = 0; i < len; i++) BMO_elem_flag_enable(bm, varr[i], BM_OVERLAP);
+
+#ifdef USE_BMESH_HOLES
+ for (lst = f->loops.first; lst; lst = lst->next)
+#endif
+ {
+
+#ifdef USE_BMESH_HOLES
+ l_iter = l_first = lst->first;
+#else
+ l_iter = l_first = f->l_first;
+#endif
+
+ do {
+ if (BMO_elem_flag_test(bm, l_iter->v, BM_OVERLAP)) {
+ count++;
+ }
+
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ for (i = 0; i < len; i++) BMO_elem_flag_disable(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_iter;
+ BMLoop *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+
+ do {
+ if (l_iter->e == e) {
+ return TRUE;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ return FALSE;
+}
+
+/*
+ * 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_edge_other_vert(BMEdge *e, BMVert *v)
+{
+ return bmesh_edge_getothervert(e, v);
+}
+
+/*
+ * BMESH VERT EDGECOUNT
+ *
+ * Returns the number of edges around this vertex.
+ */
+
+int BM_vert_edge_count(BMVert *v)
+{
+ return bmesh_disk_count(v);
+}
+
+/*
+ * BMESH EDGE FACECOUNT
+ *
+ * Returns the number of faces around this edge
+ */
+
+int BM_edge_face_count(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_face_count(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_face_count(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_vert_is_wire(BMesh *UNUSED(bm), BMVert *v)
+{
+ BMEdge *curedge;
+
+ if (v->e == NULL) {
+ return FALSE;
+ }
+
+ curedge = v->e;
+ do {
+ if (curedge->l) {
+ return FALSE;
+ }
+
+ curedge = bmesh_disk_nextedge(curedge, v);
+ } while (curedge != v->e);
+
+ return TRUE;
+}
+
+/*
+ * 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_edge_is_wire(BMesh *UNUSED(bm), BMEdge *e)
+{
+ return (e->l) ? FALSE : TRUE;
+}
+
+/*
+ * 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_vert_is_manifold(BMesh *UNUSED(bm), BMVert *v)
+{
+ BMEdge *e, *oe;
+ BMLoop *l;
+ int len, count, flag;
+
+ if (v->e == NULL) {
+ /* loose vert */
+ return FALSE;
+ }
+
+ /* 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 FALSE;
+ }
+
+ if (bmesh_radial_length(e->l) > 2) {
+ /* edge shared by more than two faces */
+ return FALSE;
+ }
+ }
+
+ count = 1;
+ flag = 1;
+ e = NULL;
+ oe = v->e;
+ l = oe->l;
+ while (e != oe) {
+ l = (l->v == v) ? l->prev : 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 FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * 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_edge_is_manifold(BMesh *UNUSED(bm), BMEdge *e)
+{
+ int count = BM_edge_face_count(e);
+ if (count != 2 && count != 1) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * 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_edge_is_boundry(BMEdge *e)
+{
+ int count = BM_edge_face_count(e);
+ if (count == 1) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * BMESH FACE SHAREDEDGES
+ *
+ * Counts the number of edges two faces share (if any)
+ *
+ * BMESH_TODO:
+ * Move this to structure, and wrap.
+ *
+ * Returns -
+ * Integer
+ */
+
+int BM_face_share_edges(BMFace *f1, BMFace *f2)
+{
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ int count = 0;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f1);
+ do {
+ if (bmesh_radial_find_face(l_iter->e, f2)) {
+ count++;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ 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 TRUE;
+ }
+ l = l->radial_next;
+ } while (l != e1->l);
+ }
+ return FALSE;
+}
+
+/**
+ *
+ * BMESH EDGE SHARE A VERTEX
+ *
+ * Tests to see if e1 shares a vertex with e2
+ *
+ */
+
+int BM_edge_share_vert(struct BMEdge *e1, struct BMEdge *e2)
+{
+ return (e1->v1 == e2->v1 ||
+ e1->v1 == e2->v2 ||
+ e1->v2 == e2->v1 ||
+ e1->v2 == e2->v2);
+}
+
+/**
+ *
+ * BMESH EDGE ORDERED VERTS
+ *
+ * Returns the verts of an edge as used in a face
+ * if used in a face at all, otherwise just assign as used in the edge.
+ *
+ * Useful to get a determanistic winding order when calling
+ * BM_face_create_ngon() on an arbitrary array of verts,
+ * though be sure to pick an edge which has a face.
+ *
+ */
+
+void BM_edge_ordered_verts(BMEdge *edge, BMVert **r_v1, BMVert **r_v2)
+{
+ if ( (edge->l == NULL) ||
+ ( ((edge->l->prev->v == edge->v1) && (edge->l->v == edge->v2)) ||
+ ((edge->l->v == edge->v1) && (edge->l->next->v == edge->v2)) )
+ )
+ {
+ *r_v1 = edge->v1;
+ *r_v2 = edge->v2;
+ }
+ else {
+ *r_v1 = edge->v2;
+ *r_v2 = edge->v1;
+ }
+}
+
+/*
+ * BMESH FACE ANGLE
+ *
+ * Calculates the angle between two faces.
+ * Assumes the face normals are correct.
+ *
+ * Returns -
+ * Float.
+ */
+
+float BM_edge_face_angle(BMesh *UNUSED(bm), BMEdge *e)
+{
+ if (BM_edge_face_count(e) == 2) {
+ BMLoop *l1 = e->l;
+ BMLoop *l2 = e->l->radial_next;
+ return angle_normalized_v3v3(l1->f->no, l2->f->no);
+ }
+ else {
+ return (float)M_PI / 2.0f; /* acos(0.0) */
+ }
+}
+
+/*
+ * BMESH FACE ANGLE
+ *
+ * Calculates the angle a verts 2 edges.
+ *
+ * Returns -
+ * Float.
+ */
+float BM_vert_edge_angle(BMesh *UNUSED(bm), BMVert *v)
+{
+ BMEdge *e1, *e2;
+
+ /* saves BM_vert_edge_count(v) and and edge iterator,
+ * get the edges and count them both at once */
+
+ if ((e1 = v->e) &&
+ (e2 = bmesh_disk_nextedge(e1, v)) &&
+ /* make sure we come full circle and only have 2 connected edges */
+ (e1 == bmesh_disk_nextedge(e2, v)))
+ {
+ BMVert *v1 = BM_edge_other_vert(e1, v);
+ BMVert *v2 = BM_edge_other_vert(e2, v);
+
+ return M_PI - angle_v3v3v3(v1->co, v->co, v2->co);
+ }
+ else {
+ return (float)M_PI / 2.0f; /* acos(0.0) */
+ }
+}
+
+/*
+ * 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_face_exists_overlap(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 = BM_iter_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 TRUE;
+ }
+ f = BM_iter_step(&vertfaces);
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * 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 = BM_iter_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 TRUE;
+ }
+ f = BM_iter_step(&vertfaces);
+ }
+ }
+ return FALSE;
+}
diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c
new file mode 100644
index 00000000000..268d8bfa346
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_structure.c
@@ -0,0 +1,1103 @@
+/*
+ * ***** 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): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_structure.c
+ * \ingroup bmesh
+ *
+ * Low level routines for manipulating the BM structure.
+ */
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+/**
+ * MISC utility functions.
+ *
+ */
+
+int bmesh_vert_in_edge(BMEdge *e, BMVert *v)
+{
+ if (e->v1 == v || e->v2 == v) return TRUE;
+ return FALSE;
+}
+int bmesh_verts_in_edge(BMVert *v1, BMVert *v2, BMEdge *e)
+{
+ if (e->v1 == v1 && e->v2 == v2) return TRUE;
+ else if (e->v1 == v2 && e->v2 == v1) return TRUE;
+ return FALSE;
+}
+
+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->v1_disk_link.next = e->v1_disk_link.prev = NULL;
+ return TRUE;
+ }
+ else if (e->v2 == orig) {
+ e->v2 = newv;
+ e->v2_disk_link.next = e->v2_disk_link.prev = NULL;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * 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) {
+ BMDiskLink *dl1 = BM_EDGE_DISK_LINK_GET(e, v);
+
+ v->e = e;
+ dl1->next = dl1->prev = e;
+ }
+ else {
+ BMDiskLink *dl1, *dl2, *dl3;
+
+ dl1 = BM_EDGE_DISK_LINK_GET(e, v);
+ dl2 = BM_EDGE_DISK_LINK_GET(v->e, v);
+ dl3 = dl2->prev ? BM_EDGE_DISK_LINK_GET(dl2->prev, v) : NULL;
+
+ dl1->next = v->e;
+ dl1->prev = dl2->prev;
+
+ dl2->prev = e;
+ if (dl3)
+ dl3->next = e;
+ }
+
+ return TRUE;
+}
+
+void bmesh_disk_remove_edge(struct BMEdge *e, struct BMVert *v)
+{
+ BMDiskLink *dl1, *dl2;
+
+ dl1 = BM_EDGE_DISK_LINK_GET(e, v);
+ if (dl1->prev) {
+ dl2 = BM_EDGE_DISK_LINK_GET(dl1->prev, v);
+ dl2->next = dl1->next;
+ }
+
+ if (dl1->next) {
+ dl2 = BM_EDGE_DISK_LINK_GET(dl1->next, v);
+ dl2->prev = dl1->prev;
+ }
+
+ if (v->e == e)
+ v->e = (e != (BMEdge *)dl1->next) ? (BMEdge *)dl1->next : NULL;
+
+ dl1->next = dl1->prev = NULL;
+}
+
+struct BMEdge *bmesh_disk_nextedge(struct BMEdge *e, struct BMVert *v)
+{
+ if (v == e->v1)
+ return e->v1_disk_link.next;
+ if (v == e->v2)
+ return e->v2_disk_link.next;
+ return NULL;
+}
+
+static BMEdge *bmesh_disk_prevedge(BMEdge *e, BMVert *v)
+{
+ if (v == e->v1)
+ return e->v1_disk_link.prev;
+ if (v == e->v2)
+ return e->v2_disk_link.prev;
+ return NULL;
+}
+
+BMEdge *bmesh_disk_existedge(BMVert *v1, BMVert *v2)
+{
+ BMEdge *curedge, *startedge;
+
+ if (v1->e) {
+ startedge = v1->e;
+ curedge = startedge;
+ do {
+ if (bmesh_verts_in_edge(v1, v2, curedge)) {
+ return curedge;
+ }
+
+ curedge = bmesh_disk_nextedge(curedge, v1);
+ } while (curedge != startedge);
+ }
+
+ 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++;
+ } 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 FALSE;
+ if (bmesh_disk_count(v) != len || len == 0)
+ return FALSE;
+
+ e2 = e;
+ do {
+ if (len != 1 && bmesh_disk_prevedge(e2, v) == e2) {
+ return FALSE;
+ }
+
+ e2 = bmesh_disk_nextedge(e2, v);
+ } while (e2 != e);
+
+ return TRUE;
+}
+
+/*
+ * 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 edge */
+ 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;
+ int i = 0;
+
+ if (bmesh_radial_length(l) != radlen)
+ return FALSE;
+
+ do {
+ if (!l2) {
+ bmesh_error();
+ return FALSE;
+ }
+
+ if (l2->e != l->e)
+ return FALSE;
+ if (l2->v != l->e->v1 && l2->v != l->e->v2)
+ return FALSE;
+
+ if (i > BM_LOOP_RADIAL_MAX) {
+ bmesh_error();
+ return FALSE;
+ }
+
+ i++;
+ l2 = l2->radial_next;
+ } while (l2 != l);
+
+ return TRUE;
+}
+
+/*
+ * BMESH RADIAL REMOVE LOOP
+ *
+ * Removes a loop from an radial cycle. If edge e is non-NULL
+ * it should contain the radial cycle, and it will also get
+ * updated (in the case that the edge's link into the radial
+ * cycle was the loop which is being removed from the cycle).
+ */
+void bmesh_radial_remove_loop(BMLoop *l, BMEdge *e)
+{
+ /* if e is non-NULL, l must be in the radial cycle of e */
+ if (e && e != l->e) {
+ bmesh_error();
+ }
+
+ 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 {
+ if (e) {
+ if (l == e->l) {
+ e->l = NULL;
+ }
+ else {
+ bmesh_error();
+ }
+ }
+ }
+
+ /* l is no longer in a radial cycle; empty the links
+ * to the cycle and the link back to an edge */
+ l->radial_next = l->radial_prev = NULL;
+ l->e = NULL;
+}
+
+
+/*
+ * 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 {
+ if (!l2) {
+ /* radial cycle is broken (not a circulat loop) */
+ bmesh_error();
+ return 0;
+ }
+
+ i++;
+ l2 = l2->radial_next;
+ if (i >= BM_LOOP_RADIAL_MAX) {
+ bmesh_error();
+ 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;
+ }
+
+ if (l->e && l->e != e) {
+ /* l is already in a radial cycle for a different edge */
+ bmesh_error();
+ }
+
+ l->e = e;
+}
+
+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 TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * 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;
+}
+
+/*****loop cycle functions, e.g. loops surrounding a face**** */
+int bmesh_loop_validate(BMFace *f)
+{
+ int i;
+ int len = f->len;
+ BMLoop *l_iter, *l_first;
+
+ l_first = BM_FACE_FIRST_LOOP(f);
+
+ if (l_first == NULL) {
+ return FALSE;
+ }
+
+ /* Validate that the face loop cycle is the length specified by f->len */
+ for (i = 1, l_iter = l_first->next; i < len; i++, l_iter = l_iter->next) {
+ if ( (l_iter->f != f) ||
+ (l_iter == l_first))
+ {
+ return FALSE;
+ }
+ }
+ if (l_iter != l_first) {
+ return FALSE;
+ }
+
+ /* Validate the loop->prev links also form a cycle of length f->len */
+ for (i = 1, l_iter = l_first->prev; i < len; i++, l_iter = l_iter->prev) {
+ if (l_iter == l_first) {
+ return FALSE;
+ }
+ }
+ if (l_iter != l_first) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+#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 TRUE;
+ }
+ 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 TRUE;
+
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * 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 validatio */
+ for (i = 0, curnode = head; i < len; i++, curnode = curnode->next);
+ if (curnode != head) {
+ return FALSE;
+ }
+
+ /* reverse validatio */
+ for (i = 0, curnode = head; i < len; i++, curnode = curnode->prev);
+ if (curnode != head) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Begin Disk Cycle routine */
+
+/**
+ * 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 dis */
+ 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;
+
+ /* check to make sure v is in */
+ if (bmesh_vert_in_edge(e, v) == 0) {
+ return FALSE;
+ }
+
+ /* check for loose vert firs */
+ if (v->e == NULL) {
+ v->e = e;
+ base = tail = bmesh_disk_getpointer(e, v);
+ bmesh_cycle_append(base, tail); /* circular reference is ok */
+ return TRUE;
+ }
+
+ /* insert e at the end of disk cycle and make it the new v-> */
+ base = bmesh_disk_getpointer(v->e, v);
+ tail = bmesh_disk_getpointer(e, v);
+ bmesh_cycle_append(base, tail);
+ return TRUE;
+}
+
+/**
+ * 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 rebas */
+ 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) {
+
+ /* tflag and eflag are reserved for different functions */
+ if (eflag && tflag) {
+ return 0;
+ }
+
+ 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 TRUE;
+ }
+ else curedge = bmesh_disk_nextedge(curedge, v);
+ }
+ }
+ return FALSE;
+}
+
+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 routine */
+BMLoop *bmesh_radial_nextloop(BMLoop *l)
+{
+ return 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 pointe */
+ 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 rebas */
+ 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 TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+ * 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 edge */
+ 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 = 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..aff90dcced7
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_structure.h
@@ -0,0 +1,106 @@
+/*
+ * ***** 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): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_STRUCTURE_H__
+#define __BMESH_STRUCTURE_H__
+
+/** \file blender/bmesh/intern/bmesh_structure.h
+ * \ingroup bmesh
+ *
+ * The lowest level of functionality for manipulating bmesh structures.
+ * None of these functions should ever be exported to the rest of Blender.
+ *
+ * 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);
+
+/* LOOP CYCLE MANAGEMENT */
+int bmesh_loop_validate(BMFace *f);
+
+/*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
+#ifdef USE_BMESH_HOLES
+ , ListBase *holes
+#endif
+ );
+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 /* __BMESH_STRUCTURE_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_walkers.c b/source/blender/bmesh/intern/bmesh_walkers.c
new file mode 100644
index 00000000000..9cba90c1bf5
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_walkers.c
@@ -0,0 +1,266 @@
+/*
+ * ***** 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): Joseph Eagar, Geoffrey Bantle, Levi Schooley.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_walkers.c
+ * \ingroup bmesh
+ *
+ * BMesh Walker API.
+ */
+
+#include <stdlib.h>
+
+
+
+#include "BLI_listbase.h"
+
+#include "bmesh.h"
+
+#include "bmesh_walkers_private.h"
+
+/* - joeedh -
+ * design notes:
+ *
+ * original desing: walkers directly emulation recursive functions.
+ * functions save their state onto a worklist, and also add 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 worklist 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.
+ */
+
+void *BMW_begin(BMWalker *walker, void *start)
+{
+ walker->begin(walker, start);
+
+ return BMW_current_state(walker) ? 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,
+ short mask_vert, short mask_edge, short mask_loop, short mask_face,
+ int layer)
+{
+ memset(walker, 0, sizeof(BMWalker));
+
+ walker->layer = layer;
+ walker->bm = bm;
+
+ walker->mask_vert = mask_vert;
+ walker->mask_edge = mask_edge;
+ walker->mask_loop = mask_loop;
+ walker->mask_face = mask_face;
+
+ walker->visithash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh walkers 1");
+
+ if (type >= BMW_MAXWALKERS || type < 0) {
+ bmesh_error();
+ fprintf(stderr,
+ "Invalid walker type in BMW_init; type: %d, "
+ "searchmask: (v:%d, e:%d, l:%d, f:%d), flag: %d\n",
+ type, mask_vert, mask_edge, mask_loop, mask_face, layer);
+ }
+
+ if (type != BMW_CUSTOM) {
+ walker->begin = bm_walker_types[type]->begin;
+ walker->yield = bm_walker_types[type]->yield;
+ walker->step = bm_walker_types[type]->step;
+ walker->structsize = bm_walker_types[type]->structsize;
+ walker->order = bm_walker_types[type]->order;
+ walker->valid_mask = bm_walker_types[type]->valid_mask;
+
+ /* safety checks */
+ /* if this raises an error either the caller is wrong or
+ * 'bm_walker_types' needs updating */
+ BLI_assert(mask_vert == 0 || (walker->valid_mask & BM_VERT));
+ BLI_assert(mask_edge == 0 || (walker->valid_mask & BM_EDGE));
+ BLI_assert(mask_loop == 0 || (walker->valid_mask & BM_LOOP));
+ BLI_assert(mask_face == 0 || (walker->valid_mask & BM_FACE));
+ }
+
+ walker->worklist = BLI_mempool_create(walker->structsize, 100, 100, TRUE, FALSE);
+ walker->states.first = walker->states.last = NULL;
+}
+
+/*
+ * BMW_end
+ *
+ * Frees a walker's worklist.
+ */
+
+void BMW_end(BMWalker *walker)
+{
+ BLI_mempool_destroy(walker->worklist);
+ BLI_ghash_free(walker->visithash, NULL, NULL);
+}
+
+
+/*
+ * BMW_step
+ */
+
+void *BMW_step(BMWalker *walker)
+{
+ BMHeader *head;
+
+ head = BMW_walk(walker);
+
+ return head;
+}
+
+/*
+ * BMW_current_depth
+ *
+ * Returns the current depth of the walker.
+ */
+
+int BMW_current_depth(BMWalker *walker)
+{
+ return walker->depth;
+}
+
+/*
+ * BMW_WALK
+ *
+ * Steps a mesh walker forward by one element
+ *
+ * BMESH_TODO:
+ * -add searchmask filtering
+ */
+
+void *BMW_walk(BMWalker *walker)
+{
+ void *current = NULL;
+
+ while (BMW_current_state(walker)) {
+ current = walker->step(walker);
+ if (current) {
+ return current;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * BMW_current_state
+ *
+ * Returns the first state from the walker state
+ * worklist. This state is the the next in the
+ * worklist for processing.
+ */
+
+void *BMW_current_state(BMWalker *walker)
+{
+ bmesh_walkerGeneric *currentstate = walker->states.first;
+ if (currentstate) {
+ /* Automatic update of depth. For most walkers that
+ * follow the standard "Step" pattern of:
+ * - read current state
+ * - remove current state
+ * - push new states
+ * - return walk result from just-removed current state
+ * this simple automatic update should keep track of depth
+ * just fine. Walkers that deviate from that pattern may
+ * need to manually update the depth if they care about
+ * keeping it correct. */
+ walker->depth = currentstate->depth + 1;
+ }
+ return currentstate;
+}
+
+/*
+ * BMW_state_remove
+ *
+ * Remove and free an item from the end of the walker state
+ * worklist.
+ */
+
+void BMW_state_remove(BMWalker *walker)
+{
+ void *oldstate;
+ oldstate = BMW_current_state(walker);
+ BLI_remlink(&walker->states, oldstate);
+ BLI_mempool_free(walker->worklist, oldstate);
+}
+
+/*
+ * BMW_newstate
+ *
+ * Allocate a new empty state and put it on the worklist.
+ * A pointer to the new state is returned so that the caller
+ * can fill in the state data. The new state will be inserted
+ * at the front for depth-first walks, and at the end for
+ * breadth-first walks.
+ */
+
+void *BMW_state_add(BMWalker *walker)
+{
+ bmesh_walkerGeneric *newstate;
+ newstate = BLI_mempool_alloc(walker->worklist);
+ newstate->depth = walker->depth;
+ switch (walker->order)
+ {
+ case BMW_DEPTH_FIRST:
+ BLI_addhead(&walker->states, newstate);
+ break;
+ case BMW_BREADTH_FIRST:
+ BLI_addtail(&walker->states, newstate);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ return newstate;
+}
+
+/*
+ * BMW_reset
+ *
+ * Frees all states from the worklist, resetting the walker
+ * for reuse in a new walk.
+ */
+
+void BMW_reset(BMWalker *walker)
+{
+ while (BMW_current_state(walker)) {
+ BMW_state_remove(walker);
+ }
+ walker->depth = 0;
+ BLI_ghash_free(walker->visithash, NULL, NULL);
+ walker->visithash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh walkers 1");
+}
diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c
new file mode 100644
index 00000000000..e6bcbf405fe
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c
@@ -0,0 +1,911 @@
+/*
+ * ***** 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): Joseph Eagar, Geoffrey Bantle, Levi Schooley.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_walkers_impl.c
+ * \ingroup bmesh
+ *
+ * BMesh Walker Code.
+ */
+
+#include "BKE_customdata.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+#include "bmesh_walkers_private.h"
+
+/* 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_visitEdge(BMWalker *walker, BMEdge *e)
+{
+ shellWalker *shellWalk = NULL;
+
+ if (BLI_ghash_haskey(walker->visithash, e)) {
+ return;
+ }
+
+ if (walker->mask_edge && !BMO_elem_flag_test(walker->bm, e, walker->mask_edge)) {
+ return;
+ }
+
+ shellWalk = BMW_state_add(walker);
+ shellWalk->curedge = e;
+ BLI_ghash_insert(walker->visithash, e, NULL);
+}
+
+static void shellWalker_begin(BMWalker *walker, void *data)
+{
+ BMIter eiter;
+ BMHeader *h = data;
+ BMEdge *e;
+ BMVert *v;
+
+ if (h == NULL)
+ {
+ return;
+ }
+
+ switch (h->htype) {
+ case BM_VERT:
+ {
+ /* starting the walk at a vert, add all the edges
+ * to the worklist */
+ v = (BMVert *)h;
+ BM_ITER(e, &eiter, walker->bm, BM_EDGES_OF_VERT, v) {
+ shellWalker_visitEdge(walker, e);
+ }
+ break;
+ }
+
+ case BM_EDGE:
+ {
+ /* starting the walk at an edge, add the single edge
+ * to the worklist */
+ e = (BMEdge *)h;
+ shellWalker_visitEdge(walker, e);
+ break;
+ }
+ }
+}
+
+static void *shellWalker_yield(BMWalker *walker)
+{
+ shellWalker *shellWalk = BMW_current_state(walker);
+ return shellWalk->curedge;
+}
+
+static void *shellWalker_step(BMWalker *walker)
+{
+ shellWalker *swalk = BMW_current_state(walker);
+ BMEdge *e, *e2;
+ BMVert *v;
+ BMIter iter;
+ int i;
+
+ e = swalk->curedge;
+ BMW_state_remove(walker);
+
+ for (i = 0; i < 2; i++) {
+ v = i ? e->v2 : e->v1;
+ BM_ITER(e2, &iter, walker->bm, BM_EDGES_OF_VERT, v) {
+ shellWalker_visitEdge(walker, e2);
+ }
+ }
+
+ return e;
+}
+
+#if 0
+static void *shellWalker_step(BMWalker *walker)
+{
+ BMEdge *curedge, *next = NULL;
+ BMVert *ov = NULL;
+ int restrictpass = 1;
+ shellWalker shellWalk = *((shellWalker *)BMW_current_state(walker));
+
+ if (!BLI_ghash_haskey(walker->visithash, shellWalk.base)) {
+ BLI_ghash_insert(walker->visithash, shellWalk.base, NULL);
+ }
+
+ BMW_state_remove(walker);
+
+
+ /* find the next edge whose other vertex has not been visite */
+ curedge = shellWalk.curedge;
+ do {
+ if (!BLI_ghash_haskey(walker->visithash, curedge)) {
+ if (!walker->restrictflag ||
+ (walker->restrictflag && BMO_elem_flag_test(walker->bm, curedge, walker->restrictflag)))
+ {
+ shellWalker *newstate;
+
+ ov = BM_edge_other_vert(curedge, shellWalk.base);
+
+ /* push a new state onto the stac */
+ newState = BMW_state_add(walker);
+ BLI_ghash_insert(walker->visithash, curedge, NULL);
+
+ /* populate the new stat */
+
+ newState->base = ov;
+ newState->curedge = curedge;
+ }
+ }
+ curedge = bmesh_disk_nextedge(curedge, shellWalk.base);
+ } while (curedge != shellWalk.curedge);
+
+ return shellWalk.curedge;
+}
+#endif
+
+/* Connected Vertex Walker:
+ *
+ * Similar to shell walker, but visits vertices instead of edges.
+ *
+ */
+
+static void connectedVertexWalker_visitVertex(BMWalker *walker, BMVert *v)
+{
+ connectedVertexWalker *vwalk;
+
+ if (BLI_ghash_haskey(walker->visithash, v)) {
+ /* already visited */
+ return;
+ }
+ if (walker->mask_vert && !BMO_elem_flag_test(walker->bm, v, walker->mask_vert)) {
+ /* not flagged for walk */
+ return;
+ }
+
+ vwalk = BMW_state_add(walker);
+ vwalk->curvert = v;
+ BLI_ghash_insert(walker->visithash, v, NULL);
+}
+
+static void connectedVertexWalker_begin(BMWalker *walker, void *data)
+{
+ BMVert *v = data;
+ connectedVertexWalker_visitVertex(walker, v);
+}
+
+static void *connectedVertexWalker_yield(BMWalker *walker)
+{
+ connectedVertexWalker *vwalk = BMW_current_state(walker);
+ return vwalk->curvert;
+}
+
+static void *connectedVertexWalker_step(BMWalker *walker)
+{
+ connectedVertexWalker *vwalk = BMW_current_state(walker);
+ BMVert *v, *v2;
+ BMEdge *e;
+ BMIter iter;
+
+ v = vwalk->curvert;
+
+ BMW_state_remove(walker);
+
+ BM_ITER(e, &iter, walker->bm, BM_EDGES_OF_VERT, v) {
+ v2 = BM_edge_other_vert(e, v);
+ if (!BLI_ghash_haskey(walker->visithash, v2)) {
+ connectedVertexWalker_visitVertex(walker, v2);
+ }
+ }
+
+ return v;
+}
+
+/* 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;
+
+ iwalk = BMW_state_add(walker);
+
+ iwalk->base = iwalk->curloop = l;
+ iwalk->lastv = l->v;
+
+ BLI_ghash_insert(walker->visithash, data, NULL);
+
+}
+
+static void *islandboundWalker_yield(BMWalker *walker)
+{
+ islandboundWalker *iwalk = BMW_current_state(walker);
+
+ return iwalk->curloop;
+}
+
+static void *islandboundWalker_step(BMWalker *walker)
+{
+ islandboundWalker *iwalk = BMW_current_state(walker), 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_vert_is_manifold(walker->bm, v)) {
+ BMW_reset(walker);
+ BMO_error_raise(walker->bm, NULL, BMERR_WALKER_FAILED,
+ "Non-manifold vert "
+ "while searching region boundary");
+ return NULL;
+ }
+
+ /* pop off current stat */
+ BMW_state_remove(walker);
+
+ f = l->f;
+
+ while (1) {
+ l = BM_face_other_loop(e, f, v);
+ if (bmesh_radial_nextloop(l) != l) {
+ l = bmesh_radial_nextloop(l);
+ f = l->f;
+ e = l->e;
+ if (walker->mask_face && !BMO_elem_flag_test(walker->bm, f, walker->mask_face)) {
+ l = l->radial_next;
+ break;
+ }
+ }
+ else {
+ f = l->f;
+ e = l->e;
+ break;
+ }
+ }
+
+ if (l == owalk.curloop) {
+ return NULL;
+ }
+ else if (BLI_ghash_haskey(walker->visithash, l)) {
+ return owalk.curloop;
+ }
+
+ BLI_ghash_insert(walker->visithash, l, NULL);
+ iwalk = BMW_state_add(walker);
+ iwalk->base = owalk.base;
+
+ //if (!BMO_elem_flag_test(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;
+
+ if (walker->mask_face && !BMO_elem_flag_test(walker->bm, (BMElemF *)data, walker->mask_face)) {
+ return;
+ }
+
+ iwalk = BMW_state_add(walker);
+ BLI_ghash_insert(walker->visithash, data, NULL);
+
+ iwalk->cur = data;
+}
+
+static void *islandWalker_yield(BMWalker *walker)
+{
+ islandWalker *iwalk = BMW_current_state(walker);
+
+ return iwalk->cur;
+}
+
+static void *islandWalker_step(BMWalker *walker)
+{
+ islandWalker *iwalk = BMW_current_state(walker);
+ /* islandWalker *owalk = iwalk; */ /* UNUSED */
+ BMIter iter, liter;
+ BMFace *f, *curf = iwalk->cur;
+ BMLoop *l;
+
+ BMW_state_remove(walker);
+
+ l = BM_iter_new(&liter, walker->bm, BM_LOOPS_OF_FACE, iwalk->cur);
+ for ( ; l; l = BM_iter_step(&liter)) {
+ /* could skip loop here too, but dont add unless we need it */
+ if (walker->mask_edge && !BMO_elem_flag_test(walker->bm, l->e, walker->mask_edge)) {
+ continue;
+ }
+
+ f = BM_iter_new(&iter, walker->bm, BM_FACES_OF_EDGE, l->e);
+ for ( ; f; f = BM_iter_step(&iter)) {
+ if (walker->mask_face && !BMO_elem_flag_test(walker->bm, f, walker->mask_face)) {
+ continue;
+ }
+ if (BLI_ghash_haskey(walker->visithash, f)) continue;
+
+ iwalk = BMW_state_add(walker);
+ iwalk->cur = f;
+ BLI_ghash_insert(walker->visithash, f, NULL);
+ break;
+ }
+ }
+
+ return curf;
+}
+
+
+/* Edge Loop Walker:
+ *
+ * Starts at a tool-flagged edge and walks over the edge loop
+ *
+ */
+
+static void loopWalker_begin(BMWalker *walker, void *data)
+{
+ loopWalker *lwalk = NULL, owalk;
+ BMEdge *e = data;
+ BMVert *v;
+ /* int found = 1, val; */ /* UNUSED */
+
+ v = e->v1;
+
+ /* val = BM_vert_edge_count(v); */ /* UNUSED */
+
+ lwalk = BMW_state_add(walker);
+ BLI_ghash_insert(walker->visithash, e, NULL);
+
+ lwalk->cur = lwalk->start = e;
+ lwalk->lastv = lwalk->startv = v;
+ lwalk->stage2 = 0;
+ lwalk->startrad = BM_edge_face_count(e);
+
+ /* rewin */
+ while (BMW_current_state(walker)) {
+ owalk = *((loopWalker *)BMW_current_state(walker));
+ BMW_walk(walker);
+ }
+
+ lwalk = BMW_state_add(walker);
+ *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 = BMW_current_state(walker);
+
+ return lwalk->cur;
+}
+
+static void *loopWalker_step(BMWalker *walker)
+{
+ loopWalker *lwalk = BMW_current_state(walker), owalk;
+ BMIter eiter;
+ BMEdge *e = lwalk->cur, *nexte = NULL;
+ BMLoop *l, *l2;
+ BMVert *v;
+ int val, rlen /* , found = 0 */, i = 0, stopi;
+
+ owalk = *lwalk;
+ BMW_state_remove(walker);
+
+ l = e->l;
+
+ /* handle wire edge case */
+ if (!l) {
+
+ /* match trunk: mark all connected wire edges */
+ for (i = 0; i < 2; i++) {
+ v = i ? e->v2 : e->v1;
+
+ BM_ITER(nexte, &eiter, walker->bm, BM_EDGES_OF_VERT, v) {
+ if ((nexte->l == NULL) && !BLI_ghash_haskey(walker->visithash, nexte)) {
+ lwalk = BMW_state_add(walker);
+ lwalk->cur = nexte;
+ lwalk->lastv = v;
+ lwalk->startrad = owalk.startrad;
+
+ BLI_ghash_insert(walker->visithash, nexte, NULL);
+ }
+ }
+ }
+
+ return owalk.cur;
+ }
+
+ v = (e->v1 == lwalk->lastv) ? e->v2 : e->v1;
+
+ val = BM_vert_edge_count(v);
+
+ rlen = owalk.startrad;
+
+ if (val == 4 || val == 2 || rlen == 1) {
+ i = 0;
+ stopi = val / 2;
+ while (1) {
+ if (rlen != 1 && i == stopi) break;
+
+ l = BM_face_other_loop(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)) {
+ lwalk = BMW_state_add(walker);
+ lwalk->cur = l->e;
+ lwalk->lastv = v;
+ lwalk->startrad = owalk.startrad;
+ BLI_ghash_insert(walker->visithash, l->e, NULL);
+ }
+ }
+
+ return owalk.cur;
+}
+
+/* Face Loop Walker:
+ *
+ * Starts at a tool-flagged face and walks over the face loop
+ * Conditions for starting and stepping the face loop have been
+ * tuned in an attempt to match the face loops built by EditMesh
+ *
+ */
+
+/* Check whether the face loop should includes the face specified
+ * by the given BMLoop */
+static int faceloopWalker_include_face(BMWalker *walker, BMLoop *l)
+{
+ /* face must have degree 4 */
+ if (l->f->len != 4) {
+ return FALSE;
+ }
+
+ /* the face must not have been already visite */
+ if (BLI_ghash_haskey(walker->visithash, l->f)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Check whether the face loop can start from the given edge */
+static int faceloopWalker_edge_begins_loop(BMWalker *walker, BMEdge *e)
+{
+ BMesh *bm = walker->bm;
+
+ /* There is no face loop starting from a wire edge */
+ if (BM_edge_is_wire(bm, e)) {
+ return FALSE;
+ }
+
+ /* Don't start a loop from a boundary edge if it cannot
+ * be extended to cover any faces */
+ if (BM_edge_face_count(e) == 1) {
+ if (!faceloopWalker_include_face(walker, e->l)) {
+ return FALSE;
+ }
+ }
+
+ /* Don't start a face loop from non-manifold edges */
+ if (!BM_edge_is_manifold(bm, e)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void faceloopWalker_begin(BMWalker *walker, void *data)
+{
+ faceloopWalker *lwalk, owalk;
+ BMEdge *e = data;
+ /* BMesh *bm = walker->bm; */ /* UNUSED */
+ /* int fcount = BM_edge_face_count(e); */ /* UNUSED */
+
+ if (!faceloopWalker_edge_begins_loop(walker, e))
+ return;
+
+ lwalk = BMW_state_add(walker);
+ lwalk->l = e->l;
+ lwalk->nocalc = 0;
+ BLI_ghash_insert(walker->visithash, lwalk->l->f, NULL);
+
+ /* rewin */
+ while (BMW_current_state(walker)) {
+ owalk = *((faceloopWalker *)BMW_current_state(walker));
+ BMW_walk(walker);
+ }
+
+ lwalk = BMW_state_add(walker);
+ *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 = BMW_current_state(walker);
+
+ if (!lwalk) {
+ return NULL;
+ }
+
+ return lwalk->l->f;
+}
+
+static void *faceloopWalker_step(BMWalker *walker)
+{
+ faceloopWalker *lwalk = BMW_current_state(walker);
+ BMFace *f = lwalk->l->f;
+ BMLoop *l = lwalk->l, *origl = lwalk->l;
+
+ BMW_state_remove(walker);
+
+ l = l->radial_next;
+
+ if (lwalk->nocalc)
+ return f;
+
+ if (!faceloopWalker_include_face(walker, l)) {
+ l = lwalk->l;
+ l = l->next->next;
+ if (BM_edge_face_count(l->e) != 2) {
+ l = l->prev->prev;
+ }
+ l = l->radial_next;
+ }
+
+ if (faceloopWalker_include_face(walker, l)) {
+ lwalk = BMW_state_add(walker);
+ 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;
+}
+
+/* Edge Ring Walker:
+ *
+ * Starts at a tool-flagged edge and walks over the edge ring
+ * Conditions for starting and stepping the edge ring have been
+ * tuned in an attempt to match the edge rings built by EditMesh
+ *
+ */
+
+static void edgeringWalker_begin(BMWalker *walker, void *data)
+{
+ edgeringWalker *lwalk, owalk;
+ BMEdge *e = data;
+
+ lwalk = BMW_state_add(walker);
+ lwalk->l = e->l;
+
+ if (!lwalk->l) {
+ lwalk->wireedge = e;
+ return;
+ }
+ else {
+ lwalk->wireedge = NULL;
+ }
+
+ BLI_ghash_insert(walker->visithash, lwalk->l->e, NULL);
+
+ /* rewin */
+ while (BMW_current_state(walker)) {
+ owalk = *((edgeringWalker *)BMW_current_state(walker));
+ BMW_walk(walker);
+ }
+
+ lwalk = BMW_state_add(walker);
+ *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 = BMW_current_state(walker);
+
+ if (!lwalk) {
+ return NULL;
+ }
+
+ if (lwalk->l)
+ return lwalk->l->e;
+ else
+ return lwalk->wireedge;
+}
+
+static void *edgeringWalker_step(BMWalker *walker)
+{
+ edgeringWalker *lwalk = BMW_current_state(walker);
+ BMEdge *e;
+ BMLoop *l = lwalk->l /* , *origl = lwalk->l */;
+ BMesh *bm = walker->bm;
+
+ BMW_state_remove(walker);
+
+ if (!l)
+ return lwalk->wireedge;
+
+ e = l->e;
+ if (!BM_edge_is_manifold(bm, e)) {
+ /* walker won't traverse to a non-manifold edge, but may
+ * be started on one, and should not traverse *away* from
+ * a non-manfold edge (non-manifold edges are never in an
+ * edge ring with manifold edges */
+ return e;
+ }
+
+ l = l->radial_next;
+ l = l->next->next;
+
+ if ((l->f->len != 4) || !BM_edge_is_manifold(bm, l->e)) {
+ l = lwalk->l->next->next;
+ }
+
+ /* only walk to manifold edge */
+ if ((l->f->len == 4) && BM_edge_is_manifold(bm, l->e) &&
+ !BLI_ghash_haskey(walker->visithash, l->e)) {
+ lwalk = BMW_state_add(walker);
+ lwalk->l = l;
+ lwalk->wireedge = NULL;
+
+ 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;
+
+ lwalk = BMW_state_add(walker);
+ lwalk->l = l;
+ BLI_ghash_insert(walker->visithash, l, NULL);
+}
+
+static void *uvedgeWalker_yield(BMWalker *walker)
+{
+ uvedgeWalker *lwalk = BMW_current_state(walker);
+
+ if (!lwalk) {
+ return NULL;
+ }
+
+ return lwalk->l;
+}
+
+static void *uvedgeWalker_step(BMWalker *walker)
+{
+ uvedgeWalker *lwalk = BMW_current_state(walker);
+ 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->layer].type;
+
+ BMW_state_remove(walker);
+
+ if (walker->mask_edge && !BMO_elem_flag_test(walker->bm, l->e, walker->mask_edge))
+ 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->layer);
+
+ rlen = BM_edge_face_count(l2->e);
+ for (j = 0; j < rlen; j++) {
+ if (BLI_ghash_haskey(walker->visithash, l2))
+ continue;
+ if (walker->mask_edge && !(BMO_elem_flag_test(walker->bm, l2->e, walker->mask_edge))) {
+ if (l2->v != cl->v)
+ continue;
+ }
+
+ l3 = l2->v != cl->v ? l2->next : l2;
+ d2 = CustomData_bmesh_get_layer_n(&walker->bm->ldata,
+ l3->head.data, walker->layer);
+
+ if (!CustomData_data_equals(type, d1, d2))
+ continue;
+
+ lwalk = BMW_state_add(walker);
+ BLI_ghash_insert(walker->visithash, l2, NULL);
+
+ lwalk->l = l2;
+
+ l2 = l2->radial_next;
+ }
+ }
+ }
+
+ return l;
+}
+
+static BMWalker shell_walker_type = {
+ shellWalker_begin,
+ shellWalker_step,
+ shellWalker_yield,
+ sizeof(shellWalker),
+ BMW_BREADTH_FIRST,
+ BM_EDGE, /* valid restrict masks */
+};
+
+static BMWalker islandbound_walker_type = {
+ islandboundWalker_begin,
+ islandboundWalker_step,
+ islandboundWalker_yield,
+ sizeof(islandboundWalker),
+ BMW_DEPTH_FIRST,
+ BM_FACE, /* valid restrict masks */
+};
+
+static BMWalker island_walker_type = {
+ islandWalker_begin,
+ islandWalker_step,
+ islandWalker_yield,
+ sizeof(islandWalker),
+ BMW_BREADTH_FIRST,
+ BM_EDGE | BM_FACE, /* valid restrict masks */
+};
+
+static BMWalker loop_walker_type = {
+ loopWalker_begin,
+ loopWalker_step,
+ loopWalker_yield,
+ sizeof(loopWalker),
+ BMW_DEPTH_FIRST,
+ 0, /* valid restrict masks */ /* could add flags here but so far none are used */
+};
+
+static BMWalker faceloop_walker_type = {
+ faceloopWalker_begin,
+ faceloopWalker_step,
+ faceloopWalker_yield,
+ sizeof(faceloopWalker),
+ BMW_DEPTH_FIRST,
+ 0, /* valid restrict masks */ /* could add flags here but so far none are used */
+};
+
+static BMWalker edgering_walker_type = {
+ edgeringWalker_begin,
+ edgeringWalker_step,
+ edgeringWalker_yield,
+ sizeof(edgeringWalker),
+ BMW_DEPTH_FIRST,
+ 0, /* valid restrict masks */ /* could add flags here but so far none are used */
+};
+
+static BMWalker loopdata_region_walker_type = {
+ uvedgeWalker_begin,
+ uvedgeWalker_step,
+ uvedgeWalker_yield,
+ sizeof(uvedgeWalker),
+ BMW_DEPTH_FIRST,
+ BM_EDGE, /* valid restrict masks */
+};
+
+static BMWalker connected_vertex_walker_type = {
+ connectedVertexWalker_begin,
+ connectedVertexWalker_step,
+ connectedVertexWalker_yield,
+ sizeof(connectedVertexWalker),
+ BMW_BREADTH_FIRST,
+ BM_VERT, /* valid restrict masks */
+};
+
+BMWalker *bm_walker_types[] = {
+ &shell_walker_type, /* BMW_SHELL */
+ &loop_walker_type, /* BMW_LOOP */
+ &faceloop_walker_type, /* BMW_FACELOOP */
+ &edgering_walker_type, /* BMW_EDGERING */
+ &loopdata_region_walker_type, /* BMW_LOOPDATA_ISLAND */
+ &islandbound_walker_type, /* BMW_ISLANDBOUND */
+ &island_walker_type, /* BMW_ISLAND */
+ &connected_vertex_walker_type, /* BMW_CONNECTED_VERTEX */
+};
+
+int bm_totwalkers = sizeof(bm_walker_types) / sizeof(*bm_walker_types);
diff --git a/source/blender/bmesh/intern/bmesh_walkers_private.h b/source/blender/bmesh/intern/bmesh_walkers_private.h
new file mode 100644
index 00000000000..2d59a940448
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_walkers_private.h
@@ -0,0 +1,89 @@
+/*
+ * ***** 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): Joseph Eagar, Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_WALKERS_PRIVATE_H__
+#define __BMESH_WALKERS_PRIVATE_H__
+
+/** \file blender/bmesh/intern/bmesh_walkers_private.h
+ * \ingroup bmesh
+ *
+ * BMesh walker API.
+ */
+
+extern BMWalker *bm_walker_types[];
+extern int bm_totwalkers;
+
+
+/* Pointer hiding*/
+typedef struct bmesh_walkerGeneric{
+ Link link;
+ int depth;
+} bmesh_walkerGeneric;
+
+
+typedef struct shellWalker{
+ bmesh_walkerGeneric header;
+ BMEdge *curedge;
+} shellWalker;
+
+typedef struct islandboundWalker {
+ bmesh_walkerGeneric header;
+ BMLoop *base;
+ BMVert *lastv;
+ BMLoop *curloop;
+} islandboundWalker;
+
+typedef struct islandWalker {
+ bmesh_walkerGeneric header;
+ BMFace *cur;
+} islandWalker;
+
+typedef struct loopWalker {
+ bmesh_walkerGeneric header;
+ BMEdge *cur, *start;
+ BMVert *lastv, *startv;
+ int startrad, stage2;
+} loopWalker;
+
+typedef struct faceloopWalker {
+ bmesh_walkerGeneric header;
+ BMLoop *l;
+ int nocalc;
+} faceloopWalker;
+
+typedef struct edgeringWalker {
+ bmesh_walkerGeneric header;
+ BMLoop *l;
+ BMEdge *wireedge;
+} edgeringWalker;
+
+typedef struct uvedgeWalker {
+ bmesh_walkerGeneric header;
+ BMLoop *l;
+} uvedgeWalker;
+
+typedef struct connectedVertexWalker {
+ bmesh_walkerGeneric header;
+ BMVert *curvert;
+} connectedVertexWalker;
+
+#endif /* __BMESH_WALKERS_PRIVATE_H__ */
diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c
new file mode 100644
index 00000000000..98e9a510126
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_bevel.c
@@ -0,0 +1,881 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_array.h"
+#include "BLI_math.h"
+#include "BLI_smallhash.h"
+
+#include "BKE_customdata.h"
+
+#include "bmesh.h"
+
+#define BEVEL_FLAG 1
+#define BEVEL_DEL 2
+#define FACE_NEW 4
+#define EDGE_OLD 8
+#define FACE_OLD 16
+#define VERT_OLD 32
+#define FACE_SPAN 64
+#define FACE_HOLE 128
+
+typedef struct LoopTag {
+ BMVert *newv;
+} LoopTag;
+
+typedef struct EdgeTag {
+ BMVert *newv1, *newv2;
+} EdgeTag;
+
+static void calc_corner_co(BMesh *bm, BMLoop *l, const float fac, float r_co[3],
+ const short do_dist, const short do_even)
+{
+ float no[3], l_vec_prev[3], l_vec_next[3], l_co_prev[3], l_co[3], l_co_next[3], co_ofs[3];
+ int is_concave;
+
+ /* first get the prev/next verts */
+ if (l->f->len > 2) {
+ copy_v3_v3(l_co_prev, l->prev->v->co);
+ copy_v3_v3(l_co, l->v->co);
+ copy_v3_v3(l_co_next, l->next->v->co);
+
+ /* calculate norma */
+ sub_v3_v3v3(l_vec_prev, l_co_prev, l_co);
+ sub_v3_v3v3(l_vec_next, l_co_next, l_co);
+
+ cross_v3_v3v3(no, l_vec_prev, l_vec_next);
+ is_concave = dot_v3v3(no, l->f->no) > 0.0f;
+ }
+ else {
+ BMIter iter;
+ BMLoop *l2;
+ float up[3] = {0.0f, 0.0f, 1.0f};
+
+ copy_v3_v3(l_co_prev, l->prev->v->co);
+ copy_v3_v3(l_co, l->v->co);
+
+ BM_ITER(l2, &iter, bm, BM_LOOPS_OF_VERT, l->v) {
+ if (l2->f != l->f) {
+ copy_v3_v3(l_co_next, BM_edge_other_vert(l2->e, l2->next->v)->co);
+ break;
+ }
+ }
+
+ sub_v3_v3v3(l_vec_prev, l_co_prev, l_co);
+ sub_v3_v3v3(l_vec_next, l_co_next, l_co);
+
+ cross_v3_v3v3(no, l_vec_prev, l_vec_next);
+ if (dot_v3v3(no, no) == 0.0f) {
+ no[0] = no[1] = 0.0f; no[2] = -1.0f;
+ }
+
+ is_concave = dot_v3v3(no, up) < 0.0f;
+ }
+
+
+ /* now calculate the new location */
+ if (do_dist) { /* treat 'fac' as distance */
+
+ normalize_v3(l_vec_prev);
+ normalize_v3(l_vec_next);
+
+ add_v3_v3v3(co_ofs, l_vec_prev, l_vec_next);
+ if (UNLIKELY(normalize_v3(co_ofs) == 0.0f)) { /* edges form a straignt line */
+ cross_v3_v3v3(co_ofs, l_vec_prev, l->f->no);
+ }
+
+ if (do_even) {
+ negate_v3(l_vec_next);
+ mul_v3_fl(co_ofs, fac * shell_angle_to_dist(0.5f * angle_normalized_v3v3(l_vec_prev, l_vec_next)));
+ /* negate_v3(l_vec_next); */ /* no need unless we use again */
+ }
+ else {
+ mul_v3_fl(co_ofs, fac);
+ }
+ }
+ else { /* treat as 'fac' as a factor (0 - 1) */
+
+ /* not strictly necessary, balance vectors
+ * so the longer edge doesn't skew the result,
+ * gives nicer, move even output.
+ *
+ * Use the minimum rather then the middle value so skinny faces don't flip along the short axis */
+ float min_fac = minf(normalize_v3(l_vec_prev), normalize_v3(l_vec_next));
+ float angle;
+
+ if (do_even) {
+ negate_v3(l_vec_next);
+ angle = angle_normalized_v3v3(l_vec_prev, l_vec_next);
+ negate_v3(l_vec_next); /* no need unless we use again */
+ }
+ else {
+ angle = 0.0f;
+ }
+
+ mul_v3_fl(l_vec_prev, min_fac);
+ mul_v3_fl(l_vec_next, min_fac);
+
+ add_v3_v3v3(co_ofs, l_vec_prev, l_vec_next);
+
+ if (UNLIKELY(is_zero_v3(co_ofs))) {
+ cross_v3_v3v3(co_ofs, l_vec_prev, l->f->no);
+ normalize_v3(co_ofs);
+ mul_v3_fl(co_ofs, min_fac);
+ }
+
+ /* done */
+ if (do_even) {
+ mul_v3_fl(co_ofs, (fac * 0.5) * shell_angle_to_dist(0.5f * angle));
+ }
+ else {
+ mul_v3_fl(co_ofs, fac * 0.5);
+ }
+ }
+
+ /* apply delta vec */
+ if (is_concave)
+ negate_v3(co_ofs);
+
+ add_v3_v3v3(r_co, co_ofs, l->v->co);
+}
+
+
+#define ETAG_SET(e, v, nv) ( \
+ (v) == (e)->v1 ? \
+ (etags[BM_elem_index_get((e))].newv1 = (nv)) : \
+ (etags[BM_elem_index_get((e))].newv2 = (nv)) \
+ )
+
+#define ETAG_GET(e, v) ( \
+ (v) == (e)->v1 ? \
+ (etags[BM_elem_index_get((e))].newv1) : \
+ (etags[BM_elem_index_get((e))].newv2) \
+ )
+
+void bmesh_bevel_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMIter iter;
+ BMEdge *e;
+ BMVert *v;
+ BMFace **faces = NULL, *f;
+ LoopTag *tags = NULL, *tag;
+ EdgeTag *etags = NULL;
+ BMVert **verts = NULL;
+ BMEdge **edges = NULL;
+ BLI_array_declare(faces);
+ BLI_array_declare(tags);
+ BLI_array_declare(etags);
+ BLI_array_declare(verts);
+ BLI_array_declare(edges);
+ SmallHash hash;
+ float fac = BMO_slot_float_get(op, "percent");
+ const short do_even = BMO_slot_int_get(op, "use_even");
+ const short do_dist = BMO_slot_int_get(op, "use_dist");
+ int i, li, has_elens, HasMDisps = CustomData_has_layer(&bm->ldata, CD_MDISPS);
+
+ has_elens = CustomData_has_layer(&bm->edata, CD_PROP_FLT) && BMO_slot_int_get(op, "use_lengths");
+ if (has_elens) {
+ li = BMO_slot_int_get(op, "lengthlayer");
+ }
+
+ BLI_smallhash_init(&hash);
+
+ BMO_ITER(e, &siter, bm, op, "geom", BM_EDGE) {
+ BMO_elem_flag_enable(bm, e, BEVEL_FLAG|BEVEL_DEL);
+ BMO_elem_flag_enable(bm, e->v1, BEVEL_FLAG|BEVEL_DEL);
+ BMO_elem_flag_enable(bm, e->v2, BEVEL_FLAG|BEVEL_DEL);
+
+ if (BM_edge_face_count(e) < 2) {
+ BMO_elem_flag_disable(bm, e, BEVEL_DEL);
+ BMO_elem_flag_disable(bm, e->v1, BEVEL_DEL);
+ BMO_elem_flag_disable(bm, e->v2, BEVEL_DEL);
+ }
+#if 0
+ if (BM_edge_face_count(e) == 0) {
+ BMVert *verts[2] = {e->v1, e->v2};
+ BMEdge *edges[2] = {e, BM_edge_create(bm, e->v1, e->v2, e, 0)};
+
+ BMO_elem_flag_enable(bm, edges[1], BEVEL_FLAG);
+ BM_face_create(bm, verts, edges, 2, FALSE);
+ }
+#endif
+ }
+
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BMO_elem_flag_enable(bm, v, VERT_OLD);
+ }
+
+#if 0
+ //a bit of cleaner code that, alas, doens't work.
+ /* build edge tag */
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (BMO_elem_flag_test(bm, e->v1, BEVEL_FLAG) || BMO_elem_flag_test(bm, e->v2, BEVEL_FLAG)) {
+ BMIter liter;
+ BMLoop *l;
+
+ if (!BMO_elem_flag_test(bm, e, EDGE_OLD)) {
+ BM_elem_index_set(e, BLI_array_count(etags)); /* set_dirty! */
+ BLI_array_growone(etags);
+
+ BMO_elem_flag_enable(bm, e, EDGE_OLD);
+ }
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_EDGE, e) {
+ BMLoop *l2;
+ BMIter liter2;
+
+ if (BMO_elem_flag_test(bm, l->f, BEVEL_FLAG))
+ continue;
+
+ BM_ITER(l2, &liter2, bm, BM_LOOPS_OF_FACE, l->f) {
+ BM_elem_index_set(l2, BLI_array_count(tags)); /* set_loop */
+ BLI_array_growone(tags);
+
+ if (!BMO_elem_flag_test(bm, l2->e, EDGE_OLD)) {
+ BM_elem_index_set(l2->e, BLI_array_count(etags)); /* set_dirty! */
+ BLI_array_growone(etags);
+
+ BMO_elem_flag_enable(bm, l2->e, EDGE_OLD);
+ }
+ }
+
+ BMO_elem_flag_enable(bm, l->f, BEVEL_FLAG);
+ BLI_array_append(faces, l->f);
+ }
+ }
+ else {
+ BM_elem_index_set(e, -1); /* set_dirty! */
+ }
+ }
+#endif
+
+ /* create and assign looptag structure */
+ BMO_ITER(e, &siter, bm, op, "geom", BM_EDGE) {
+ BMLoop *l;
+ BMIter liter;
+
+ BMO_elem_flag_enable(bm, e->v1, BEVEL_FLAG|BEVEL_DEL);
+ BMO_elem_flag_enable(bm, e->v2, BEVEL_FLAG|BEVEL_DEL);
+
+ if (BM_edge_face_count(e) < 2) {
+ BMO_elem_flag_disable(bm, e, BEVEL_DEL);
+ BMO_elem_flag_disable(bm, e->v1, BEVEL_DEL);
+ BMO_elem_flag_disable(bm, e->v2, BEVEL_DEL);
+ }
+
+ if (!BLI_smallhash_haskey(&hash, (intptr_t)e)) {
+ BLI_array_growone(etags);
+ BM_elem_index_set(e, BLI_array_count(etags) - 1); /* set_dirty! */
+ BLI_smallhash_insert(&hash, (intptr_t)e, NULL);
+ BMO_elem_flag_enable(bm, e, EDGE_OLD);
+ }
+
+ /* find all faces surrounding e->v1 and, e->v2 */
+ for (i = 0; i < 2; i++) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_VERT, i ? e->v2:e->v1) {
+ BMLoop *l2;
+ BMIter liter2;
+
+ /* see if we've already processed this loop's fac */
+ if (BLI_smallhash_haskey(&hash, (intptr_t)l->f))
+ continue;
+
+ /* create tags for all loops in l-> */
+ BM_ITER(l2, &liter2, bm, BM_LOOPS_OF_FACE, l->f) {
+ BLI_array_growone(tags);
+ BM_elem_index_set(l2, BLI_array_count(tags) - 1); /* set_loop */
+
+ if (!BLI_smallhash_haskey(&hash, (intptr_t)l2->e)) {
+ BLI_array_growone(etags);
+ BM_elem_index_set(l2->e, BLI_array_count(etags) - 1); /* set_dirty! */
+ BLI_smallhash_insert(&hash, (intptr_t)l2->e, NULL);
+ BMO_elem_flag_enable(bm, l2->e, EDGE_OLD);
+ }
+ }
+
+ BLI_smallhash_insert(&hash, (intptr_t)l->f, NULL);
+ BMO_elem_flag_enable(bm, l->f, BEVEL_FLAG);
+ BLI_array_append(faces, l->f);
+ }
+ }
+ }
+
+ bm->elem_index_dirty |= BM_EDGE;
+
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BMIter eiter;
+
+ if (!BMO_elem_flag_test(bm, v, BEVEL_FLAG))
+ continue;
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ if (!BMO_elem_flag_test(bm, e, BEVEL_FLAG) && !ETAG_GET(e, v)) {
+ BMVert *v2;
+ float co[3];
+
+ v2 = BM_edge_other_vert(e, v);
+ sub_v3_v3v3(co, v2->co, v->co);
+ if (has_elens) {
+ float elen = *(float *)CustomData_bmesh_get_n(&bm->edata, e->head.data, CD_PROP_FLT, li);
+
+ normalize_v3(co);
+ mul_v3_fl(co, elen);
+ }
+
+ mul_v3_fl(co, fac);
+ add_v3_v3(co, v->co);
+
+ v2 = BM_vert_create(bm, co, v);
+ ETAG_SET(e, v, v2);
+ }
+ }
+ }
+
+ for (i = 0; i < BLI_array_count(faces); i++) {
+ BMLoop *l;
+ BMIter liter;
+
+ BMO_elem_flag_enable(bm, faces[i], FACE_OLD);
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, faces[i]) {
+ float co[3];
+
+ if (BMO_elem_flag_test(bm, l->e, BEVEL_FLAG)) {
+ if (BMO_elem_flag_test(bm, l->prev->e, BEVEL_FLAG))
+ {
+ tag = tags + BM_elem_index_get(l);
+ calc_corner_co(bm, l, fac, co, do_dist, do_even);
+ tag->newv = BM_vert_create(bm, co, l->v);
+ }
+ else {
+ tag = tags + BM_elem_index_get(l);
+ tag->newv = ETAG_GET(l->prev->e, l->v);
+
+ if (!tag->newv) {
+ sub_v3_v3v3(co, l->prev->v->co, l->v->co);
+ if (has_elens) {
+ float elen = *(float *)CustomData_bmesh_get_n(&bm->edata, l->prev->e->head.data,
+ CD_PROP_FLT, li);
+
+ normalize_v3(co);
+ mul_v3_fl(co, elen);
+ }
+
+ mul_v3_fl(co, fac);
+ add_v3_v3(co, l->v->co);
+
+ tag->newv = BM_vert_create(bm, co, l->v);
+
+ ETAG_SET(l->prev->e, l->v, tag->newv);
+ }
+ }
+ }
+ else if (BMO_elem_flag_test(bm, l->v, BEVEL_FLAG)) {
+ tag = tags + BM_elem_index_get(l);
+ tag->newv = ETAG_GET(l->e, l->v);
+
+ if (!tag->newv) {
+ sub_v3_v3v3(co, l->next->v->co, l->v->co);
+ if (has_elens) {
+ float elen = *(float *)CustomData_bmesh_get_n(&bm->edata, l->e->head.data, CD_PROP_FLT, li);
+
+ normalize_v3(co);
+ mul_v3_fl(co, elen);
+ }
+
+ mul_v3_fl(co, fac);
+ add_v3_v3(co, l->v->co);
+
+ tag = tags + BM_elem_index_get(l);
+ tag->newv = BM_vert_create(bm, co, l->v);
+
+ ETAG_SET(l->e, l->v, tag->newv);
+ }
+ }
+ else {
+ tag = tags + BM_elem_index_get(l);
+ tag->newv = l->v;
+ BMO_elem_flag_disable(bm, l->v, BEVEL_DEL);
+ }
+ }
+ }
+
+ /* create new faces inset from original face */
+ for (i = 0; i < BLI_array_count(faces); i++) {
+ BMLoop *l;
+ BMIter liter;
+ BMFace *f;
+ BMVert *lastv = NULL, *firstv = NULL;
+
+ BMO_elem_flag_enable(bm, faces[i], BEVEL_DEL);
+
+ BLI_array_empty(verts);
+ BLI_array_empty(edges);
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, faces[i]) {
+ BMVert *v2;
+
+ tag = tags + BM_elem_index_get(l);
+ BLI_array_append(verts, tag->newv);
+
+ if (!firstv)
+ firstv = tag->newv;
+
+ if (lastv) {
+ e = BM_edge_create(bm, lastv, tag->newv, l->e, TRUE);
+ BM_elem_attrs_copy(bm, bm, l->prev->e, e);
+ BLI_array_append(edges, e);
+ }
+ lastv = tag->newv;
+
+ v2 = ETAG_GET(l->e, l->next->v);
+
+ tag = &tags[BM_elem_index_get(l->next)];
+ if (!BMO_elem_flag_test(bm, l->e, BEVEL_FLAG) && v2 && v2 != tag->newv) {
+ BLI_array_append(verts, v2);
+
+ e = BM_edge_create(bm, lastv, v2, l->e, TRUE);
+ BM_elem_attrs_copy(bm, bm, l->e, e);
+
+ BLI_array_append(edges, e);
+ lastv = v2;
+ }
+ }
+
+ e = BM_edge_create(bm, firstv, lastv, BM_FACE_FIRST_LOOP(faces[i])->e, TRUE);
+ if (BM_FACE_FIRST_LOOP(faces[i])->prev->e != e) {
+ BM_elem_attrs_copy(bm, bm, BM_FACE_FIRST_LOOP(faces[i])->prev->e, e);
+ }
+ BLI_array_append(edges, e);
+
+ f = BM_face_create_ngon(bm, verts[0], verts[1], edges, BLI_array_count(edges), FALSE);
+ if (!f) {
+ printf("%s: could not make face!\n", __func__);
+ continue;
+ }
+
+ BMO_elem_flag_enable(bm, f, FACE_NEW);
+ }
+
+ for (i = 0; i < BLI_array_count(faces); i++) {
+ BMLoop *l;
+ BMIter liter;
+ int j;
+
+ /* create quad spans between split edge */
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, faces[i]) {
+ BMVert *v1 = NULL, *v2 = NULL, *v3 = NULL, *v4 = NULL;
+
+ if (!BMO_elem_flag_test(bm, l->e, BEVEL_FLAG))
+ continue;
+
+ v1 = tags[BM_elem_index_get(l)].newv;
+ v2 = tags[BM_elem_index_get(l->next)].newv;
+ if (l->radial_next != l) {
+ v3 = tags[BM_elem_index_get(l->radial_next)].newv;
+ if (l->radial_next->next->v == l->next->v) {
+ v4 = v3;
+ v3 = tags[BM_elem_index_get(l->radial_next->next)].newv;
+ }
+ else {
+ v4 = tags[BM_elem_index_get(l->radial_next->next)].newv;
+ }
+ }
+ else {
+ /* the loop is on a boundar */
+ v3 = l->next->v;
+ v4 = l->v;
+
+ for (j = 0; j < 2; j++) {
+ BMIter eiter;
+ BMVert *v = j ? v4 : v3;
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ if (!BM_vert_in_edge(e, v3) || !BM_vert_in_edge(e, v4))
+ continue;
+
+ if (!BMO_elem_flag_test(bm, e, BEVEL_FLAG) && BMO_elem_flag_test(bm, e, EDGE_OLD)) {
+ BMVert *vv;
+
+ vv = ETAG_GET(e, v);
+ if (!vv || BMO_elem_flag_test(bm, vv, BEVEL_FLAG))
+ continue;
+
+ if (j)
+ v1 = vv;
+ else
+ v2 = vv;
+ break;
+ }
+ }
+ }
+
+ BMO_elem_flag_disable(bm, v3, BEVEL_DEL);
+ BMO_elem_flag_disable(bm, v4, BEVEL_DEL);
+ }
+
+ if (v1 != v2 && v2 != v3 && v3 != v4) {
+ BMIter liter2;
+ BMLoop *l2, *l3;
+ BMEdge *e1, *e2;
+ float d1, d2, *d3;
+
+ f = BM_face_create_quad_tri(bm, v4, v3, v2, v1, l->f, TRUE);
+
+ e1 = BM_edge_exists(v4, v3);
+ e2 = BM_edge_exists(v2, v1);
+ BM_elem_attrs_copy(bm, bm, l->e, e1);
+ BM_elem_attrs_copy(bm, bm, l->e, e2);
+
+ /* set edge lengths of cross edges as the average of the cross edges they're based o */
+ if (has_elens) {
+ /* angle happens not to be used. why? - not sure it just isnt - campbell.
+ * leave this in incase we need to use it later */
+#if 0
+ float ang;
+#endif
+ e1 = BM_edge_exists(v1, v4);
+ e2 = BM_edge_exists(v2, v3);
+
+ if (l->radial_next->v == l->v) {
+ l2 = l->radial_next->prev;
+ l3 = l->radial_next->next;
+ }
+ else {
+ l2 = l->radial_next->next;
+ l3 = l->radial_next->prev;
+ }
+
+ d3 = CustomData_bmesh_get_n(&bm->edata, e1->head.data, CD_PROP_FLT, li);
+ d1 = *(float *)CustomData_bmesh_get_n(&bm->edata, l->prev->e->head.data, CD_PROP_FLT, li);
+ d2 = *(float *)CustomData_bmesh_get_n(&bm->edata, l2->e->head.data, CD_PROP_FLT, li);
+#if 0
+ ang = angle_v3v3v3(l->prev->v->co, l->v->co, BM_edge_other_vert(l2->e, l->v)->co);
+#endif
+ *d3 = (d1 + d2) * 0.5f;
+
+ d3 = CustomData_bmesh_get_n(&bm->edata, e2->head.data, CD_PROP_FLT, li);
+ d1 = *(float *)CustomData_bmesh_get_n(&bm->edata, l->next->e->head.data, CD_PROP_FLT, li);
+ d2 = *(float *)CustomData_bmesh_get_n(&bm->edata, l3->e->head.data, CD_PROP_FLT, li);
+#if 0
+ ang = angle_v3v3v3(BM_edge_other_vert(l->next->e, l->next->v)->co, l->next->v->co,
+ BM_edge_other_vert(l3->e, l->next->v)->co);
+#endif
+ *d3 = (d1 + d2) * 0.5f;
+ }
+
+ if (!f) {
+ fprintf(stderr, "%s: face index out of range! (bmesh internal error)\n", __func__);
+ continue;
+ }
+
+ BMO_elem_flag_enable(bm, f, FACE_NEW|FACE_SPAN);
+
+ /* un-tag edges in f for deletio */
+ BM_ITER(l2, &liter2, bm, BM_LOOPS_OF_FACE, f) {
+ BMO_elem_flag_disable(bm, l2->e, BEVEL_DEL);
+ }
+ }
+ else {
+ f = NULL;
+ }
+ }
+ }
+
+ /* fill in holes at vertices */
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BMIter eiter;
+ BMVert *vv, *vstart = NULL, *lastv = NULL;
+ SmallHash tmphash;
+ int rad, insorig = 0, err = 0;
+
+ BLI_smallhash_init(&tmphash);
+
+ if (!BMO_elem_flag_test(bm, v, BEVEL_FLAG))
+ continue;
+
+ BLI_array_empty(verts);
+ BLI_array_empty(edges);
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ BMIter liter;
+ BMVert *v1 = NULL, *v2 = NULL;
+ BMLoop *l;
+
+ if (BM_edge_face_count(e) < 2)
+ insorig = 1;
+
+ if (BM_elem_index_get(e) == -1)
+ continue;
+
+ rad = 0;
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_EDGE, e) {
+ if (!BMO_elem_flag_test(bm, l->f, FACE_OLD))
+ continue;
+
+ rad++;
+
+ tag = tags + BM_elem_index_get((l->v == v) ? l : l->next);
+
+ if (!v1)
+ v1 = tag->newv;
+ else if (!v2)
+ v2 = tag->newv;
+ }
+
+ if (rad < 2)
+ insorig = 1;
+
+ if (!v1)
+ v1 = ETAG_GET(e, v);
+ if (!v2 || v1 == v2)
+ v2 = ETAG_GET(e, v);
+
+ if (v1) {
+ if (!BLI_smallhash_haskey(&tmphash, (intptr_t)v1)) {
+ BLI_array_append(verts, v1);
+ BLI_smallhash_insert(&tmphash, (intptr_t)v1, NULL);
+ }
+
+ if (v2 && v1 != v2 && !BLI_smallhash_haskey(&tmphash, (intptr_t)v2)) {
+ BLI_array_append(verts, v2);
+ BLI_smallhash_insert(&tmphash, (intptr_t)v2, NULL);
+ }
+ }
+ }
+
+ if (!BLI_array_count(verts))
+ continue;
+
+ if (insorig) {
+ BLI_array_append(verts, v);
+ BLI_smallhash_insert(&tmphash, (intptr_t)v, NULL);
+ }
+
+ /* find edges that exist between vertices in verts. this is basically
+ * a topological walk of the edges connecting them */
+ vstart = vstart ? vstart : verts[0];
+ vv = vstart;
+ do {
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, vv) {
+ BMVert *vv2 = BM_edge_other_vert(e, vv);
+
+ if (vv2 != lastv && BLI_smallhash_haskey(&tmphash, (intptr_t)vv2)) {
+ /* if we've go over the same vert twice, break out of outer loop */
+ if (BLI_smallhash_lookup(&tmphash, (intptr_t)vv2) != NULL) {
+ e = NULL;
+ err = 1;
+ break;
+ }
+
+ /* use self pointer as ta */
+ BLI_smallhash_remove(&tmphash, (intptr_t)vv2);
+ BLI_smallhash_insert(&tmphash, (intptr_t)vv2, vv2);
+
+ lastv = vv;
+ BLI_array_append(edges, e);
+ vv = vv2;
+ break;
+ }
+ }
+
+ if (e == NULL) {
+ break;
+ }
+ } while (vv != vstart);
+
+ if (err) {
+ continue;
+ }
+
+ /* there may not be a complete loop of edges, so start again and make
+ * final edge afterwards. in this case, the previous loop worked to
+ * find one of the two edges at the extremes. */
+ if (vv != vstart) {
+ /* undo previous taggin */
+ for (i = 0; i < BLI_array_count(verts); i++) {
+ BLI_smallhash_remove(&tmphash, (intptr_t)verts[i]);
+ BLI_smallhash_insert(&tmphash, (intptr_t)verts[i], NULL);
+ }
+
+ vstart = vv;
+ lastv = NULL;
+ BLI_array_empty(edges);
+ do {
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, vv) {
+ BMVert *vv2 = BM_edge_other_vert(e, vv);
+
+ if (vv2 != lastv && BLI_smallhash_haskey(&tmphash, (intptr_t)vv2)) {
+ /* if we've go over the same vert twice, break out of outer loo */
+ if (BLI_smallhash_lookup(&tmphash, (intptr_t)vv2) != NULL) {
+ e = NULL;
+ err = 1;
+ break;
+ }
+
+ /* use self pointer as ta */
+ BLI_smallhash_remove(&tmphash, (intptr_t)vv2);
+ BLI_smallhash_insert(&tmphash, (intptr_t)vv2, vv2);
+
+ lastv = vv;
+ BLI_array_append(edges, e);
+ vv = vv2;
+ break;
+ }
+ }
+ if (e == NULL)
+ break;
+ } while (vv != vstart);
+
+ if (!err) {
+ e = BM_edge_create(bm, vv, vstart, NULL, TRUE);
+ BLI_array_append(edges, e);
+ }
+ }
+
+ if (err)
+ continue;
+
+ if (BLI_array_count(edges) >= 3) {
+ BMFace *f;
+
+ if (BM_face_exists(bm, verts, BLI_array_count(verts), &f))
+ continue;
+
+ f = BM_face_create_ngon(bm, lastv, vstart, edges, BLI_array_count(edges), FALSE);
+ if (!f) {
+ fprintf(stderr, "%s: in bevel vert fill! (bmesh internal error)\n", __func__);
+ }
+ else {
+ BMO_elem_flag_enable(bm, f, FACE_NEW|FACE_HOLE);
+ }
+ }
+ BLI_smallhash_release(&tmphash);
+ }
+
+ /* copy over customdat */
+ for (i = 0; i < BLI_array_count(faces); i++) {
+ BMLoop *l;
+ BMIter liter;
+ BMFace *f = faces[i];
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ BMLoop *l2;
+ BMIter liter2;
+
+ tag = tags + BM_elem_index_get(l);
+ if (!tag->newv)
+ continue;
+
+ BM_ITER(l2, &liter2, bm, BM_LOOPS_OF_VERT, tag->newv) {
+ if (!BMO_elem_flag_test(bm, l2->f, FACE_NEW) || (l2->v != tag->newv && l2->v != l->v))
+ continue;
+
+ if (tag->newv != l->v || HasMDisps) {
+ BM_elem_attrs_copy(bm, bm, l->f, l2->f);
+ BM_loop_interp_from_face(bm, l2, l->f, TRUE, TRUE);
+ }
+ else {
+ BM_elem_attrs_copy(bm, bm, l->f, l2->f);
+ BM_elem_attrs_copy(bm, bm, l, l2);
+ }
+
+ if (HasMDisps) {
+ BMLoop *l3;
+ BMIter liter3;
+
+ BM_ITER(l3, &liter3, bm, BM_LOOPS_OF_FACE, l2->f) {
+ BM_loop_interp_multires(bm, l3, l->f);
+ }
+ }
+ }
+ }
+ }
+
+ /* handle vertices along boundary edge */
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMO_elem_flag_test(bm, v, VERT_OLD) &&
+ BMO_elem_flag_test(bm, v, BEVEL_FLAG) &&
+ !BMO_elem_flag_test(bm, v, BEVEL_DEL))
+ {
+ BMLoop *l;
+ BMLoop *lorig = NULL;
+ BMIter liter;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_VERT, v) {
+ // BMIter liter2;
+ // BMLoop *l2 = l->v == v ? l : l->next, *l3;
+
+ if (BMO_elem_flag_test(bm, l->f, FACE_OLD)) {
+ lorig = l;
+ break;
+ }
+ }
+
+ if (!lorig)
+ continue;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_VERT, v) {
+ BMLoop *l2 = l->v == v ? l : l->next;
+
+ BM_elem_attrs_copy(bm, bm, lorig->f, l2->f);
+ BM_elem_attrs_copy(bm, bm, lorig, l2);
+ }
+ }
+ }
+#if 0
+ /* clean up any remaining 2-edged face */
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (f->len == 2) {
+ BMFace *faces[2] = {f, BM_FACE_FIRST_LOOP(f)->radial_next->f};
+
+ if (faces[0] == faces[1])
+ BM_face_kill(bm, f);
+ else
+ BM_faces_join(bm, faces, 2);
+ }
+ }
+#endif
+
+ BMO_op_callf(bm, "del geom=%fv context=%i", BEVEL_DEL, DEL_VERTS);
+
+ /* clean up any edges that might not get properly delete */
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (BMO_elem_flag_test(bm, e, EDGE_OLD) && !e->l)
+ BMO_elem_flag_enable(bm, e, BEVEL_DEL);
+ }
+
+ BMO_op_callf(bm, "del geom=%fe context=%i", BEVEL_DEL, DEL_EDGES);
+ BMO_op_callf(bm, "del geom=%ff context=%i", BEVEL_DEL, DEL_FACES);
+
+ BLI_smallhash_release(&hash);
+ BLI_array_free(tags);
+ BLI_array_free(etags);
+ BLI_array_free(verts);
+ BLI_array_free(edges);
+ BLI_array_free(faces);
+
+ BMO_slot_from_flag(bm, op, "face_spans", FACE_SPAN, BM_FACE);
+ BMO_slot_from_flag(bm, op, "face_holes", FACE_HOLE, BM_FACE);
+}
diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c
new file mode 100644
index 00000000000..6ab6d28008b
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_connect.c
@@ -0,0 +1,414 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+
+#include "bmesh.h"
+
+#include "BLI_math.h"
+#include "BLI_array.h"
+
+#define VERT_INPUT 1
+#define EDGE_OUT 1
+#define FACE_NEW 2
+#define EDGE_MARK 4
+#define EDGE_DONE 8
+
+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 **verts = NULL;
+ BLI_array_declare(verts);
+ int i;
+
+ BMO_slot_buffer_flag_enable(bm, op, "verts", VERT_INPUT, BM_VERT);
+
+ for (f = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, NULL); f; f = BM_iter_step(&iter)) {
+ BLI_array_empty(loops);
+ BLI_array_empty(verts);
+
+ if (BMO_elem_flag_test(bm, f, FACE_NEW)) continue;
+
+ l = BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, f);
+ lastl = NULL;
+ for ( ; l; l = BM_iter_step(&liter)) {
+ if (BMO_elem_flag_test(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_face_legal_splits(bm, f, (BMLoop *(*)[2])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_face_split(bm, f, verts[i * 2], verts[i * 2 + 1], &nl, NULL);
+ f = nf;
+
+ if (!nl || !nf) {
+ BMO_error_raise(bm, op, BMERR_CONNECTVERT_FAILED, NULL);
+ BLI_array_free(loops);
+ return;
+ }
+ BMO_elem_flag_enable(bm, nf, FACE_NEW);
+ BMO_elem_flag_enable(bm, nl->e, EDGE_OUT);
+ }
+ }
+
+ BMO_slot_from_flag(bm, op, "edgeout", EDGE_OUT, BM_EDGE);
+
+ BLI_array_free(loops);
+ BLI_array_free(verts);
+}
+
+static BMVert *get_outer_vert(BMesh *bm, BMEdge *e)
+{
+ BMIter iter;
+ BMEdge *e2;
+ int i;
+
+ i = 0;
+ BM_ITER(e2, &iter, bm, BM_EDGES_OF_VERT, e->v1) {
+ if (BMO_elem_flag_test(bm, e2, EDGE_MARK)) {
+ i++;
+ }
+ }
+
+ return (i == 2) ? e->v2 : e->v1;
+}
+
+/* Clamp x to the interval {0..len-1}, with wrap-around */
+static int clamp_index(const int x, const int len)
+{
+ return (x < 0) ? (len - (-x % len)) : (x % len);
+}
+
+/* There probably is a better way to swap BLI_arrays, or if there
+ * isn't there should be... */
+#define ARRAY_SWAP(elemtype, arr1, arr2) \
+ { \
+ int i; \
+ elemtype *arr_tmp = NULL; \
+ BLI_array_declare(arr_tmp); \
+ for (i = 0; i < BLI_array_count(arr1); i++) { \
+ BLI_array_append(arr_tmp, arr1[i]); \
+ } \
+ BLI_array_empty(arr1); \
+ for (i = 0; i < BLI_array_count(arr2); i++) { \
+ BLI_array_append(arr1, arr2[i]); \
+ } \
+ BLI_array_empty(arr2); \
+ for (i = 0; i < BLI_array_count(arr_tmp); i++) { \
+ BLI_array_append(arr2, arr_tmp[i]); \
+ } \
+ BLI_array_free(arr_tmp); \
+ }
+
+void bmesh_bridge_loops_exec(BMesh *bm, BMOperator *op)
+{
+ BMEdge **ee1 = NULL, **ee2 = NULL;
+ BMVert **vv1 = NULL, **vv2 = NULL;
+ BLI_array_declare(ee1);
+ BLI_array_declare(ee2);
+ BLI_array_declare(vv1);
+ BLI_array_declare(vv2);
+ BMOIter siter;
+ BMIter iter;
+ BMEdge *e, *nexte;
+ int c = 0, cl1 = 0, cl2 = 0;
+
+ BMO_slot_buffer_flag_enable(bm, op, "edges", EDGE_MARK, BM_EDGE);
+
+ BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
+ if (!BMO_elem_flag_test(bm, e, EDGE_DONE)) {
+ BMVert *v, *ov;
+ /* BMEdge *e2, *e3, *oe = e; */ /* UNUSED */
+ BMEdge *e2, *e3;
+
+ if (c > 2) {
+ BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Select only two edge loops");
+ goto cleanup;
+ }
+
+ e2 = e;
+ v = e->v1;
+ do {
+ v = BM_edge_other_vert(e2, v);
+ nexte = NULL;
+ BM_ITER(e3, &iter, bm, BM_EDGES_OF_VERT, v) {
+ if (e3 != e2 && BMO_elem_flag_test(bm, e3, EDGE_MARK)) {
+ if (nexte == NULL) {
+ nexte = e3;
+ }
+ else {
+ /* edges do not form a loop: there is a disk
+ * with more than two marked edges. */
+ BMO_error_raise(bm, op, BMERR_INVALID_SELECTION,
+ "Selection must only contain edges from two edge loops");
+ goto cleanup;
+ }
+ }
+ }
+
+ if (nexte)
+ e2 = nexte;
+ } while (nexte && e2 != e);
+
+ if (!e2)
+ e2 = e;
+
+ e = e2;
+ ov = v;
+ do {
+ if (c == 0) {
+ BLI_array_append(ee1, e2);
+ BLI_array_append(vv1, v);
+ }
+ else {
+ BLI_array_append(ee2, e2);
+ BLI_array_append(vv2, v);
+ }
+
+ BMO_elem_flag_enable(bm, e2, EDGE_DONE);
+
+ v = BM_edge_other_vert(e2, v);
+ BM_ITER(e3, &iter, bm, BM_EDGES_OF_VERT, v) {
+ if (e3 != e2 && BMO_elem_flag_test(bm, e3, EDGE_MARK) && !BMO_elem_flag_test(bm, e3, EDGE_DONE)) {
+ break;
+ }
+ }
+ if (e3)
+ e2 = e3;
+ } while (e3 && e2 != e);
+
+ if (v && !e3) {
+ if (c == 0) {
+ if (BLI_array_count(vv1) && v == vv1[BLI_array_count(vv1) - 1]) {
+ printf("%s: internal state waning *TODO DESCRIPTION!*\n", __func__);
+ }
+ BLI_array_append(vv1, v);
+ }
+ else {
+ BLI_array_append(vv2, v);
+ }
+ }
+
+ /* test for connected loops, and set cl1 or cl2 if so */
+ if (v == ov) {
+ if (c == 0) {
+ cl1 = 1;
+ }
+ else {
+ cl2 = 1;
+ }
+ }
+
+ c++;
+ }
+ }
+
+ if (ee1 && ee2) {
+ int i, j;
+ BMVert *v1, *v2, *v3, *v4;
+ int starti = 0, dir1 = 1, wdir = 0, lenv1, lenv2;
+
+ /* Simplify code below by avoiding the (!cl1 && cl2) case */
+ if (!cl1 && cl2) {
+ SWAP(int, cl1, cl2);
+ ARRAY_SWAP(BMVert *, vv1, vv2);
+ ARRAY_SWAP(BMEdge *, ee1, ee2);
+ }
+
+ lenv1 = lenv2 = BLI_array_count(vv1);
+
+ /* Below code assumes vv1/vv2 each have at least two verts. should always be
+ * a safe assumption, since ee1/ee2 are non-empty and an edge has two verts. */
+ BLI_assert((lenv1 > 1) && (lenv2 > 1));
+
+ /* BMESH_TODO: Would be nice to handle cases where the edge loops
+ * have different edge counts by generating triangles & quads for
+ * the bridge instead of quads only. */
+ if (BLI_array_count(ee1) != BLI_array_count(ee2)) {
+ BMO_error_raise(bm, op, BMERR_INVALID_SELECTION,
+ "Selected loops must have equal edge counts");
+ goto cleanup;
+ }
+
+ j = 0;
+ if (vv1[0] == vv1[lenv1 - 1]) {
+ lenv1--;
+ }
+ if (vv2[0] == vv2[lenv2 - 1]) {
+ lenv2--;
+ }
+
+ /* Find starting point and winding direction for two unclosed loops */
+ if (!cl1 && !cl2) {
+ /* First point of loop 1 */
+ v1 = get_outer_vert(bm, ee1[0]);
+ /* Last point of loop 1 */
+ v2 = get_outer_vert(bm, ee1[clamp_index(-1, BLI_array_count(ee1))]);
+ /* First point of loop 2 */
+ v3 = get_outer_vert(bm, ee2[0]);
+ /* Last point of loop 2 */
+ v4 = get_outer_vert(bm, ee2[clamp_index(-1, BLI_array_count(ee2))]);
+
+ /* If v1 is a better match for v4 than v3, AND v2 is a better match
+ * for v3 than v4, the loops are in opposite directions, so reverse
+ * the order of reads from vv1. We can avoid sqrt for comparison */
+ if (len_squared_v3v3(v1->co, v3->co) > len_squared_v3v3(v1->co, v4->co) &&
+ len_squared_v3v3(v2->co, v4->co) > len_squared_v3v3(v2->co, v3->co))
+ {
+ dir1 = -1;
+ starti = clamp_index(-1, lenv1);
+ }
+ }
+
+ /* Find the shortest distance from a vert in vv1 to vv2[0]. Use that
+ * vertex in vv1 as a starting point in the first loop, while starting
+ * from vv2[0] in the second loop. This is a simplistic attempt to get
+ * a better edge-to-edge match between the two loops. */
+ if (cl1) {
+ int previ, nexti;
+ float min = 1e32;
+
+ /* BMESH_TODO: Would be nice to do a more thorough analysis of all
+ * the vertices in both loops to find a more accurate match for the
+ * starting point and winding direction of the bridge generation. */
+
+ for (i = 0; i < BLI_array_count(vv1); i++) {
+ if (len_v3v3(vv1[i]->co, vv2[0]->co) < min) {
+ min = len_v3v3(vv1[i]->co, vv2[0]->co);
+ starti = i;
+ }
+ }
+
+ /* Reverse iteration order for the first loop if the distance of
+ * the (starti - 1) vert from vv1 is a better match for vv2[1] than
+ * the (starti + 1) vert.
+ *
+ * This is not always going to be right, but it will work better in
+ * the average case.
+ */
+ previ = clamp_index(starti - 1, lenv1);
+ nexti = clamp_index(starti + 1, lenv1);
+
+ /* avoid sqrt for comparison */
+ if (len_squared_v3v3(vv1[nexti]->co, vv2[1]->co) > len_squared_v3v3(vv1[previ]->co, vv2[1]->co)) {
+ /* reverse direction for reading vv1 (1 is forward, -1 is backward) */
+ dir1 = -1;
+ }
+ }
+
+ /* Vert rough attempt to determine proper winding for the bridge quads:
+ * just uses the first loop it finds for any of the edges of ee2 or ee1 */
+ if (wdir == 0) {
+ for (i = 0; i < BLI_array_count(ee2); i++) {
+ if (ee2[i]->l) {
+ wdir = (ee2[i]->l->v == vv2[i]) ? (-1) : (1);
+ break;
+ }
+ }
+ }
+ if (wdir == 0) {
+ for (i = 0; i < BLI_array_count(ee1); i++) {
+ j = clamp_index((i * dir1) + starti, BLI_array_count(ee1));
+ if (ee1[j]->l && ee2[j]->l) {
+ wdir = (ee2[j]->l->v == vv2[j]) ? (1) : (-1);
+ break;
+ }
+ }
+ }
+
+ /* Generate the bridge quads */
+ for (i = 0; i < BLI_array_count(ee1) && i < BLI_array_count(ee2); i++) {
+ BMFace *f;
+ int i1, i1next, i2, i2next;
+
+ i1 = clamp_index(i * dir1 + starti, lenv1);
+ i1next = clamp_index((i + 1) * dir1 + starti, lenv1);
+ i2 = i;
+ i2next = clamp_index(i + 1, lenv2);
+
+ if (vv1[i1] == vv1[i1next]) {
+ continue;
+ }
+
+ if (wdir < 0) {
+ SWAP(int, i1, i1next);
+ SWAP(int, i2, i2next);
+ }
+
+ f = BM_face_create_quad_tri(bm,
+ vv1[i1],
+ vv2[i2],
+ vv2[i2next],
+ vv1[i1next],
+ NULL, TRUE);
+ if (!f || f->len != 4) {
+ fprintf(stderr, "%s: in bridge! (bmesh internal error)\n", __func__);
+ }
+ }
+ }
+
+cleanup:
+ BLI_array_free(ee1);
+ BLI_array_free(ee2);
+ BLI_array_free(vv1);
+ BLI_array_free(vv2);
+}
diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c
new file mode 100644
index 00000000000..d90e5c36c80
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_create.c
@@ -0,0 +1,1412 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_heap.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_array.h"
+#include "BLI_smallhash.h"
+#include "BLI_rand.h"
+
+#include "bmesh.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;
+ BMDiskLink v1_disk_link, v2_disk_link;
+} EdgeData;
+
+typedef struct VertData {
+ BMEdge *e;
+ float no[3], offco[3], sco[3]; /* offco is vertex coordinate slightly offset randoml */
+ int tag;
+} VertData;
+
+static int count_edge_faces(BMesh *bm, BMEdge *e);
+
+/**** rotation system code * */
+
+#define RS_GET_EDGE_LINK(e, v, e_data) ( \
+ (v) == ((BMEdge *)(e))->v1 ? \
+ &(((EdgeData *)(e_data))->v1_disk_link) : \
+ &(((EdgeData *)(e_data))->v2_disk_link) \
+ )
+
+
+static int rotsys_append_edge(struct BMEdge *e, struct BMVert *v,
+ EdgeData *edata, VertData *vdata)
+{
+ EdgeData *ed = &edata[BM_elem_index_get(e)];
+ VertData *vd = &vdata[BM_elem_index_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 {
+ BMDiskLink *dl1, *dl2, *dl3;
+ EdgeData *ved = &edata[BM_elem_index_get(vd->e)];
+
+ dl1 = RS_GET_EDGE_LINK(e, v, ed);
+ dl2 = RS_GET_EDGE_LINK(vd->e, v, ved);
+ dl3 = dl2->prev ? RS_GET_EDGE_LINK(dl2->prev, v, &edata[BM_elem_index_get(dl2->prev)]) : NULL;
+
+ dl1->next = vd->e;
+ dl1->prev = dl2->prev;
+
+ dl2->prev = e;
+ if (dl3) {
+ dl3->next = e;
+ }
+ }
+
+ return TRUE;
+}
+
+static void UNUSED_FUNCTION(rotsys_remove_edge)(struct BMEdge *e, struct BMVert *v,
+ EdgeData *edata, VertData *vdata)
+{
+ EdgeData *ed = edata + BM_elem_index_get(e);
+ VertData *vd = vdata + BM_elem_index_get(v);
+ BMDiskLink *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 != (BMEdge *)e1->next) ? (BMEdge *)e1->next : NULL;
+
+ e1->next = e1->prev = NULL;
+}
+
+static struct BMEdge *rotsys_nextedge(struct BMEdge *e, struct BMVert *v,
+ EdgeData *edata, VertData *UNUSED(vdata))
+{
+ if (v == e->v1)
+ return edata[BM_elem_index_get(e)].v1_disk_link.next;
+ if (v == e->v2)
+ return edata[BM_elem_index_get(e)].v2_disk_link.next;
+ return NULL;
+}
+
+static BMEdge *rotsys_prevedge(BMEdge *e, BMVert *v,
+ EdgeData *edata, VertData *UNUSED(vdata))
+{
+ if (v == e->v1)
+ return edata[BM_elem_index_get(e)].v1_disk_link.prev;
+ if (v == e->v2)
+ return edata[BM_elem_index_get(e)].v2_disk_link.prev;
+ return NULL;
+}
+
+static void rotsys_reverse(struct BMEdge *UNUSED(e), struct BMVert *v, EdgeData *edata, VertData *vdata)
+{
+ BMEdge **edges = NULL;
+ BMEdge *e_first;
+ BMEdge *e;
+ BLI_array_staticdeclare(edges, BM_NGON_STACK_SIZE);
+ int i, totedge;
+
+ e = e_first = vdata[BM_elem_index_get(v)].e;
+ do {
+ BLI_array_append(edges, e);
+ e = rotsys_nextedge(e, v, edata, vdata);
+ } while (e != e_first);
+
+ totedge = BLI_array_count(edges);
+ for (i = 0; i < totedge / 2; i++) {
+ SWAP(BMEdge *, edges[i], edges[totedge - 1 - i]);
+ }
+
+ vdata[BM_elem_index_get(v)].e = NULL;
+ for (i = 0; i < totedge; i++) {
+ rotsys_append_edge(edges[i], v, edata, vdata);
+ }
+
+ BLI_array_free(edges);
+}
+
+static int UNUSED_FUNCTION(rotsys_count)(struct BMVert *v, EdgeData *edata, VertData *vdata)
+{
+ BMEdge *e = vdata[BM_elem_index_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[BM_elem_index_get(v)].e);
+
+ return i;
+}
+
+static int UNUSED_FUNCTION(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 backwar */
+ 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_edge_other_vert(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_face_create_ngon(bm, verts[0], verts[1], edges, BLI_array_count(edges), TRUE);
+ if (!f)
+ continue;
+ }
+ }
+
+ return 0;
+}
+
+static 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 = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i = 0; i < bm->totvert; i++, BM_iter_step(&iter)) {
+ vd = vdata + BM_elem_index_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 + BM_elem_index_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 + BM_elem_index_get(v);
+
+ if (!vd->e)
+ continue;
+
+ e = vd->e;
+ do {
+ BMVert *v2 = BM_edge_other_vert(e, v);
+ VertData *vd2 = vdata + BM_elem_index_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);
+ }
+ }
+
+ BLI_array_free(stack);
+}
+
+static void init_rotsys(BMesh *bm, EdgeData *edata, VertData *vdata)
+{
+ BMIter iter;
+ BMEdge *e;
+ BMEdge **edges = NULL;
+ BLI_array_staticdeclare(edges, BM_NGON_STACK_SIZE);
+ BMVert *v;
+ /* BMVert **verts = NULL; */
+ /* BLI_array_staticdeclare(verts, BM_NGON_STACK_SIZE); */ /* UNUSE */
+ 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 (BM_elem_index_get(v) == -1)
+ continue;
+
+ BLI_array_empty(edges);
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ if (BMO_elem_flag_test(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_edge_other_vert(e1, v))->co, v->co);
+ sub_v3_v3v3(vec2, (BM_edge_other_vert(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 coordinate */
+ for (i = 0; i < totedge; i++) {
+ BMEdge *e1;
+ BMVert *v2;
+ float cvec[3], vec1[3];
+
+ e1 = edges[i];
+ v2 = BM_edge_other_vert(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[BM_elem_index_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_edge_other_vert(e1, v);
+ v2 = BM_edge_other_vert(e2, v);
+ v3 = BM_edge_other_vert(e3, v);
+
+ vd1 = vdata + BM_elem_index_get(v1);
+ vd2 = vdata + BM_elem_index_get(v2);
+ vd3 = vdata + BM_elem_index_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.01f;
+ normalize_v3(vec1); normalize_v3(vec2); normalize_v3(vec3);
+
+#ifdef STRAIGHT
+#undef STRAIGHT
+#endif
+#define STRAIGHT(vec11, vec22) (fabsf(dot_v3v3((vec11), (vec22))) > 1.0f - ((float)FLT_EPSILON * 1000.0f))
+
+ 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[BM_elem_index_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_edge_other_vert(e1, v);
+ v2 = BM_edge_other_vert(e2, v);
+ v3 = BM_edge_other_vert(e3, v);
+
+ vd1 = vdata + BM_elem_index_get(v1);
+ vd2 = vdata + BM_elem_index_get(v2);
+ vd3 = vdata + BM_elem_index_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);
+
+ /* Other way to determine if two vectors approach are (nearly) parallel: the
+ * cross product of the two vectors will approach zero */
+ s1 = (dot_v3v3(n1, n1) < (0.0f + FLT_EPSILON * 10));
+ s2 = (dot_v3v3(n2, n2) < (0.0f + FLT_EPSILON * 10));
+ s3 = (totedge < 3) ? 0 : (dot_v3v3(n3, n3) < (0.0f + FLT_EPSILON * 10));
+
+ normalize_v3(n1); normalize_v3(n2); normalize_v3(n3);
+
+ if (s1 || s2 || s3) {
+ fprintf(stderr, "%s: s1: %d, s2: %d, s3: %dx (bmesh internal error)\n", __func__, 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 are sorted */
+ for (i = 0; i < totedge; i++) {
+ BMEdge *e1 = edges[i], *e2 = edges[(i + 1) % totedge];
+ float eno[3];
+
+ normal_tri_v3(eno, BM_edge_other_vert(e1, v)->co, v->co, BM_edge_other_vert(e2, v)->co);
+ add_v3_v3(no, eno);
+
+ rotsys_append_edge(edges[i], v, edata, vdata);
+ }
+
+ normalize_v3(no);
+ copy_v3_v3(vdata[BM_elem_index_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 geometr */
+ BMVert *lastv;
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BMVert *v2;
+ BMFace *f;
+ int totedge = BM_vert_edge_count(v);
+
+ if (BM_elem_index_get(v) == -1)
+ continue;
+
+ //cv = BM_vert_create(bm, cent, v);
+ //BM_elem_index_set(cv, -1); /* set_dirty! */
+ i = 0;
+ e = vdata[BM_elem_index_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_edge_other_vert(e, v))
+ continue;
+
+ sub_v3_v3v3(co, (BM_edge_other_vert(e, v))->co, vdata[BM_elem_index_get(v)].offco);
+ mul_v3_fl(co, f);
+ add_v3_v3(co, vdata[BM_elem_index_get(v)].offco);
+
+ v2 = BM_vert_create(bm, co, NULL);
+ BM_elem_index_set(v2, -1); /* set_dirty! */
+ //BM_edge_create(bm, cv, v2, NULL, FALSE);
+
+ BM_elem_select_set(bm, v2, TRUE);
+ if (lastv) {
+ e2 = BM_edge_create(bm, lastv, v2, NULL, FALSE);
+ BM_elem_select_set(bm, e2, TRUE);
+ }
+
+ lastv = v2;
+
+ e = rotsys_nextedge(e, v, edata, vdata);
+ i++;
+ } while (e != vdata[BM_elem_index_get(v)].e);
+ }
+#endif
+
+ BLI_array_free(edges);
+}
+
+static PathBase *edge_pathbase_new(void)
+{
+ PathBase *pb = MEM_callocN(sizeof(PathBase), "PathBase");
+
+ pb->nodepool = BLI_mempool_create(sizeof(EPathNode), 1, 512, TRUE, FALSE);
+ pb->pathpool = BLI_mempool_create(sizeof(EPath), 1, 512, TRUE, FALSE);
+
+ return pb;
+}
+
+static void edge_pathbase_free(PathBase *pathbase)
+{
+ BLI_mempool_destroy(pathbase->nodepool);
+ BLI_mempool_destroy(pathbase->pathpool);
+ MEM_freeN(pathbase);
+}
+
+static 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;
+}
+
+static 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;
+}
+
+static float edge_weight_path(EPath *path, EdgeData *edata, VertData *UNUSED(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[BM_elem_index_get(node->e)].ftag;
+ if (node->prev) {
+ /* BMESH_TOD */
+ (void)first;
+ //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;
+}
+
+
+static 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);
+}
+
+static EPath *edge_find_shortest_path(BMesh *bm, BMOperator *op, BMEdge *edge, EdgeData *edata,
+ VertData *vdata, PathBase *pathbase, int group)
+{
+ BMEdge *e;
+ 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_slot_int_get(op, "use_restrict");
+
+ startv = edata[BM_elem_index_get(edge)].ftag ? edge->v2 : edge->v1;
+ endv = edata[BM_elem_index_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_elem_flag_test(bm, f, FACE_IGNORE)) {
+ BLI_ghash_remove(gh, endv, NULL, NULL);
+ continue;
+ }
+ }
+ break;
+ }
+
+ vd = vdata + BM_elem_index_get(v1);
+ if (!vd->e)
+ continue;
+
+ v2 = NULL;
+ while (1) {
+ if (!last->cure) {
+ last->cure = e = vdata[BM_elem_index_get(last->v)].e;
+ }
+ else {
+ last->cure = e = rotsys_nextedge(last->cure, last->v, edata, vdata);
+ if (last->cure == vdata[BM_elem_index_get(last->v)].e) {
+ v2 = NULL;
+ break;
+ }
+ }
+
+ if (e == edge || !BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ continue;
+ }
+
+ v2 = BM_edge_other_vert(e, last->v);
+
+ if (BLI_ghash_haskey(gh, v2)) {
+ v2 = NULL;
+ continue;
+ }
+
+ if (use_restrict && BMO_slot_map_contains(bm, op, "restrict", e)) {
+ int group = BMO_slot_map_int_get(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 hea */
+ BLI_heap_insert(heap, path->weight, path);
+
+ /* put v2 in gh ma */
+ 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_elem_flag_test(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 **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_slot_int_get(op, "use_restrict");
+ int i, j, group = 0;
+ unsigned int winding[2]; /* accumulte winding directions for each edge which has a face */
+
+ if (!bm->totvert || !bm->totedge)
+ return;
+
+ edata = MEM_callocN(sizeof(EdgeData)*bm->totedge, "EdgeData");
+ vdata = MEM_callocN(sizeof(VertData)*bm->totvert, "VertData");
+
+ BMO_slot_buffer_flag_enable(bm, op, "edges", EDGE_MARK, BM_EDGE);
+ BMO_slot_buffer_flag_enable(bm, op, "excludefaces", FACE_IGNORE, BM_FACE);
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BMO_elem_flag_enable(bm, f, ELE_ORIG);
+ }
+
+ i = 0;
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ BM_elem_index_set(e, i); /* set_inline */
+
+ if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ edata[i].tag = 2;
+ }
+
+ i++;
+ }
+ bm->elem_index_dirty &= ~BM_EDGE;
+
+ 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_slot_map_contains(bm, op, "restrict", e))
+ continue;
+
+ if (edata[BM_elem_index_get(e)].tag < 2) {
+ edge = e;
+
+ if (use_restrict) {
+ int i = 0, j = 0, gi = 0;
+
+ group = BMO_slot_map_int_get(bm, op, "restrict", e);
+
+ for (i = 0; i < 30; i++) {
+ if (group & (1 << i)) {
+ j++;
+ gi = i;
+
+ if (j - 1 == edata[BM_elem_index_get(e)].tag) {
+ break;
+ }
+ }
+ }
+
+ group = (1 << gi);
+ }
+
+ break;
+ }
+ }
+
+ if (!edge)
+ break;
+
+ edata[BM_elem_index_get(edge)].tag += 1;
+
+ path = edge_find_shortest_path(bm, op, edge, edata, vdata, pathbase, group);
+ if (!path)
+ continue;
+
+ winding[0] = winding[1] = 0;
+
+ 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_exists(node->v, node->next->v);
+
+ /* this should never happe */
+ if (!e)
+ break;
+
+ /* check on the winding */
+ if (e->l) {
+ BMVert *test_v1, *test_v2;
+ /* we want to use the reverse winding to the existing order */
+ BM_edge_ordered_verts(edge, &test_v2, &test_v1);
+
+ /* edges vote on which winding wins out */
+ winding[(test_v1 == node->v)]++;
+ }
+
+ edata[BM_elem_index_get(e)].ftag++;
+ BLI_array_growone(edges);
+ edges[i++] = e;
+
+ BLI_array_append(verts, node->v);
+ }
+
+ BLI_array_growone(edges);
+ edges[i++] = edge;
+ edata[BM_elem_index_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) {
+ BMVert *v1, *v2;
+
+ /* to define the winding order must select first edge,
+ * otherwise we could leave this as-is */
+ edge = edges[0];
+
+ /* if these are even it doesnt really matter what to do,
+ * with consistent geometry one will be zero, the choice is clear */
+ if (winding[0] > winding[1]) {
+ v1 = verts[0];
+ v2 = verts[1];
+ }
+ else {
+ v1 = verts[1];
+ v2 = verts[0];
+ }
+
+ f = BM_face_create_ngon(bm, v1, v2, edges, i, TRUE);
+ if (f && !BMO_elem_flag_test(bm, f, ELE_ORIG)) {
+ BMO_elem_flag_enable(bm, f, FACE_NEW);
+ }
+
+ if (use_restrict)
+ BMO_slot_map_int_insert(bm, op, "faceout_groupmap", f, path->group);
+ }
+
+ edge_free_path(pathbase, path);
+ }
+
+ BMO_slot_from_flag(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);
+}
+
+static 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_elem_flag_test(bm, e2, EDGE_MARK)) &&
+ (!BMO_elem_flag_test(bm, e2, EDGE_VIS)) &&
+ (e2 != e))
+ {
+ return e2;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void bmesh_edgenet_prepare(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMEdge *e;
+ 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_slot_buffer_flag_enable(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_edge_flags_count(bm, i ? e->v2 : e->v1, EDGE_MARK);
+ if (count > 2) {
+ ok = 0;
+ break;
+ }
+ }
+
+ if (!ok) {
+ break;
+ }
+ }
+
+ /* we don't have valid edge layouts, retur */
+ if (!ok) {
+ return;
+ }
+
+ /* find connected loops within the input edge */
+ count = 0;
+ while (1) {
+ BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
+ if (!BMO_elem_flag_test(bm, e, EDGE_VIS)) {
+ if ( BMO_vert_edge_flags_count(bm, e->v1, EDGE_MARK) == 1 ||
+ BMO_vert_edge_flags_count(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_elem_flag_enable(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++;
+ }
+
+ if (edges1 && BLI_array_count(edges1) > 2 &&
+ BM_edge_share_vert(edges1[0], edges1[BLI_array_count(edges1) - 1]))
+ {
+ if (edges2 && BLI_array_count(edges2) > 2 &&
+ BM_edge_share_vert(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 &&
+ BM_edge_share_vert(edges2[0], edges2[BLI_array_count(edges2) - 1]))
+ {
+ edges2 = NULL;
+ }
+
+ /* two unconnected loops, connect the */
+ 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;
+ }
+
+ /* avoid sqrt for comparison */
+ if (len_squared_v3v3(v1->co, v3->co) + len_squared_v3v3(v2->co, v4->co) >
+ len_squared_v3v3(v1->co, v4->co) + len_squared_v3v3(v2->co, v3->co))
+ {
+ BMVert *v;
+ v = v3;
+ v3 = v4;
+ v4 = v;
+ }
+
+ e = BM_edge_create(bm, v1, v3, NULL, TRUE);
+ BMO_elem_flag_enable(bm, e, ELE_NEW);
+ e = BM_edge_create(bm, v2, v4, NULL, TRUE);
+ BMO_elem_flag_enable(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_edge_create(bm, v1, v2, NULL, TRUE);
+ BMO_elem_flag_enable(bm, e, ELE_NEW);
+ }
+ }
+
+ BMO_slot_from_flag(bm, op, "edgeout", ELE_NEW, BM_EDGE);
+
+ BLI_array_free(edges1);
+ BLI_array_free(edges2);
+}
+
+/* this is essentially new fke */
+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 passe */
+ BMO_ITER(h, &oiter, bm, op, "geom", BM_VERT|BM_EDGE|BM_FACE) {
+ switch (h->htype) {
+ case BM_VERT: totv++; break;
+ case BM_EDGE: tote++; break;
+ case BM_FACE: totf++; break;
+ }
+
+ BMO_elem_flag_enable(bm, (BMElemF *)h, ELE_NEW);
+ }
+
+ /* --- Support for Special Case ---
+ * where there is a contiguous edge ring with one isolated vertex.
+ *
+ * This example shows 2 edges created from 3 verts
+ * with 1 free standing vertex. Dotted lines denote the 2 edges that are created.
+ *
+ * note that this works for any sided shape.
+ *
+ * +--------+
+ * | .
+ * | .
+ * | .
+ * | .
+ * +........+ <-- starts out free standing.
+ *
+ */
+
+ /* Here we check for consistancy and create 2 edges */
+ if (totf == 0 && totv >= 4 && totv == tote + 2) {
+ /* find a free standing vertex and 2 endpoint verts */
+ BMVert *v_free = NULL, *v_a = NULL, *v_b = NULL;
+ int ok = TRUE;
+
+
+ BMO_ITER(v, &oiter, bm, op, "geom", BM_VERT) {
+ /* count how many flagged edges this vertex uses */
+ int tot_edges = 0;
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
+ if (BMO_elem_flag_test(bm, e, ELE_NEW)) {
+ tot_edges++;
+ if (tot_edges > 2) {
+ break;
+ }
+ }
+ }
+
+ if (tot_edges == 0) {
+ /* only accept 1 free vert */
+ if (v_free == NULL) v_free = v;
+ else ok = FALSE; /* only ever want one of these */
+ }
+ else if (tot_edges == 1) {
+ if (v_a == NULL) v_a = v;
+ else if (v_b == NULL) v_b = v;
+ else ok = FALSE; /* only ever want 2 of these */
+ }
+ else if (tot_edges == 2) {
+ /* do nothing, regular case */
+ }
+ else {
+ ok = FALSE; /* if a vertex has 3+ edge users then cancel - this is only simple cases */
+ }
+
+ if (ok == FALSE) {
+ break;
+ }
+ }
+
+ if (ok == TRUE && v_free && v_a && v_b) {
+ e = BM_edge_create(bm, v_free, v_a, NULL, TRUE);
+ BMO_elem_flag_enable(bm, e, ELE_NEW);
+
+ e = BM_edge_create(bm, v_free, v_b, NULL, TRUE);
+ BMO_elem_flag_enable(bm, e, ELE_NEW);
+ }
+ }
+ /* --- end special case support, continue as normal --- */
+
+
+ /* possible bug?, selecting 2 triangles and pressing F will make a quad rather then joining them,
+ * perhaps this should be looked into? - campbell */
+
+ /* call edgenet create */
+ /* call edgenet prepare op so additional face creation cases wor */
+ BMO_op_initf(bm, &op2, "edgenet_prepare edges=%fe", ELE_NEW);
+ BMO_op_exec(bm, &op2);
+ BMO_slot_buffer_flag_enable(bm, &op2, "edgeout", ELE_NEW, BM_EDGE);
+ BMO_op_finish(bm, &op2);
+
+ BMO_op_initf(bm, &op2, "edgenet_fill edges=%fe", ELE_NEW);
+ BMO_op_exec(bm, &op2);
+
+ /* return if edge net create did somethin */
+ if (BMO_slot_buf_count(bm, &op2, "faceout")) {
+ BMO_slot_copy(&op2, op, "faceout", "faceout");
+ BMO_op_finish(bm, &op2);
+ return;
+ }
+
+ BMO_op_finish(bm, &op2);
+
+ /* now call dissolve face */
+ BMO_op_initf(bm, &op2, "dissolvefaces faces=%ff", ELE_NEW);
+ BMO_op_exec(bm, &op2);
+
+ /* if we dissolved anything, then return */
+ if (BMO_slot_buf_count(bm, &op2, "regionout")) {
+ BMO_slot_copy(&op2, op, "regionout", "faceout");
+ BMO_op_finish(bm, &op2);
+ return;
+ }
+
+ BMO_op_finish(bm, &op2);
+
+ /* now, count how many verts we hav */
+ amount = 0;
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMO_elem_flag_test(bm, v, ELE_NEW)) {
+ verts[amount] = v;
+ amount++;
+
+ if (amount > 4) break;
+ }
+ }
+
+ if (amount == 2) {
+ /* create edg */
+ e = BM_edge_create(bm, verts[0], verts[1], NULL, TRUE);
+ BMO_elem_flag_enable(bm, e, ELE_OUT);
+ }
+ else if (amount == 3) {
+ /* create triangl */
+ BM_face_create_quad_tri(bm, verts[0], verts[1], verts[2], NULL, NULL, TRUE);
+ }
+ else if (amount == 4) {
+ f = NULL;
+
+ /* the order of vertices can be anything, 6 cases to check */
+ if (is_quad_convex_v3(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co)) {
+ f = BM_face_create_quad_tri(bm, verts[0], verts[1], verts[2], verts[3], NULL, TRUE);
+ }
+ else if (is_quad_convex_v3(verts[0]->co, verts[2]->co, verts[3]->co, verts[1]->co)) {
+ f = BM_face_create_quad_tri(bm, verts[0], verts[2], verts[3], verts[1], NULL, TRUE);
+ }
+ else if (is_quad_convex_v3(verts[0]->co, verts[2]->co, verts[1]->co, verts[3]->co)) {
+ f = BM_face_create_quad_tri(bm, verts[0], verts[2], verts[1], verts[3], NULL, TRUE);
+ }
+ else if (is_quad_convex_v3(verts[0]->co, verts[1]->co, verts[3]->co, verts[2]->co)) {
+ f = BM_face_create_quad_tri(bm, verts[0], verts[1], verts[3], verts[2], NULL, TRUE);
+ }
+ else if (is_quad_convex_v3(verts[0]->co, verts[3]->co, verts[2]->co, verts[1]->co)) {
+ f = BM_face_create_quad_tri(bm, verts[0], verts[3], verts[2], verts[1], NULL, TRUE);
+ }
+ else if (is_quad_convex_v3(verts[0]->co, verts[3]->co, verts[1]->co, verts[2]->co)) {
+ f = BM_face_create_quad_tri(bm, verts[0], verts[3], verts[1], verts[2], NULL, TRUE);
+ }
+ else {
+ printf("cannot find nice quad from concave set of vertices\n");
+ }
+
+ if (f) BMO_elem_flag_enable(bm, f, ELE_OUT);
+ }
+}
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
new file mode 100644
index 00000000000..05aead466d1
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -0,0 +1,559 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_array.h"
+#include "BLI_math.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include "bmesh_operators_private.h" /* own include */
+
+#define FACE_MARK 1
+#define FACE_ORIG 2
+#define FACE_NEW 4
+#define EDGE_MARK 1
+
+#define VERT_MARK 1
+
+static int UNUSED_FUNCTION(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 regio */
+
+ BMW_init(&regwalker, bm, BMW_ISLAND,
+ BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, FACE_MARK,
+ BMW_NIL_LAY);
+ f2 = BMW_begin(&regwalker, f);
+ for ( ; f2; f2 = BMW_step(&regwalker)) {
+ l2 = BM_iter_new(&liter2, bm, BM_LOOPS_OF_FACE, f2);
+ for ( ; l2; l2 = BM_iter_step(&liter2)) {
+ l3 = bmesh_radial_nextloop(l2);
+ if ( BMO_elem_flag_test(bm, l3->f, FACE_MARK) !=
+ BMO_elem_flag_test(bm, l2->f, FACE_MARK))
+ {
+ if (!BMO_elem_flag_test(bm, l2->e, EDGE_MARK)) {
+ return FALSE;
+ }
+ }
+ }
+ }
+ BMW_end(&regwalker);
+
+ return TRUE;
+}
+
+void dissolvefaces_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter oiter;
+ BMFace *f, *f2 /* , *nf = NULL */;
+ BLI_array_declare(faces);
+ BLI_array_declare(regions);
+ BMFace ***regions = NULL;
+ BMFace **faces = NULL;
+ BMWalker regwalker;
+ int i;
+
+ int use_verts = BMO_slot_int_get(op, "use_verts");
+
+ if (use_verts) {
+ /* tag verts that start out with only 2 edges,
+ * don't remove these later */
+ BMIter viter;
+ BMVert *v;
+
+ BM_ITER(v, &viter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_vert_edge_count(v) == 2) {
+ BMO_elem_flag_disable(bm, v, VERT_MARK);
+ }
+ else {
+ BMO_elem_flag_enable(bm, v, VERT_MARK);
+ }
+ }
+ }
+
+ BMO_slot_buffer_flag_enable(bm, op, "faces", FACE_MARK, BM_FACE);
+
+ /* collect region */
+ BMO_ITER(f, &oiter, bm, op, "faces", BM_FACE) {
+ if (!BMO_elem_flag_test(bm, f, FACE_MARK)) continue;
+
+ BLI_array_empty(faces);
+ faces = NULL; /* forces different allocatio */
+
+ /* yay, walk */
+ BMW_init(&regwalker, bm, BMW_ISLAND,
+ BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, FACE_MARK,
+ BMW_NIL_LAY);
+
+ f2 = BMW_begin(&regwalker, f);
+ for ( ; f2; f2 = BMW_step(&regwalker)) {
+ BLI_array_append(faces, f2);
+ }
+ BMW_end(&regwalker);
+
+ for (i = 0; i < BLI_array_count(faces); i++) {
+ f2 = faces[i];
+ BMO_elem_flag_disable(bm, f2, FACE_MARK);
+ BMO_elem_flag_enable(bm, f2, FACE_ORIG);
+ }
+
+ if (BMO_error_occurred(bm)) {
+ BMO_error_clear(bm);
+ BMO_error_raise(bm, op, BMERR_DISSOLVEFACES_FAILED, NULL);
+ goto cleanup;
+ }
+
+ BLI_array_append(faces, NULL);
+ BLI_array_append(regions, faces);
+ }
+
+ for (i = 0; i < BLI_array_count(regions); i++) {
+ int tot = 0;
+
+ faces = regions[i];
+ if (!faces[0]) {
+ BMO_error_raise(bm, op, BMERR_DISSOLVEFACES_FAILED,
+ "Could not find boundary of dissolve region");
+ goto cleanup;
+ }
+
+ while (faces[tot])
+ tot++;
+
+ f = BM_faces_join(bm, faces, tot);
+ if (!f) {
+ BMO_error_raise(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_elem_flag_disable(bm, f, FACE_ORIG);
+ BMO_elem_flag_enable(bm, f, FACE_NEW);
+
+ }
+
+ BMO_op_callf(bm, "del geom=%ff context=%d", FACE_ORIG, DEL_FACES);
+
+
+ if (use_verts) {
+ BMIter viter;
+ BMVert *v;
+
+ BM_ITER(v, &viter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ if (BM_vert_edge_count(v) == 2) {
+ BM_vert_collapse_edges(bm, v->e, v);
+ }
+ }
+ }
+ }
+
+ if (BMO_error_occurred(bm)) goto cleanup;
+
+ BMO_slot_from_flag(bm, op, "regionout", FACE_NEW, BM_FACE);
+
+cleanup:
+ /* free/cleanu */
+ 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 vertice */
+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_face_count(e) == 2) {
+ BMO_elem_flag_enable(bm, e->v1, VERT_MARK);
+ BMO_elem_flag_enable(bm, e->v2, VERT_MARK);
+
+ BM_faces_join_pair(bm, e->l->f,
+ e->l->radial_next->f,
+ e);
+ }
+ }
+
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMO_elem_flag_test(bm, v, VERT_MARK) && BM_vert_edge_count(v) == 2) {
+ BLI_array_append(verts, v);
+ }
+ }
+
+ /* clean up extreneous 2-valence vertice */
+ for (i = 0; i < BLI_array_count(verts); i++) {
+ if (verts[i]->e) {
+ BM_vert_collapse_edges(bm, verts[i]->e, verts[i]);
+ }
+ }
+
+ BLI_array_free(verts);
+
+ //BMO_op_initf(bm, &fop, "dissolvefaces faces=%ff", FACE_MARK);
+ //BMO_op_exec(bm, &fop);
+
+ //BMO_slot_copy(op, &fop, "regionout", "regionout");
+
+ //BMO_op_finish(bm, &fop);
+}
+
+
+void dissolveedges_exec(BMesh *bm, BMOperator *op)
+{
+ /* might want to make this an option or mode - campbell */
+
+ /* BMOperator fop; */
+ BMOIter eiter;
+ BMEdge *e;
+
+ BMIter viter;
+ BMVert *v;
+
+ int use_verts = BMO_slot_int_get(op, "use_verts");
+
+ if (use_verts) {
+ BM_ITER(v, &viter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_vert_edge_count(v) == 2) {
+ BMO_elem_flag_disable(bm, v, VERT_MARK);
+ }
+ else {
+ BMO_elem_flag_enable(bm, v, VERT_MARK);
+ }
+ }
+ }
+
+ BMO_ITER(e, &eiter, bm, op, "edges", BM_EDGE) {
+ const int edge_face_count = BM_edge_face_count(e);
+ if (edge_face_count == 2) {
+
+ /* join faces */
+ BM_faces_join_pair(bm, e->l->f,
+ e->l->radial_next->f,
+ e);
+ }
+ }
+
+ if (use_verts) {
+ BM_ITER(v, &viter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ if (BM_vert_edge_count(v) == 2) {
+ BM_vert_collapse_edges(bm, v->e, v);
+ }
+ }
+ }
+ }
+}
+
+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 = BM_iter_new(&iter, bm, BM_FACES_OF_VERT, v);
+ for ( ; f; f = BM_iter_step(&iter)) {
+ l = BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for ( ; l; l = BM_iter_step(&liter)) {
+ if (!BMO_elem_flag_test(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 region */
+ found = FALSE;
+ e = BM_iter_new(&iter2, bm, BM_EDGES_OF_VERT, l->v);
+ for ( ; e; e = BM_iter_step(&iter2)) {
+ if (BM_edge_face_count(e) == 1) {
+ found = TRUE;
+ }
+ f2 = BM_iter_new(&iter3, bm, BM_FACES_OF_EDGE, e);
+ for ( ; f2; f2 = BM_iter_step(&iter3)) {
+ if (!BMO_elem_flag_test(bm, f2, FACE_MARK)) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found == TRUE) {
+ break;
+ }
+ }
+ if (found == FALSE) {
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+void dissolveverts_exec(BMesh *bm, BMOperator *op)
+{
+ BMOpSlot *vinput;
+ BMIter iter, fiter;
+ BMVert *v;
+ BMFace *f;
+ /* int i; */
+
+ vinput = BMO_slot_get(op, "verts");
+ BMO_slot_buffer_flag_enable(bm, op, "verts", VERT_MARK, BM_VERT);
+
+ for (v = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v = BM_iter_step(&iter)) {
+ if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ /* check if it's a two-valence ver */
+ if (BM_vert_edge_count(v) == 2) {
+
+ /* collapse the ver */
+ BM_vert_collapse_faces(bm, v->e, v, 1.0f, TRUE);
+ continue;
+ }
+
+ f = BM_iter_new(&fiter, bm, BM_FACES_OF_VERT, v);
+ for ( ; f; f = BM_iter_step(&fiter)) {
+ BMO_elem_flag_enable(bm, f, FACE_ORIG);
+ BMO_elem_flag_enable(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 = BM_iter_new(&fiter, bm, BM_FACES_OF_VERT, v);
+ for ( ; f; f = BM_iter_step(&fiter)) {
+ if (BMO_elem_flag_test(bm, f, FACE_ORIG)) {
+ BMO_elem_flag_disable(bm, f, FACE_MARK);
+ BMO_elem_flag_disable(bm, f, FACE_ORIG);
+ }
+ }
+ }
+ else {
+ f = BM_iter_new(&fiter, bm, BM_FACES_OF_VERT, v);
+ for ( ; f; f = BM_iter_step(&fiter)) {
+ BMO_elem_flag_disable(bm, f, FACE_ORIG);
+ }
+ }
+ }
+ }
+
+ BMO_op_callf(bm, "dissolvefaces faces=%ff", FACE_MARK);
+ if (BMO_error_occurred(bm)) {
+ const char *msg;
+
+ BMO_error_get(bm, &msg, NULL);
+ BMO_error_clear(bm);
+ BMO_error_raise(bm, op, BMERR_DISSOLVEVERTS_FAILED, msg);
+ }
+
+ /* clean up any remainin */
+ for (v = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v = BM_iter_step(&iter)) {
+ if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ if (!BM_vert_dissolve(bm, v)) {
+ BMO_error_raise(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
+void dummy_exec(BMesh *bm, BMOperator *op)
+{
+ {
+ /* clean up two-edged face */
+ /* 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 = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, NULL); f; f = BM_iter_step(&iter)) {
+ if (!BM_face_validate(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 = BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, f);
+ fe = l->e;
+ for ( ; l; l = BM_iter_step(&liter)) {
+ f2 = BM_iter_new(&fiter, bm,
+ BM_FACES_OF_EDGE, l->e);
+ for ( ; f2; f2 = BM_iter_step(&fiter)) {
+ if (f2 != f) {
+ BM_faces_join_pair(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 = BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for ( ; l; l = BM_iter_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
+
+/**/
+typedef struct DissolveElemWeight_t {
+ BMHeader *ele;
+ float weight;
+} DissolveElemWeight_t;
+
+static int dissolve_elem_cmp(const void *a1, const void *a2)
+{
+ const struct DissolveElemWeight_t *d1 = a1, *d2 = a2;
+
+ if (d1->weight > d2->weight) return 1;
+ else if (d1->weight < d2->weight) return -1;
+ return 0;
+}
+
+void dissolvelimit_exec(BMesh *bm, BMOperator *op)
+{
+ BMOpSlot *einput = BMO_slot_get(op, "edges");
+ BMOpSlot *vinput = BMO_slot_get(op, "verts");
+ const float angle_max = (float)M_PI / 2.0f;
+ const float angle_limit = minf(angle_max, BMO_slot_float_get(op, "angle_limit"));
+ DissolveElemWeight_t *weight_elems = MEM_mallocN(MAX2(einput->len, vinput->len) *
+ sizeof(DissolveElemWeight_t), __func__);
+ int i, tot_found;
+
+ /* --- first edges --- */
+
+ /* go through and split edge */
+ for (i = 0, tot_found = 0; i < einput->len; i++) {
+ BMEdge *e = ((BMEdge **)einput->data.p)[i];
+ const float angle = BM_edge_face_angle(bm, e);
+
+ if (angle < angle_limit) {
+ weight_elems[i].ele = (BMHeader *)e;
+ weight_elems[i].weight = angle;
+ tot_found++;
+ }
+ else {
+ weight_elems[i].ele = NULL;
+ weight_elems[i].weight = angle_max;
+ }
+ }
+
+ if (tot_found != 0) {
+ qsort(weight_elems, einput->len, sizeof(DissolveElemWeight_t), dissolve_elem_cmp);
+
+ for (i = 0; i < tot_found; i++) {
+ BMEdge *e = (BMEdge *)weight_elems[i].ele;
+ /* check twice because cumulative effect could disolve over angle limit */
+ if (BM_edge_face_angle(bm, e) < angle_limit) {
+ BMFace *nf = BM_faces_join_pair(bm, e->l->f,
+ e->l->radial_next->f,
+ e); /* join faces */
+
+ /* there may be some errors, we dont mind, just move on */
+ if (nf == NULL) {
+ BMO_error_clear(bm);
+ }
+ }
+ }
+ }
+
+ /* --- second verts --- */
+ for (i = 0, tot_found = 0; i < vinput->len; i++) {
+ BMVert *v = ((BMVert **)vinput->data.p)[i];
+ const float angle = BM_vert_edge_angle(bm, v);
+
+ if (angle < angle_limit) {
+ weight_elems[i].ele = (BMHeader *)v;
+ weight_elems[i].weight = angle;
+ tot_found++;
+ }
+ else {
+ weight_elems[i].ele = NULL;
+ weight_elems[i].weight = angle_max;
+ }
+ }
+
+ if (tot_found != 0) {
+ qsort(weight_elems, vinput->len, sizeof(DissolveElemWeight_t), dissolve_elem_cmp);
+
+ for (i = 0; i < tot_found; i++) {
+ BMVert *v = (BMVert *)weight_elems[i].ele;
+ /* check twice because cumulative effect could disolve over angle limit */
+ if (BM_vert_edge_angle(bm, v) < angle_limit) {
+ BM_vert_collapse_edges(bm, v->e, v); /* join edges */
+ }
+ }
+ }
+
+ MEM_freeN(weight_elems);
+}
diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c
new file mode 100644
index 00000000000..2e1c91d920c
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_dupe.c
@@ -0,0 +1,512 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+
+#include "BLI_array.h"
+#include "BLI_math.h"
+
+#include "bmesh.h"
+
+/* local flag define */
+#define DUPE_INPUT 1 /* input from operato */
+#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 verte */
+ target_vertex = BM_vert_create(target_mesh, source_vertex->co, NULL);
+
+ /* Insert new vertex into the vert has */
+ BLI_ghash_insert(vhash, source_vertex, target_vertex);
+
+ /* Copy attribute */
+ BM_elem_attrs_copy(source_mesh, target_mesh, source_vertex, target_vertex);
+
+ /* Set internal op flag */
+ BMO_elem_flag_enable(target_mesh, 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 = BM_iter_new(&fiter, source_mesh, BM_FACES_OF_EDGE, source_edge);
+ face;
+ face = BM_iter_step(&fiter))
+ {
+ if (BMO_elem_flag_test(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 edg */
+ target_edge = BM_edge_create(target_mesh, target_vert1, target_vert2, NULL, FALSE);
+
+ /* add to new/old edge map if necassar */
+ if (rlen < 2) {
+ /* not sure what non-manifold cases of greater then three
+ * radial should do. */
+ BMO_slot_map_ptr_insert(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_elem_attrs_copy(source_mesh, target_mesh, source_edge, target_edge);
+
+ /* Set internal op flags */
+ BMO_elem_flag_enable(target_mesh, 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,
+ BMVert **vtar, BMEdge **edar, GHash *vhash, GHash *ehash)
+{
+ /* BMVert *target_vert1, *target_vert2; */ /* UNUSED */
+ BMLoop *source_loop, *target_loop;
+ BMFace *target_face = NULL;
+ BMIter iter, iter2;
+ int i;
+
+ /* lookup the first and second vert */
+#if 0 /* UNUSED */
+ target_vert1 = BLI_ghash_lookup(vhash, BM_iter_new(&iter, source_mesh, BM_VERTS_OF_FACE, source_face));
+ target_vert2 = BLI_ghash_lookup(vhash, BM_iter_step(&iter));
+#else
+ BM_iter_new(&iter, source_mesh, BM_VERTS_OF_FACE, source_face);
+ BM_iter_step(&iter);
+#endif
+
+ /* lookup edge */
+ for (i = 0, source_loop = BM_iter_new(&iter, source_mesh, BM_LOOPS_OF_FACE, source_face);
+ source_loop;
+ source_loop = BM_iter_step(&iter), i++)
+ {
+ vtar[i] = BLI_ghash_lookup(vhash, source_loop->v);
+ edar[i] = BLI_ghash_lookup(ehash, source_loop->e);
+ }
+
+ /* create new fac */
+ target_face = BM_face_create(target_mesh, vtar, edar, source_face->len, FALSE);
+ BMO_slot_map_ptr_insert(source_mesh, op,
+ "facemap", source_face, target_face);
+ BMO_slot_map_ptr_insert(source_mesh, op,
+ "facemap", target_face, source_face);
+
+ BM_elem_attrs_copy(source_mesh, target_mesh, source_face, target_face);
+
+ /* mark the face for outpu */
+ BMO_elem_flag_enable(target_mesh, target_face, DUPE_NEW);
+
+ /* copy per-loop custom dat */
+ BM_ITER(source_loop, &iter, source_mesh, BM_LOOPS_OF_FACE, source_face) {
+ BM_ITER(target_loop, &iter2, target_mesh, BM_LOOPS_OF_FACE, target_face) {
+ if (BLI_ghash_lookup(vhash, source_loop->v) == target_loop->v) {
+ BM_elem_attrs_copy(source_mesh, target_mesh, source_loop, target_loop);
+ break;
+ }
+ }
+ }
+
+ 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;
+ BMFace *f = NULL;
+
+ BLI_array_declare(vtar);
+ BLI_array_declare(edar);
+ BMVert **vtar = NULL;
+ BMEdge **edar = NULL;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ GHash *vhash;
+ GHash *ehash;
+
+ /* initialize pointer hashe */
+ 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");
+
+ for (v = BM_iter_new(&verts, source, BM_VERTS_OF_MESH, source); v; v = BM_iter_step(&verts)) {
+ if ( BMO_elem_flag_test(source, v, DUPE_INPUT) &&
+ !BMO_elem_flag_test(source, 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_elem_flag_test(source, f, DUPE_INPUT)) {
+ iso = 0;
+ break;
+ }
+ }
+
+ if (iso) {
+ BM_ITER(e, &iter, source, BM_EDGES_OF_VERT, v) {
+ if (BMO_elem_flag_test(source, e, DUPE_INPUT)) {
+ iso = 0;
+ break;
+ }
+ }
+ }
+
+ if (iso) {
+ BMO_slot_map_ptr_insert(source, op, "isovertmap", v, v2);
+ }
+
+ BMO_elem_flag_enable(source, v, DUPE_DONE);
+ }
+ }
+
+ /* now we dupe all the edge */
+ for (e = BM_iter_new(&edges, source, BM_EDGES_OF_MESH, source); e; e = BM_iter_step(&edges)) {
+ if ( BMO_elem_flag_test(source, e, DUPE_INPUT) &&
+ !BMO_elem_flag_test(source, e, DUPE_DONE))
+ {
+ /* make sure that verts are copie */
+ if (!BMO_elem_flag_test(source, e->v1, DUPE_DONE)) {
+ copy_vertex(source, e->v1, target, vhash);
+ BMO_elem_flag_enable(source, e->v1, DUPE_DONE);
+ }
+ if (!BMO_elem_flag_test(source, e->v2, DUPE_DONE)) {
+ copy_vertex(source, e->v2, target, vhash);
+ BMO_elem_flag_enable(source, e->v2, DUPE_DONE);
+ }
+ /* now copy the actual edg */
+ copy_edge(op, source, e, target, vhash, ehash);
+ BMO_elem_flag_enable(source, e, DUPE_DONE);
+ }
+ }
+
+ /* first we dupe all flagged faces and their elements from sourc */
+ for (f = BM_iter_new(&faces, source, BM_FACES_OF_MESH, source); f; f = BM_iter_step(&faces)) {
+ if (BMO_elem_flag_test(source, f, DUPE_INPUT)) {
+ /* vertex pas */
+ for (v = BM_iter_new(&verts, source, BM_VERTS_OF_FACE, f); v; v = BM_iter_step(&verts)) {
+ if (!BMO_elem_flag_test(source, v, DUPE_DONE)) {
+ copy_vertex(source, v, target, vhash);
+ BMO_elem_flag_enable(source, v, DUPE_DONE);
+ }
+ }
+
+ /* edge pas */
+ for (e = BM_iter_new(&edges, source, BM_EDGES_OF_FACE, f); e; e = BM_iter_step(&edges)) {
+ if (!BMO_elem_flag_test(source, e, DUPE_DONE)) {
+ copy_edge(op, source, e, target, vhash, ehash);
+ BMO_elem_flag_enable(source, e, DUPE_DONE);
+ }
+ }
+
+ /* ensure arrays are the right size */
+ BLI_array_empty(vtar);
+ BLI_array_empty(edar);
+
+ BLI_array_growitems(vtar, f->len);
+ BLI_array_growitems(edar, f->len);
+
+ copy_face(op, source, f, target, vtar, edar, vhash, ehash);
+ BMO_elem_flag_enable(source, f, DUPE_DONE);
+ }
+ }
+
+ /* free pointer hashe */
+ BLI_ghash_free(vhash, NULL, NULL);
+ BLI_ghash_free(ehash, NULL, NULL);
+
+ BLI_array_free(vtar); /* free vert pointer array */
+ BLI_array_free(edar); /* free edge pointer array */
+}
+
+/*
+ * 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_slot_ptr_get(op, "dest");
+
+ if (!bm2)
+ bm2 = bm;
+
+ /* flag inpu */
+ BMO_slot_buffer_flag_enable(bm, dupeop, "geom", DUPE_INPUT, BM_ALL);
+
+ /* use the internal copy functio */
+ copy_mesh(dupeop, bm, bm2);
+
+ /* Outpu */
+ /* First copy the input buffers to output buffers - original dat */
+ BMO_slot_copy(dupeop, dupeop, "geom", "origout");
+
+ /* Now alloc the new output buffer */
+ BMO_slot_from_flag(bm, dupeop, "newout", DUPE_NEW, BM_ALL);
+}
+
+#if 0 /* UNUSED */
+/* 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 BMO_dupe_from_flag(BMesh *bm, int etypeflag, const char hflag)
+{
+ BMOperator dupeop;
+
+ BMO_op_init(bm, &dupeop, "dupe");
+ BMO_slot_from_hflag(bm, &dupeop, "geom", hflag, etypeflag);
+
+ BMO_op_exec(bm, &dupeop);
+ BMO_op_finish(bm, &dupeop);
+}
+#endif
+
+/*
+ * 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-operator */
+ BMO_op_init(bm, &dupeop, "dupe");
+ BMO_op_init(bm, &delop, "del");
+
+ BMO_slot_copy(splitop, &dupeop, "geom", "geom");
+ BMO_op_exec(bm, &dupeop);
+
+ BMO_slot_buffer_flag_enable(bm, splitop, "geom", SPLIT_INPUT, BM_ALL);
+
+ /* make sure to remove edges and verts we don't need */
+ for (e = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); e; e = BM_iter_step(&iter)) {
+ found = 0;
+ f = BM_iter_new(&iter2, bm, BM_FACES_OF_EDGE, e);
+ for ( ; f; f = BM_iter_step(&iter2)) {
+ if (!BMO_elem_flag_test(bm, f, SPLIT_INPUT)) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) BMO_elem_flag_enable(bm, e, SPLIT_INPUT);
+ }
+
+ for (v = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v = BM_iter_step(&iter)) {
+ found = 0;
+ e = BM_iter_new(&iter2, bm, BM_EDGES_OF_VERT, v);
+ for ( ; e; e = BM_iter_step(&iter2)) {
+ if (!BMO_elem_flag_test(bm, e, SPLIT_INPUT)) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) BMO_elem_flag_enable(bm, v, SPLIT_INPUT);
+
+ }
+
+ /* connect outputs of dupe to delete, exluding keep geometr */
+ BMO_slot_int_set(&delop, "context", DEL_FACES);
+ BMO_slot_from_flag(bm, &delop, "geom", SPLIT_INPUT, BM_ALL);
+
+ BMO_op_exec(bm, &delop);
+
+ /* now we make our outputs by copying the dupe output */
+ BMO_slot_copy(&dupeop, splitop, "newout", "geomout");
+ BMO_slot_copy(&dupeop, splitop, "boundarymap",
+ "boundarymap");
+ BMO_slot_copy(&dupeop, splitop, "isovertmap",
+ "isovertmap");
+
+ /* cleanu */
+ BMO_op_finish(bm, &delop);
+ BMO_op_finish(bm, &dupeop);
+}
+
+
+void delop_exec(BMesh *bm, BMOperator *op)
+{
+#define DEL_INPUT 1
+
+ BMOperator *delop = op;
+
+ /* Mark Buffer */
+ BMO_slot_buffer_flag_enable(bm, delop, "geom", DEL_INPUT, BM_ALL);
+
+ BMO_remove_tagged_context(bm, DEL_INPUT, BMO_slot_int_get(op, "context"));
+
+#undef DEL_INPUT
+}
+
+/*
+ * Spin Operator
+ *
+ * Extrude or duplicate geometry a number of times,
+ * rotating and possibly translating after each step
+ */
+
+void spinop_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator dupop, extop;
+ float cent[3], dvec[3];
+ float axis[3] = {0.0f, 0.0f, 1.0f};
+ float q[4];
+ float rmat[3][3];
+ float phi, si;
+ int steps, dupli, a, usedvec;
+
+ BMO_slot_vec_get(op, "cent", cent);
+ BMO_slot_vec_get(op, "axis", axis);
+ normalize_v3(axis);
+ BMO_slot_vec_get(op, "dvec", dvec);
+ usedvec = !is_zero_v3(dvec);
+ steps = BMO_slot_int_get(op, "steps");
+ phi = BMO_slot_float_get(op, "ang") * (float)M_PI / (360.0f * steps);
+ dupli = BMO_slot_int_get(op, "dupli");
+
+ si = (float)sin(phi);
+ q[0] = (float)cos(phi);
+ q[1] = axis[0]*si;
+ q[2] = axis[1]*si;
+ q[3] = axis[2]*si;
+ quat_to_mat3(rmat, q);
+
+ BMO_slot_copy(op, op, "geom", "lastout");
+ for (a = 0; a < steps; a++) {
+ if (dupli) {
+ BMO_op_initf(bm, &dupop, "dupe geom=%s", op, "lastout");
+ BMO_op_exec(bm, &dupop);
+ BMO_op_callf(bm, "rotate cent=%v mat=%m3 verts=%s",
+ cent, rmat, &dupop, "newout");
+ BMO_slot_copy(&dupop, op, "newout", "lastout");
+ BMO_op_finish(bm, &dupop);
+ }
+ else {
+ BMO_op_initf(bm, &extop, "extrudefaceregion edgefacein=%s",
+ op, "lastout");
+ BMO_op_exec(bm, &extop);
+ BMO_op_callf(bm, "rotate cent=%v mat=%m3 verts=%s",
+ cent, rmat, &extop, "geomout");
+ BMO_slot_copy(&extop, op, "geomout", "lastout");
+ BMO_op_finish(bm, &extop);
+ }
+
+ if (usedvec)
+ BMO_op_callf(bm, "translate vec=%v verts=%s", dvec, op, "lastout");
+ }
+}
diff --git a/source/blender/bmesh/operators/bmo_edgesplit.c b/source/blender/bmesh/operators/bmo_edgesplit.c
new file mode 100644
index 00000000000..7d719e1ddc9
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_edgesplit.c
@@ -0,0 +1,426 @@
+/*
+ * ***** 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): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_array.h"
+
+#include "bmesh.h"
+
+#include "bmesh_operators_private.h" /* own include */
+
+typedef struct EdgeTag {
+ BMVert *newv1, *newv2;
+ BMEdge *newe1, *newe2;
+ int tag;
+} EdgeTag;
+
+/* (EDGE_DEL == FACE_DEL) - this must be the case */
+#define EDGE_DEL 1
+#define EDGE_SEAM 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, BMEdge **edges_tmp)
+{
+ BMIter liter1, liter2;
+ EdgeTag *et;
+ BMFace *f2;
+ BMLoop *l, *l2;
+ BMEdge *e;
+ BMVert *lastv1, *lastv2 /* , *v1, *v2 */ /* UNUSED */;
+ int i;
+
+ /* we do final edge last */
+ lastv1 = verts[f->len - 1];
+ lastv2 = verts[0];
+ /* v1 = verts[0]; */ /* UNUSED */
+ /* v2 = verts[1]; */ /* UNUSED */
+ for (i = 0; i < f->len - 1; i++) {
+ e = BM_edge_create(bm, verts[i], verts[i + 1], NULL, TRUE);
+ if (!e) {
+ return NULL;
+ }
+ edges_tmp[i] = e;
+ }
+
+ edges_tmp[i] = BM_edge_create(bm, lastv1, lastv2, NULL, TRUE);
+
+ f2 = BM_face_create(bm, verts, edges_tmp, f->len, FALSE);
+ if (!f2) {
+ return NULL;
+ }
+
+ BM_elem_attrs_copy(bm, bm, f, f2);
+
+ l = BM_iter_new(&liter1, bm, BM_LOOPS_OF_FACE, f);
+ l2 = BM_iter_new(&liter2, bm, BM_LOOPS_OF_FACE, f2);
+ for ( ; l && l2; l = BM_iter_step(&liter1), l2 = BM_iter_step(&liter2)) {
+ BM_elem_attrs_copy(bm, bm, l, l2);
+ if (l->e != l2->e) {
+ /* set up data for figuring out the two sides of
+ * the split */
+
+ /* set edges index as dirty after running all */
+ BM_elem_index_set(l2->e, BM_elem_index_get(l->e)); /* set_dirty! */
+ et = &etags[BM_elem_index_get(l->e)];
+
+ if (!et->newe1) {
+ et->newe1 = l2->e;
+ }
+ else if (!et->newe2) {
+ et->newe2 = l2->e;
+ }
+ else {
+ /* Only two new edges should be created from each original edge
+ * for edge split operation */
+
+ //BLI_assert(et->newe1 == l2->e || et->newe2 == l2->e);
+ et->newe2 = l2->e;
+ }
+
+ if (BMO_elem_flag_test(bm, l->e, EDGE_SEAM)) {
+ BMO_elem_flag_enable(bm, l2->e, EDGE_SEAM);
+ }
+
+ BM_elem_attrs_copy(bm, bm, l->e, l2->e);
+ }
+
+ BMO_elem_flag_enable(bm, l->e, EDGE_MARK);
+ BMO_elem_flag_enable(bm, l2->e, EDGE_MARK);
+ }
+
+ return f2;
+}
+
+static void tag_out_edges(BMesh *bm, EdgeTag *etags, BMOperator *UNUSED(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_elem_flag_test(bm, e, EDGE_SEAM))
+ continue;
+
+ et = &etags[BM_elem_index_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 ? l->next->v : l->v;
+
+ while (1) {
+ et = &etags[BM_elem_index_get(l->e)];
+ if (et->newe1 == l->e) {
+ if (et->newe1) {
+ BMO_elem_flag_enable(bm, et->newe1, EDGE_RET1);
+ BMO_elem_flag_disable(bm, et->newe1, EDGE_SEAM);
+ }
+ if (et->newe2) {
+ BMO_elem_flag_enable(bm, et->newe2, EDGE_RET2);
+ BMO_elem_flag_disable(bm, et->newe2, EDGE_SEAM);
+ }
+ }
+ else {
+ if (et->newe1) {
+ BMO_elem_flag_enable(bm, et->newe1, EDGE_RET2);
+ BMO_elem_flag_disable(bm, et->newe1, EDGE_SEAM);
+ }
+ if (et->newe2) {
+ BMO_elem_flag_enable(bm, et->newe2, EDGE_RET1);
+ BMO_elem_flag_disable(bm, et->newe2, EDGE_SEAM);
+ }
+ }
+
+ /* If the original edge was non-manifold edges, then it is
+ * possible l->e is not et->newe1 or et->newe2. So always clear
+ * the flag on l->e as well, to prevent infinite looping. */
+ BMO_elem_flag_disable(bm, l->e, EDGE_SEAM);
+
+ startl = l;
+ do {
+ l = BM_face_other_loop(l->e, l->f, v);
+ if (l == startl || BM_edge_face_count(l->e) != 2) {
+ break;
+ }
+ l = l->radial_next;
+ } while (l != startl && !BMO_elem_flag_test(bm, l->e, EDGE_SEAM));
+
+ if (l == startl || !BMO_elem_flag_test(bm, l->e, EDGE_SEAM)) {
+ break;
+ }
+
+ v = (l->v == v) ? l->next->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;
+ BMVert *v, *v2, **verts = NULL;
+ BLI_array_declare(verts);
+ BMEdge **edges_tmp = NULL;
+ BLI_array_declare(edges_tmp);
+ int i, j;
+
+ BMO_slot_buffer_flag_enable(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_elem_flag_test(bm, e2, EDGE_SEAM)) {
+ break;
+ }
+ }
+ if (e2) {
+ break;
+ }
+ }
+
+ if (!e2) {
+ BMO_elem_flag_disable(bm, e, EDGE_SEAM);
+ }
+ }
+
+ etags = MEM_callocN(sizeof(EdgeTag)*bm->totedge, "EdgeTag");
+
+ BM_mesh_elem_index_ensure(bm, BM_EDGE);
+
+#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_elem_flag_test(bm, f, FACE_NEW)) {
+ continue;
+ }
+
+ BLI_array_empty(verts);
+ BLI_array_growitems(verts, f->len);
+ memset(verts, 0, sizeof(BMVert *) * f->len);
+
+ /* this is passed onto remake_face() so it doesnt need to allocate
+ * a new array on each call. */
+ BLI_array_empty(edges_tmp);
+ BLI_array_growitems(edges_tmp, f->len);
+
+ i = 0;
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ if (!BMO_elem_flag_test(bm, l->e, EDGE_SEAM)) {
+ if (!verts[i]) {
+
+ et = &etags[BM_elem_index_get(l->e)];
+ if (ETV(et, l->v, l)) {
+ verts[i] = ETV(et, l->v, l);
+ }
+ else
+ {
+ verts[i] = l->v;
+ }
+ }
+ i++;
+ continue;
+ }
+
+ nextl = l->next;
+ prevl = l->prev;
+
+ for (j = 0; j < 2; j++) {
+ /* correct as long as i & j dont change during the loop */
+ const int fv_index = j ? (i + 1) % f->len : i; /* face vert index */
+ l2 = j ? nextl : prevl;
+ v = j ? l2->v : l->v;
+
+ if (BMO_elem_flag_test(bm, l2->e, EDGE_SEAM)) {
+ if (verts[fv_index] == NULL) {
+ /* make unique vert here for this face only */
+ v2 = BM_vert_create(bm, v->co, v);
+ verts[fv_index] = v2;
+ }
+ else {
+ v2 = verts[fv_index];
+ }
+ }
+ 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 fa */
+ l3 = l2;
+ do {
+ if (BM_edge_face_count(l3->e) != 2) {
+ /* if we hit a boundary edge, tag
+ * l3 as null so we know to disconnect
+ * it */
+ if (BM_edge_face_count(l3->e) == 1) {
+ l3 = NULL;
+ }
+ break;
+ }
+
+ l3 = l3->radial_next;
+ l3 = BM_face_other_loop(l3->e, l3->f, v);
+ } while (l3 != l2 && !BMO_elem_flag_test(bm, l3->e, EDGE_SEAM));
+
+ if (l3 == NULL || (BMO_elem_flag_test(bm, l3->e, EDGE_SEAM) && l3->e != l->e)) {
+ et = &etags[BM_elem_index_get(l2->e)];
+ if (ETV(et, v, l2) == NULL) {
+ v2 = BM_vert_create(bm, v->co, v);
+
+ l3 = l2;
+ do {
+ SETETV(et, v, l3, v2);
+ if (BM_edge_face_count(l3->e) != 2) {
+ break;
+ }
+
+ l3 = l3->radial_next;
+ l3 = BM_face_other_loop(l3->e, l3->f, v);
+
+ et = &etags[BM_elem_index_get(l3->e)];
+ } while (l3 != l2 && !BMO_elem_flag_test(bm, l3->e, EDGE_SEAM));
+ }
+ else {
+ v2 = ETV(et, v, l2);
+ }
+
+ verts[fv_index] = v2;
+ }
+ else {
+ verts[fv_index] = v;
+ }
+ }
+ }
+
+ i++;
+ }
+
+ /* debugging code, quick way to find the face/vert combination
+ * which is failing assuming quads start planer - campbell */
+#if 0
+ if (f->len == 4) {
+ float no1[3];
+ float no2[3];
+ float angle_error;
+ printf(" ** found QUAD\n");
+ normal_tri_v3(no1, verts[0]->co, verts[1]->co, verts[2]->co);
+ normal_tri_v3(no2, verts[0]->co, verts[2]->co, verts[3]->co);
+ if ((angle_error = angle_v3v3(no1, no2)) > 0.05) {
+ printf(" ERROR %.4f\n", angle_error);
+ print_v3("0", verts[0]->co);
+ print_v3("1", verts[1]->co);
+ print_v3("2", verts[2]->co);
+ print_v3("3", verts[3]->co);
+
+ }
+ }
+ else {
+ printf(" ** fount %d len face\n", f->len);
+ }
+#endif
+
+ f2 = remake_face(bm, etags, f, verts, edges_tmp);
+ if (!f2) {
+ continue;
+ }
+
+ BMO_elem_flag_enable(bm, f, FACE_DEL);
+ BMO_elem_flag_enable(bm, f2, FACE_NEW);
+ }
+
+ /* remake_face() sets invalid indecies,
+ * likely these will be corrected on operator exit anyway */
+ bm->elem_index_dirty &= ~BM_EDGE;
+
+ /* cant call the operator because 'tag_out_edges'
+ * relies on original index values, from before editing geometry */
+
+#if 0
+ BMO_op_callf(bm, "del geom=%ff context=%i", FACE_DEL, DEL_ONLYFACES);
+#else
+ BMO_remove_tagged_context(bm, FACE_DEL, DEL_ONLYFACES);
+#endif
+
+ /* 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_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (!e->l) {
+ BMO_elem_flag_enable(bm, e, EDGE_DEL);
+ }
+ }
+ }
+
+#if 0
+ BMO_op_callf(bm, "del geom=%fe context=%i", EDGE_DEL, DEL_EDGES);
+#else
+ BMO_remove_tagged_context(bm, EDGE_DEL, DEL_EDGES);
+#endif
+
+ tag_out_edges(bm, etags, op);
+ BMO_slot_from_flag(bm, op, "edgeout1", EDGE_RET1, BM_EDGE);
+ BMO_slot_from_flag(bm, op, "edgeout2", EDGE_RET2, BM_EDGE);
+
+ BLI_array_free(verts);
+ BLI_array_free(edges_tmp);
+ if (etags) MEM_freeN(etags);
+}
+
+#undef ETV
+#undef SETETV
diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c
new file mode 100644
index 00000000000..b6a87e604ec
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_extrude.c
@@ -0,0 +1,591 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_array.h"
+
+#include "bmesh.h"
+
+#include "bmesh_operators_private.h" /* own include */
+
+#define EXT_INPUT 1
+#define EXT_KEEP 2
+#define EXT_DEL 4
+
+#define VERT_MARK 1
+#define EDGE_MARK 1
+#define FACE_MARK 1
+#define VERT_NONMAN 2
+#define EDGE_NONMAN 2
+
+void bmesh_extrude_face_indiv_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMIter liter, liter2;
+ BMFace *f, *f2, *f3;
+ BMLoop *l, *l2, *l3, *l4, *l_tmp;
+ 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_vert_create(bm, l->v->co, l->v);
+
+ if (lastv) {
+ e = BM_edge_create(bm, lastv, v, l->e, FALSE);
+ edges[i++] = e;
+ }
+
+ lastv = v;
+ laste = l->e;
+ if (!firstv) firstv = v;
+ }
+
+ BLI_array_growone(edges);
+ e = BM_edge_create(bm, v, firstv, laste, FALSE);
+ edges[i++] = e;
+
+ BMO_elem_flag_enable(bm, f, EXT_DEL);
+
+ f2 = BM_face_create_ngon(bm, firstv, BM_edge_other_vert(edges[0], firstv), edges, f->len, FALSE);
+ if (!f2) {
+ BMO_error_raise(bm, op, BMERR_MESH_ERROR, "Extrude failed; could not create face");
+ BLI_array_free(edges);
+ return;
+ }
+
+ BMO_elem_flag_enable(bm, f2, EXT_KEEP);
+ BM_elem_attrs_copy(bm, bm, f, f2);
+
+ l2 = BM_iter_new(&liter2, bm, BM_LOOPS_OF_FACE, f2);
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ BM_elem_attrs_copy(bm, bm, l, l2);
+
+ l3 = l->next;
+ l4 = l2->next;
+
+ f3 = BM_face_create_quad_tri(bm, l3->v, l4->v, l2->v, l->v, f, FALSE);
+
+ l_tmp = BM_FACE_FIRST_LOOP(f3);
+
+ BM_elem_attrs_copy(bm, bm, l->next, l_tmp); l_tmp = l_tmp->next;
+ BM_elem_attrs_copy(bm, bm, l->next, l_tmp); l_tmp = l_tmp->next;
+ BM_elem_attrs_copy(bm, bm, l, l_tmp); l_tmp = l_tmp->next;
+ BM_elem_attrs_copy(bm, bm, l, l_tmp);
+
+ l2 = BM_iter_step(&liter2);
+ }
+ }
+
+ BLI_array_free(edges);
+
+ BMO_op_callf(bm, "del geom=%ff context=%d", EXT_DEL, DEL_ONLYFACES);
+ BMO_slot_from_flag(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_elem_flag_enable(bm, e, EXT_INPUT);
+ BMO_elem_flag_enable(bm, e->v1, EXT_INPUT);
+ BMO_elem_flag_enable(bm, e->v2, EXT_INPUT);
+ }
+
+ BMO_op_initf(bm, &dupeop, "dupe geom=%fve", EXT_INPUT);
+ BMO_op_exec(bm, &dupeop);
+
+ e = BMO_iter_new(&siter, bm, &dupeop, "boundarymap", 0);
+ for ( ; e; e = BMO_iter_step(&siter)) {
+ e2 = BMO_iter_map_value(&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_face_create_quad_tri(bm, v1, v2, v3, v4, NULL, FALSE);
+
+ if (BMO_elem_flag_test(bm, e, EXT_INPUT))
+ e = e2;
+
+ BMO_elem_flag_enable(bm, f, EXT_KEEP);
+ BMO_elem_flag_enable(bm, e, EXT_KEEP);
+ BMO_elem_flag_enable(bm, e->v1, EXT_KEEP);
+ BMO_elem_flag_enable(bm, e->v2, EXT_KEEP);
+
+ }
+
+ BMO_op_finish(bm, &dupeop);
+
+ BMO_slot_from_flag(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_iter_new(&siter, bm, op, "verts", BM_VERT);
+ for ( ; v; v = BMO_iter_step(&siter)) {
+ dupev = BM_vert_create(bm, v->co, v);
+
+ e = BM_edge_create(bm, v, dupev, NULL, FALSE);
+
+ BMO_elem_flag_enable(bm, e, EXT_KEEP);
+ BMO_elem_flag_enable(bm, dupev, EXT_KEEP);
+ }
+
+ BMO_slot_from_flag(bm, op, "vertout", EXT_KEEP, BM_VERT);
+ BMO_slot_from_flag(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;
+ BMLoop *l, *l2;
+ BMVert *verts[4], *v, *v2;
+ BMFace *f;
+ int rlen, found, fwd, delorig = 0;
+
+ /* initialize our sub-operators */
+ BMO_op_init(bm, &dupeop, "dupe");
+
+ BMO_slot_buffer_flag_enable(bm, op, "edgefacein", EXT_INPUT, BM_EDGE|BM_FACE);
+
+ /* if one flagged face is bordered by an unflagged face, then we delete
+ * original geometry unless caller explicitly asked to keep it. */
+ if (!BMO_slot_int_get(op, "alwayskeeporig")) {
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BMO_elem_flag_test(bm, e, EXT_INPUT)) continue;
+
+ found = 0;
+ f = BM_iter_new(&fiter, bm, BM_FACES_OF_EDGE, e);
+ for (rlen = 0; f; f = BM_iter_step(&fiter), rlen++) {
+ if (!BMO_elem_flag_test(bm, f, EXT_INPUT)) {
+ found = 1;
+ delorig = 1;
+ break;
+ }
+ }
+
+ if (!found && (rlen > 1)) BMO_elem_flag_enable(bm, e, EXT_DEL);
+ }
+ }
+
+ /* calculate verts to delet */
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ found = 0;
+
+ BM_ITER(e, &viter, bm, BM_EDGES_OF_VERT, v) {
+ if (!BMO_elem_flag_test(bm, e, EXT_INPUT) || !BMO_elem_flag_test(bm, e, EXT_DEL)) {
+ found = 1;
+ break;
+ }
+ }
+
+ BM_ITER(f, &viter, bm, BM_FACES_OF_VERT, v) {
+ if (!BMO_elem_flag_test(bm, f, EXT_INPUT)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ BMO_elem_flag_enable(bm, v, EXT_DEL);
+ }
+ }
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (BMO_elem_flag_test(bm, f, EXT_INPUT))
+ BMO_elem_flag_enable(bm, f, EXT_DEL);
+ }
+
+ if (delorig) {
+ BMO_op_initf(bm, &delop, "del geom=%fvef context=%d",
+ EXT_DEL, DEL_ONLYTAGGED);
+ }
+
+ BMO_slot_copy(op, &dupeop, "edgefacein", "geom");
+ BMO_op_exec(bm, &dupeop);
+
+ if (bm->act_face && BMO_elem_flag_test(bm, bm->act_face, EXT_INPUT))
+ bm->act_face = BMO_slot_map_ptr_get(bm, &dupeop, "facemap", bm->act_face);
+
+ if (delorig) BMO_op_exec(bm, &delop);
+
+ /* if not delorig, reverse loops of original face */
+ if (!delorig) {
+ for (f = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, NULL); f; f = BM_iter_step(&iter)) {
+ if (BMO_elem_flag_test(bm, f, EXT_INPUT)) {
+ BM_face_normal_flip(bm, f);
+ }
+ }
+ }
+
+ BMO_slot_copy(&dupeop, op, "newout", "geomout");
+ e = BMO_iter_new(&siter, bm, &dupeop, "boundarymap", 0);
+ for ( ; e; e = BMO_iter_step(&siter)) {
+ if (BMO_slot_map_contains(bm, op, "exclude", e)) continue;
+
+ newedge = BMO_iter_map_value(&siter);
+ newedge = *(BMEdge **)newedge;
+ if (!newedge) continue;
+
+ /* orient loop to give same normal as a loop of newedge
+ * if it exists (will be an extruded face),
+ * else same normal as a loop of e, if it exists */
+ if (!newedge->l)
+ fwd = !e->l || !(e->l->v == e->v1);
+ else
+ fwd = (newedge->l->v == newedge->v1);
+
+
+ if (fwd) {
+ 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_face_create_quad_tri_v(bm, verts, 4, NULL, FALSE);
+
+ /* copy attribute */
+ l = BM_iter_new(&iter, bm, BM_LOOPS_OF_FACE, f);
+ for ( ; l; l = BM_iter_step(&iter)) {
+ if (l->e != e && l->e != newedge) continue;
+ l2 = l->radial_next;
+
+ if (l2 == l) {
+ l2 = newedge->l;
+ BM_elem_attrs_copy(bm, bm, l2->f, l->f);
+
+ BM_elem_attrs_copy(bm, bm, l2, l);
+ l2 = l2->next;
+ l = l->next;
+ BM_elem_attrs_copy(bm, bm, l2, l);
+ }
+ else {
+ BM_elem_attrs_copy(bm, bm, l2->f, l->f);
+
+ /* copy dat */
+ if (l2->v == l->v) {
+ BM_elem_attrs_copy(bm, bm, l2, l);
+ l2 = l2->next;
+ l = l->next;
+ BM_elem_attrs_copy(bm, bm, l2, l);
+ }
+ else {
+ l2 = l2->next;
+ BM_elem_attrs_copy(bm, bm, l2, l);
+ l2 = l2->prev;
+ l = l->next;
+ BM_elem_attrs_copy(bm, bm, l2, l);
+ }
+ }
+ }
+ }
+
+ /* link isolated vert */
+ v = BMO_iter_new(&siter, bm, &dupeop, "isovertmap", 0);
+ for ( ; v; v = BMO_iter_step(&siter)) {
+ v2 = *((void **)BMO_iter_map_value(&siter));
+ BM_edge_create(bm, v, v2, v->e, TRUE);
+ }
+
+ /* cleanu */
+ if (delorig) BMO_op_finish(bm, &delop);
+ BMO_op_finish(bm, &dupeop);
+}
+
+/*
+ * Compute higher-quality vertex normals used by solidify.
+ * Only considers geometry in the marked solidify region.
+ * Note that this does not work so well for non-manifold
+ * regions.
+ */
+static void calc_solidify_normals(BMesh *bm)
+{
+ BMIter viter, eiter, fiter;
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f, *f1, *f2;
+ float edge_normal[3];
+ int i;
+
+ /* can't use BM_edge_face_count because we need to count only marked faces */
+ int *edge_face_count = MEM_callocN(sizeof(int) * bm->totedge, __func__);
+
+ BM_ITER(v, &viter, bm, BM_VERTS_OF_MESH, NULL) {
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ }
+
+ BM_mesh_elem_index_ensure(bm, BM_EDGE);
+
+ BM_ITER(f, &fiter, bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMO_elem_flag_test(bm, f, FACE_MARK)) {
+ continue;
+ }
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_FACE, f) {
+
+ /* And mark all edges and vertices on the
+ * marked faces */
+ BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ BMO_elem_flag_enable(bm, e->v1, VERT_MARK);
+ BMO_elem_flag_enable(bm, e->v2, VERT_MARK);
+ edge_face_count[BM_elem_index_get(e)]++;
+ }
+ }
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ continue;
+ }
+
+ i = edge_face_count[BM_elem_index_get(e)]++;
+
+ if (i == 0 || i > 2) {
+ /* Edge & vertices are non-manifold even when considering
+ * only marked faces */
+ BMO_elem_flag_enable(bm, e, EDGE_NONMAN);
+ BMO_elem_flag_enable(bm, e->v1, VERT_NONMAN);
+ BMO_elem_flag_enable(bm, e->v2, VERT_NONMAN);
+ }
+ }
+ MEM_freeN(edge_face_count);
+ edge_face_count = NULL; /* dont re-use */
+
+ BM_ITER(v, &viter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_vert_is_manifold(bm, v)) {
+ BMO_elem_flag_enable(bm, v, VERT_NONMAN);
+ continue;
+ }
+
+ if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ zero_v3(v->no);
+ }
+ }
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_MESH, NULL) {
+
+ /* If the edge is not part of a the solidify region
+ * its normal should not be considered */
+ if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ continue;
+ }
+
+ /* If the edge joins more than two marked faces high
+ * quality normal computation won't work */
+ if (BMO_elem_flag_test(bm, e, EDGE_NONMAN)) {
+ continue;
+ }
+
+ f1 = f2 = NULL;
+
+ BM_ITER(f, &fiter, bm, BM_FACES_OF_EDGE, e) {
+ if (BMO_elem_flag_test(bm, f, FACE_MARK)) {
+ if (f1 == NULL) {
+ f1 = f;
+ }
+ else {
+ BLI_assert(f2 == NULL);
+ f2 = f;
+ }
+ }
+ }
+
+ BLI_assert(f1 != NULL);
+
+ if (f2 != NULL) {
+ const float angle = angle_normalized_v3v3(f1->no, f2->no);
+
+ if (angle > 0.0f) {
+ /* two faces using this edge, calculate the edge normal
+ * using the angle between the faces as a weighting */
+ add_v3_v3v3(edge_normal, f1->no, f2->no);
+ normalize_v3(edge_normal);
+ mul_v3_fl(edge_normal, angle);
+ }
+ else {
+ /* can't do anything useful here!
+ * Set the face index for a vert incase it gets a zero normal */
+ BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
+ BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
+ 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 */
+ copy_v3_v3(edge_normal, f1->no);
+ mul_v3_fl(edge_normal, M_PI / 2);
+ }
+
+ add_v3_v3(e->v1->no, edge_normal);
+ add_v3_v3(e->v2->no, edge_normal);
+ }
+
+ /* normalize accumulated vertex normal */
+ BM_ITER(v, &viter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ continue;
+ }
+
+ if (BMO_elem_flag_test(bm, v, VERT_NONMAN)) {
+ /* use standard normals for vertices connected to non-manifold edges */
+ BM_vert_normal_update(bm, v);
+ }
+ else if (normalize_v3(v->no) == 0.0f && !BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ /* exceptional case, totally flat. use the normal
+ * of any marked face around the vertex */
+ BM_ITER(f, &fiter, bm, BM_FACES_OF_VERT, v) {
+ if (BMO_elem_flag_test(bm, f, FACE_MARK)) {
+ break;
+ }
+ }
+ copy_v3_v3(v->no, f->no);
+ }
+ }
+}
+
+static void solidify_add_thickness(BMesh *bm, float dist)
+{
+ BMFace *f;
+ BMVert *v;
+ BMLoop *l;
+ BMIter iter, loopIter;
+ float *vert_angles = MEM_callocN(sizeof(float) * bm->totvert * 2, "solidify"); /* 2 in 1 */
+ float *vert_accum = vert_angles + bm->totvert;
+ float angle;
+ int i, index;
+ float maxdist = dist * sqrtf(3.0f);
+
+ /* array for passing verts to angle_poly_v3 */
+ float **verts = NULL;
+ BLI_array_staticdeclare(verts, BM_NGON_STACK_SIZE);
+ /* array for receiving angles from angle_poly_v3 */
+ float *angles = NULL;
+ BLI_array_staticdeclare(angles, BM_NGON_STACK_SIZE);
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMO_elem_flag_test(bm, f, FACE_MARK)) {
+ continue;
+ }
+
+ BM_ITER(l, &loopIter, bm, BM_LOOPS_OF_FACE, f) {
+ BLI_array_append(verts, l->v->co);
+ BLI_array_growone(angles);
+ }
+
+ angle_poly_v3(angles, (const float **)verts, f->len);
+
+ i = 0;
+ BM_ITER(l, &loopIter, bm, BM_LOOPS_OF_FACE, f) {
+ v = l->v;
+ index = BM_elem_index_get(v);
+ angle = angles[i];
+ vert_accum[index] += angle;
+ vert_angles[index] += shell_angle_to_dist(angle_normalized_v3v3(v->no, f->no)) * angle;
+ i++;
+ }
+
+ BLI_array_empty(verts);
+ BLI_array_empty(angles);
+ }
+
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ index = BM_elem_index_get(v);
+ if (vert_accum[index]) { /* zero if unselected */
+ float vdist = MIN2(maxdist, dist * vert_angles[index] / vert_accum[index]);
+ madd_v3_v3fl(v->co, v->no, vdist);
+ }
+ }
+
+ MEM_freeN(vert_angles);
+}
+
+void bmesh_solidify_face_region_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator extrudeop;
+ BMOperator reverseop;
+ float thickness;
+
+ thickness = BMO_slot_float_get(op, "thickness");
+
+ /* Flip original faces (so the shell is extruded inward) */
+ BMO_op_init(bm, &reverseop, "reversefaces");
+ BMO_slot_copy(op, &reverseop, "geom", "faces");
+ BMO_op_exec(bm, &reverseop);
+ BMO_op_finish(bm, &reverseop);
+
+ /* Extrude the region */
+ BMO_op_initf(bm, &extrudeop, "extrudefaceregion alwayskeeporig=%i", TRUE);
+ BMO_slot_copy(op, &extrudeop, "geom", "edgefacein");
+ BMO_op_exec(bm, &extrudeop);
+
+ /* Push the verts of the extruded faces inward to create thickness */
+ BMO_slot_buffer_flag_enable(bm, &extrudeop, "geomout", FACE_MARK, BM_FACE);
+ calc_solidify_normals(bm);
+ solidify_add_thickness(bm, thickness);
+
+ BMO_slot_copy(&extrudeop, op, "geomout", "geomout");
+
+ BMO_op_finish(bm, &extrudeop);
+}
diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c
new file mode 100644
index 00000000000..921c579447b
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_join_triangles.c
@@ -0,0 +1,373 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+
+#include "BLI_math.h"
+#include "BLI_array.h"
+
+#include "bmesh.h"
+
+#include "bmesh_operators_private.h" /* own include */
+
+/*
+ * 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 poin */
+static float measure_facepair(BMesh *UNUSED(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 mak */
+ /* 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 differenc */
+ 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) * 0.5f;
+ if (measure > limit) {
+ return measure;
+ }
+
+ /* Second test: Colinearit */
+ 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);
+
+ /* a completely skinny face is 'pi' after halving */
+ diff = 0.25f * (fabsf(angle_v3v3(edgeVec1, edgeVec2) - (float)M_PI_2) +
+ fabsf(angle_v3v3(edgeVec2, edgeVec3) - (float)M_PI_2) +
+ fabsf(angle_v3v3(edgeVec3, edgeVec4) - (float)M_PI_2) +
+ fabsf(angle_v3v3(edgeVec4, edgeVec1) - (float)M_PI_2));
+
+ if (!diff) {
+ return 0.0;
+ }
+
+ measure += diff;
+ if (measure > limit) {
+ return measure;
+ }
+
+ /* Third test: Concavit */
+ 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.005f
+#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 = e->l->radial_next;
+
+ /* match up loops on each side of an edge corrusponding to each ver */
+ if (l1->v == l3->v) {
+ l2 = l1->next;
+ l4 = l2->next;
+ }
+ else {
+ l2 = l1->next;
+
+ l4 = l3;
+ l3 = 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 late */
+
+ /* do VCOL */
+ 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[2][i] - T2QCOL_LIMIT)
+ break;
+ if (cols[1][i] + T2QCOL_LIMIT < cols[3][i] - T2QCOL_LIMIT)
+ break;
+ }
+
+ if (i == 3)
+ mergeok_vcols = 1;
+ }
+
+ /* do UV */
+ if (luv1 && douvs) {
+ if (tp1->tpage != tp2->tpage); /* do nothin */
+ 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 TRUE;
+ }
+
+ return FALSE;
+}
+
+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_slot_int_get(op, "compare_sharp"), douvs = BMO_slot_int_get(op, "compare_uvs");
+ int dovcols = BMO_slot_int_get(op, "compare_vcols"), domat = BMO_slot_int_get(op, "compare_materials");
+ float limit = BMO_slot_float_get(op, "limit");
+ int i, totedge;
+
+ /* flag all edges of all input face */
+ BMO_ITER(f1, &siter, bm, op, "faces", BM_FACE) {
+ BMO_elem_flag_enable(bm, f1, FACE_INPUT);
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f1) {
+ BMO_elem_flag_enable(bm, l->e, EDGE_MARK);
+ }
+ }
+
+ /* unflag edges that are invalid; e.g. aren't surrounded by triangle */
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BMO_elem_flag_test(bm, e, EDGE_MARK))
+ continue;
+
+ if (BM_edge_face_count(e) != 2) {
+ BMO_elem_flag_disable(bm, e, EDGE_MARK);
+ continue;
+ }
+
+ f1 = e->l->f;
+ f2 = e->l->radial_next->f;
+
+ if (f1->len != 3 || f2->len != 3) {
+ BMO_elem_flag_disable(bm, e, EDGE_MARK);
+ continue;
+ }
+
+ if (!BMO_elem_flag_test(bm, f1, FACE_INPUT) || !BMO_elem_flag_test(bm, f2, FACE_INPUT)) {
+ BMO_elem_flag_disable(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_elem_flag_test(bm, e, EDGE_MARK))
+ continue;
+
+ f1 = e->l->f;
+ f2 = e->l->radial_next->f;
+
+ v1 = e->l->v;
+ v2 = e->l->prev->v;
+ v3 = e->l->next->v;
+ v4 = e->l->radial_next->prev->v;
+
+ if (dosharp && !BM_elem_flag_test(e, BM_ELEM_SMOOTH))
+ 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 = e->l->radial_next->f;
+
+ if (BMO_elem_flag_test(bm, f1, FACE_MARK) || BMO_elem_flag_test(bm, f2, FACE_MARK))
+ continue;
+
+ BMO_elem_flag_enable(bm, f1, FACE_MARK);
+ BMO_elem_flag_enable(bm, f2, FACE_MARK);
+ BMO_elem_flag_enable(bm, e, EDGE_CHOSEN);
+ }
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BMO_elem_flag_test(bm, e, EDGE_CHOSEN))
+ continue;
+
+ f1 = e->l->f;
+ f2 = e->l->radial_next->f;
+
+ BM_faces_join_pair(bm, f1, f2, e);
+ }
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ /* ok, this edge wasn't merged, check if it's
+ * in a 2-tri-pair island, and if so merg */
+
+ f1 = e->l->f;
+ f2 = 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_elem_flag_test(bm, l->e, EDGE_MARK)) {
+ break;
+ }
+ }
+
+ /* if l isn't NULL, we broke out of the loo */
+ if (l) {
+ break;
+ }
+ }
+
+ /* if i isn't 2, we broke out of that loo */
+ if (i != 2) {
+ continue;
+ }
+
+ BM_faces_join_pair(bm, f1, f2, e);
+ }
+ }
+
+ BLI_array_free(jedges);
+}
diff --git a/source/blender/bmesh/operators/bmo_mesh_conv.c b/source/blender/bmesh/operators/bmo_mesh_conv.c
new file mode 100644
index 00000000000..4f6db9056e5
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_mesh_conv.c
@@ -0,0 +1,906 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_key_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BKE_mesh.h"
+#include "BLI_listbase.h"
+#include "BKE_global.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+#include "BKE_customdata.h"
+
+#include "BLI_math.h"
+#include "BLI_array.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include "bmesh_operators_private.h" /* own include */
+
+/*
+ * 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_slot_ptr_get(op, "object");
+ Mesh *me = BMO_slot_ptr_get(op, "mesh");
+ MVert *mvert;
+ BLI_array_declare(verts);
+ MEdge *medge;
+ MLoop *ml;
+ MPoly *mpoly;
+ KeyBlock *actkey, *block;
+ BMVert *v, **vt = NULL, **verts = NULL;
+ BMEdge *e, **fedges = NULL, **et = NULL;
+ BMFace *f;
+ BMLoop *l;
+ BLI_array_declare(fedges);
+ float (*keyco)[3] = NULL;
+ int *keyi;
+ int set_key = BMO_slot_int_get(op, "set_shapekey");
+ int totuv, i, j;
+
+ if (!me || !me->totvert) {
+ return; /* sanity check */
+ }
+
+ 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);
+
+ /* make sure uv layer names are consisten */
+ totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ for (i = 0; i < totuv; i++) {
+ int li = CustomData_get_layer_index_n(&bm->pdata, CD_MTEXPOLY, i);
+ CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name);
+ }
+
+ 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) {
+ CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0);
+
+ /* 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 chec */
+ if (!me->key->uidgen) {
+ fprintf(stderr,
+ "%s had to generate shape key uid's in a situation we shouldn't need to! "
+ "(bmesh internal error)\n",
+ __func__);
+
+ 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, bm_mesh_allocsize_default[0]);
+ CustomData_bmesh_init_pool(&bm->edata, bm_mesh_allocsize_default[1]);
+ CustomData_bmesh_init_pool(&bm->ldata, bm_mesh_allocsize_default[2]);
+ CustomData_bmesh_init_pool(&bm->pdata, bm_mesh_allocsize_default[3]);
+
+ for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) {
+ v = BM_vert_create(bm, keyco && set_key ? keyco[i] : mvert->co, NULL);
+ BM_elem_index_set(v, i); /* set_ok */
+ vt[i] = v;
+
+ /* transfer flag */
+ v->head.hflag = BM_vert_flag_from_mflag(mvert->flag);
+
+ /* this is necassary for selection counts to work properl */
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) BM_vert_select_set(bm, v, TRUE);
+
+ normal_short_to_float_v3(v->no, mvert->no);
+
+ BM_elem_float_data_set(&bm->vdata, v, CD_BWEIGHT, (float)mvert->bweight / 255.0f);
+
+ /* Copy Custom Dat */
+ CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data);
+
+ /* set shapekey dat */
+ if (me->key) {
+ /* set shape key original inde */
+ keyi = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_SHAPE_KEYINDEX);
+ if (keyi) {
+ *keyi = i;
+ }
+
+ 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);
+
+ if (co) {
+ copy_v3_v3(co, ((float *)block->data) + 3 * i);
+ }
+ }
+ }
+ }
+
+ bm->elem_index_dirty &= ~BM_VERT; /* added in order, clear dirty flag */
+
+ 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_edge_create(bm, vt[medge->v1], vt[medge->v2], NULL, FALSE);
+ BM_elem_index_set(e, i); /* set_ok */
+ et[i] = e;
+
+ /* transfer flags */
+ e->head.hflag = BM_edge_flag_from_mflag(medge->flag);
+
+ /* this is necassary for selection counts to work properly */
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) BM_elem_select_set(bm, e, TRUE);
+
+ /* Copy Custom Dat */
+ CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data);
+
+ BM_elem_float_data_set(&bm->edata, e, CD_CREASE, (float)medge->crease / 255.0f);
+ BM_elem_float_data_set(&bm->edata, e, CD_BWEIGHT, (float)medge->bweight / 255.0f);
+ }
+
+ bm->elem_index_dirty &= ~BM_EDGE; /* added in order, clear dirty flag */
+
+ mpoly = me->mpoly;
+ for (i = 0; i < me->totpoly; i++, mpoly++) {
+ BMIter iter;
+
+ BLI_array_empty(fedges);
+ BLI_array_empty(verts);
+
+ BLI_array_growitems(fedges, mpoly->totloop);
+ BLI_array_growitems(verts, mpoly->totloop);
+
+ for (j = 0; j < mpoly->totloop; j++) {
+ ml = &me->mloop[mpoly->loopstart + j];
+ v = vt[ml->v];
+ e = et[ml->e];
+
+ fedges[j] = e;
+ verts[j] = v;
+ }
+
+ /* not sure what this block is supposed to do,
+ * but its unused. so commenting - campbell */
+#if 0
+ {
+ BMVert *v1, *v2;
+ 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;
+ }
+ }
+#endif
+
+ f = BM_face_create(bm, verts, fedges, mpoly->totloop, FALSE);
+
+ if (!f) {
+ printf("%s: Warning! Bad face in mesh"
+ " \"%s\" at index %d!, skipping\n",
+ __func__, me->id.name + 2, i);
+ continue;
+ }
+
+ /* dont use 'i' since we may have skipped the face */
+ BM_elem_index_set(f, bm->totface - 1); /* set_ok */
+
+ /* transfer flag */
+ f->head.hflag = BM_face_flag_from_mflag(mpoly->flag);
+
+ /* this is necassary for selection counts to work properl */
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) BM_elem_select_set(bm, f, TRUE);
+
+ f->mat_nr = mpoly->mat_nr;
+ if (i == me->act_face) bm->act_face = f;
+
+ j = 0;
+ BM_ITER_INDEX(l, &iter, bm, BM_LOOPS_OF_FACE, f, j) {
+ /* Save index of correspsonding MLoop */
+ BM_elem_index_set(l, mpoly->loopstart + j); /* set_loop */
+ }
+
+ /* Copy Custom Dat */
+ CustomData_to_bmesh_block(&me->pdata, &bm->pdata, i, &f->head.data);
+ }
+
+ bm->elem_index_dirty &= ~BM_FACE; /* added in order, clear dirty flag */
+
+ {
+ BMIter fiter;
+ BMIter liter;
+
+ /* Copy over loop CustomData. Doing this in a separate loop isn't necessary
+ * but is an optimization, to avoid copying a bunch of interpolated customdata
+ * for each BMLoop (from previous BMLoops using the same edge), always followed
+ * by freeing the interpolated data and overwriting it with data from the Mesh. */
+ BM_ITER(f, &fiter, bm, BM_FACES_OF_MESH, NULL) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ int li = BM_elem_index_get(l);
+ CustomData_to_bmesh_block(&me->ldata, &bm->ldata, li, &l->head.data);
+ BM_elem_index_set(l, 0); /* set_loop */
+ }
+ }
+ }
+
+ if (me->mselect && me->totselect != 0) {
+ BMIter iter;
+ BMVert *vertex;
+ BMEdge *edge;
+ BMFace *face;
+ BMVert **vertex_array = MEM_callocN(sizeof(BMVert *) * bm->totvert,
+ "Selection Conversion Vertex Pointer Array");
+ BMEdge **edge_array = MEM_callocN(sizeof(BMEdge *) * bm->totedge,
+ "Selection Conversion Edge Pointer Array");
+ BMFace **face_array = MEM_callocN(sizeof(BMFace *) * bm->totface,
+ "Selection Conversion Face Pointer Array");
+
+ for (i = 0, vertex = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ vertex;
+ i++, vertex = BM_iter_step(&iter))
+ {
+ vertex_array[i] = vertex;
+ }
+
+ for (i = 0, edge = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL);
+ edge;
+ i++, edge = BM_iter_step(&iter))
+ {
+ edge_array[i] = edge;
+ }
+
+ for (i = 0, face = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, NULL);
+ face;
+ i++, face = BM_iter_step(&iter))
+ {
+ face_array[i] = face;
+ }
+
+ if (me->mselect) {
+ for (i = 0; i < me->totselect; i++) {
+ if (me->mselect[i].type == ME_VSEL) {
+ BM_select_history_store(bm, vertex_array[me->mselect[i].index]);
+ }
+ else if (me->mselect[i].type == ME_ESEL) {
+ BM_select_history_store(bm, edge_array[me->mselect[i].index]);
+ }
+ else if (me->mselect[i].type == ME_FSEL) {
+ BM_select_history_store(bm, face_array[me->mselect[i].index]);
+ }
+ }
+ }
+ else {
+ me->totselect = 0;
+ }
+
+ MEM_freeN(vertex_array);
+ MEM_freeN(edge_array);
+ MEM_freeN(face_array);
+ }
+ else {
+ me->totselect = 0;
+ if (me->mselect) {
+ MEM_freeN(me->mselect);
+ me->mselect = NULL;
+ }
+ }
+
+ BLI_array_free(fedges);
+ BLI_array_free(verts);
+
+ MEM_freeN(vt);
+ MEM_freeN(et);
+}
+
+void object_load_bmesh_exec(BMesh *bm, BMOperator *op)
+{
+ Object *ob = BMO_slot_ptr_get(op, "object");
+ /* Scene *scene = BMO_slot_ptr_get(op, "scene"); */
+ Mesh *me = ob->data;
+
+ BMO_op_callf(bm, "bmesh_to_mesh mesh=%p object=%p notesselation=%i", me, ob, TRUE);
+}
+
+
+static BMVert **bmesh_to_mesh_vertex_map(BMesh *bm, int ototvert)
+{
+ BMVert **vertMap = NULL;
+ BMVert *eve;
+ int index;
+ int i = 0;
+ BMIter iter;
+
+ /* caller needs to ensure this */
+ BLI_assert(ototvert > 0);
+
+ vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap");
+ if (CustomData_has_layer(&bm->vdata, CD_SHAPE_KEYINDEX)) {
+ int *keyi;
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ keyi = CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_SHAPE_KEYINDEX);
+ if (keyi) {
+ if (((index = *keyi) != ORIGINDEX_NONE) && (index < ototvert)) {
+ vertMap[index] = eve;
+ }
+ }
+ else {
+ if (i < ototvert) {
+ vertMap[i] = eve;
+ }
+ }
+ i++;
+ }
+ }
+ else {
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (i < ototvert) {
+ vertMap[i] = eve;
+ }
+ else {
+ break;
+ }
+ i++;
+ }
+ }
+
+ return vertMap;
+}
+
+BM_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
+{
+ /* this is a cheap way to set the edge draw, its not precise and will
+ * pick the first 2 faces an edge uses */
+
+
+ if ( /* (med->flag & ME_EDGEDRAW) && */ /* assume to be true */
+ (e->l && (e->l != e->l->radial_next)) &&
+ (dot_v3v3(e->l->f->no, e->l->radial_next->f->no) > 0.998f))
+ {
+ med->flag &= ~ME_EDGEDRAW;
+ }
+}
+
+
+void bmesh_to_mesh_exec(BMesh *bm, BMOperator *op)
+{
+ Mesh *me = BMO_slot_ptr_get(op, "mesh");
+ /* Object *ob = BMO_slot_ptr_get(op, "object"); */
+ MLoop *mloop;
+ MPoly *mpoly;
+ MVert *mvert, *oldverts;
+ MEdge *med, *medge;
+ BMVert *v, *eve;
+ BMEdge *e;
+ BMLoop *l;
+ BMFace *f;
+ BMIter iter, liter;
+ int i, j, *keyi, ototvert, totloop;
+ int dotess = !BMO_slot_int_get(op, "notesselation");
+
+ 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 dat */
+ /* 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 allocat */
+ 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;
+ /* will be overwritten with a valid value if 'dotess' is set, otherwise we
+ * end up with 'me->totface' and me->mface == NULL which can crash [#28625]
+ */
+ me->totface = 0;
+
+ 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);
+
+ /* this is called again, 'dotess' arg is used there */
+ mesh_update_customdata_pointers(me, 0);
+
+ i = 0;
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ float *bweight = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_BWEIGHT);
+
+ mvert->bweight = bweight ? (char)((*bweight) * 255) : 0;
+
+ copy_v3_v3(mvert->co, v->co);
+ normal_float_to_short_v3(mvert->no, v->no);
+
+ mvert->flag = BM_vert_flag_to_mflag(v);
+
+ BM_elem_index_set(v, i); /* set_inline */
+
+ /* copy over customdat */
+ CustomData_from_bmesh_block(&bm->vdata, &me->vdata, v->head.data, i);
+
+ i++;
+ mvert++;
+
+ BM_CHECK_ELEMENT(bm, v);
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+
+ med = medge;
+ i = 0;
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ float *crease = CustomData_bmesh_get(&bm->edata, e->head.data, CD_CREASE);
+ float *bweight = CustomData_bmesh_get(&bm->edata, e->head.data, CD_BWEIGHT);
+
+ med->v1 = BM_elem_index_get(e->v1);
+ med->v2 = BM_elem_index_get(e->v2);
+ med->crease = crease ? (char)((*crease) * 255) : 0;
+ med->bweight = bweight ? (char)((*bweight) * 255) : 0;
+
+ med->flag = BM_edge_flag_to_mflag(e);
+
+ BM_elem_index_set(e, i); /* set_inline */
+
+ /* copy over customdat */
+ CustomData_from_bmesh_block(&bm->edata, &me->edata, e->head.data, i);
+
+ bmesh_quick_edgedraw_flag(med, e);
+
+ i++;
+ med++;
+ BM_CHECK_ELEMENT(bm, e);
+ }
+ bm->elem_index_dirty &= ~BM_EDGE;
+
+ 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 = BM_face_flag_to_mflag(f);
+
+ l = BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for ( ; l; l = BM_iter_step(&liter), j++, mloop++) {
+ mloop->e = BM_elem_index_get(l->e);
+ mloop->v = BM_elem_index_get(l->v);
+
+ /* copy over customdat */
+ CustomData_from_bmesh_block(&bm->ldata, &me->ldata, l->head.data, j);
+ BM_CHECK_ELEMENT(bm, l);
+ BM_CHECK_ELEMENT(bm, l->e);
+ BM_CHECK_ELEMENT(bm, l->v);
+ }
+
+ if (f == bm->act_face) me->act_face = i;
+
+ /* copy over customdat */
+ CustomData_from_bmesh_block(&bm->pdata, &me->pdata, f->head.data, i);
+
+ i++;
+ mpoly++;
+ BM_CHECK_ELEMENT(bm, f);
+ }
+
+ /* patch hook indices and vertex parents */
+ if (ototvert > 0) {
+ Object *ob;
+ ModifierData *md;
+ BMVert **vertMap = NULL;
+ int i, j;
+
+ for (ob = G.main->object.first; ob; ob = ob->id.next) {
+ if (ob->parent == bm->ob && ELEM(ob->partype, PARVERT1, PARVERT3)) {
+
+ if (vertMap == NULL) {
+ vertMap = bmesh_to_mesh_vertex_map(bm, ototvert);
+ }
+
+ if (ob->par1 < ototvert) {
+ eve = vertMap[ob->par1];
+ if (eve) ob->par1 = BM_elem_index_get(eve);
+ }
+ if (ob->par2 < ototvert) {
+ eve = vertMap[ob->par2];
+ if (eve) ob->par2 = BM_elem_index_get(eve);
+ }
+ if (ob->par3 < ototvert) {
+ eve = vertMap[ob->par3];
+ if (eve) ob->par3 = BM_elem_index_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 == NULL) {
+ vertMap = bmesh_to_mesh_vertex_map(bm, ototvert);
+ }
+
+ for (i = j = 0; i < hmd->totindex; i++) {
+ if (hmd->indexar[i] < ototvert) {
+ eve = vertMap[hmd->indexar[i]];
+
+ if (eve) {
+ hmd->indexar[j++] = BM_elem_index_get(eve);
+ }
+ }
+ else j++;
+ }
+
+ hmd->totindex = j;
+ }
+ }
+ }
+ }
+
+ if (vertMap) MEM_freeN(vertMap);
+ }
+
+ if (dotess) {
+ BKE_mesh_tessface_calc(me);
+ }
+
+ mesh_update_customdata_pointers(me, dotess);
+
+ {
+ BMEditSelection *selected;
+ me->totselect = BLI_countlist(&(bm->selected));
+
+ if (me->mselect) MEM_freeN(me->mselect);
+
+ me->mselect = MEM_callocN(sizeof(MSelect) * me->totselect, "Mesh selection history");
+
+
+ for (i = 0, selected = bm->selected.first; selected; i++, selected = selected->next) {
+ if (selected->htype == BM_VERT) {
+ me->mselect[i].type = ME_VSEL;
+
+ }
+ else if (selected->htype == BM_EDGE) {
+ me->mselect[i].type = ME_ESEL;
+
+ }
+ else if (selected->htype == BM_FACE) {
+ me->mselect[i].type = ME_FSEL;
+ }
+
+ me->mselect[i].index = BM_elem_index_get(selected->data);
+ }
+ }
+
+ /* see comment below, this logic is in twice */
+
+ if (me->key) {
+ KeyBlock *currkey;
+ KeyBlock *actkey = BLI_findlink(&me->key->block, bm->shapenr - 1);
+
+ float (*ofs)[3] = NULL;
+
+ /* 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 (currkey = me->key->block.first; currkey; currkey = currkey->next) {
+ if (currkey->uid == bm->vdata.layers[i].uid)
+ break;
+ }
+
+ if (!currkey) {
+ currkey = MEM_callocN(sizeof(KeyBlock), "KeyBlock mesh_conv.c");
+ currkey->type = KEY_LINEAR;
+ currkey->slidermin = 0.0f;
+ currkey->slidermax = 1.0f;
+
+ BLI_addtail(&me->key->block, currkey);
+ me->key->totkey++;
+ }
+
+ j++;
+ }
+
+
+ /* 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 (bm->shapenr - 1 == currkey->relative) {
+ act_is_basis = 1;
+ break;
+ }
+ }
+
+ if (act_is_basis) { /* active key is a base */
+ float (*fp)[3] = actkey->data;
+ int *keyi;
+ i = 0;
+ ofs = MEM_callocN(sizeof(float) * 3 * bm->totvert, "currkey->data");
+ mvert = me->mvert;
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ keyi = CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_SHAPE_KEYINDEX);
+ if (keyi && *keyi != ORIGINDEX_NONE) {
+ sub_v3_v3v3(ofs[i], mvert->co, fp[*keyi]);
+ }
+ i++;
+ mvert++;
+ }
+ }
+ }
+
+
+ for (currkey = me->key->block.first; currkey; currkey = currkey->next) {
+ j = 0;
+
+ for (i = 0; i < bm->vdata.totlayer; i++) {
+ if (bm->vdata.layers[i].type != CD_SHAPEKEY)
+ continue;
+
+ if (currkey->uid == bm->vdata.layers[i].uid) {
+ int apply_offset = (ofs && (currkey != actkey) && (bm->shapenr - 1 == currkey->relative));
+ float *fp, *co;
+ float (*ofs_pt)[3] = ofs;
+
+ if (currkey->data)
+ MEM_freeN(currkey->data);
+ currkey->data = fp = MEM_mallocN(sizeof(float) * 3 * bm->totvert, "shape key data");
+ currkey->totelem = bm->totvert;
+
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ co = (currkey == actkey) ?
+ eve->co :
+ CustomData_bmesh_get_n(&bm->vdata, eve->head.data, CD_SHAPEKEY, j);
+
+ copy_v3_v3(fp, co);
+
+ /* propagate edited basis offsets to other shapes */
+ if (apply_offset) {
+ add_v3_v3(fp, *ofs_pt++);
+ }
+
+ 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)) {
+ currkey->flag |= KEYBLOCK_MISSING;
+ }
+ }
+
+ if (ofs) MEM_freeN(ofs);
+ }
+
+ /* XXX, code below is from trunk and a duplicate functionality
+ * to the block above.
+ * We should use one or the other, having both means we have to maintain
+ * both and keep them working the same way which is a hassle - campbell */
+
+ /* 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);
+
+ 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 (bm->shapenr - 1 == currkey->relative) {
+ act_is_basis = 1;
+ break;
+ }
+ }
+
+ if (act_is_basis) { /* active key is a base */
+ float (*fp)[3] = actkey->data;
+ int *keyi;
+ i = 0;
+ ofs = MEM_callocN(sizeof(float) * 3 * bm->totvert, "currkey->data");
+ mvert = me->mvert;
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ keyi = CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_SHAPE_KEYINDEX);
+ if (keyi && *keyi != ORIGINDEX_NONE) {
+ sub_v3_v3v3(ofs[i], mvert->co, fp[*keyi]);
+ }
+ 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) && (bm->shapenr - 1 == currkey->relative));
+
+ 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 = BM_iter_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) {
+ break;
+ }
+ if (*keyi >= 0 && *keyi < currkey->totelem) { // valid old vertex
+ if (currkey == actkey) {
+ if (actkey == me->key->refkey) {
+ copy_v3_v3(fp, mvert->co);
+ }
+ else {
+ copy_v3_v3(fp, mvert->co);
+ if (oldverts) {
+ copy_v3_v3(mvert->co, oldverts[*keyi].co);
+ }
+ }
+ }
+ else {
+ if (oldkey) {
+ copy_v3_v3(fp, oldkey + 3 * *keyi);
+ }
+ }
+ }
+ else {
+ copy_v3_v3(fp, mvert->co);
+ }
+
+ /* propagate edited basis offsets to other shapes */
+ if (apply_offset) {
+ add_v3_v3(fp, ofs[i]);
+ }
+
+ fp+= 3;
+ ++i;
+ ++mvert;
+ eve = BM_iter_step(&iter);
+ }
+ currkey->totelem = bm->totvert;
+ if (currkey->data) MEM_freeN(currkey->data);
+ currkey->data = newkey;
+
+ currkey = currkey->next;
+ }
+
+ if (ofs) MEM_freeN(ofs);
+ }
+
+ if (oldverts) MEM_freeN(oldverts);
+}
diff --git a/source/blender/bmesh/operators/bmo_mirror.c b/source/blender/bmesh/operators/bmo_mirror.c
new file mode 100644
index 00000000000..82e77fc9a96
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_mirror.c
@@ -0,0 +1,126 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_meshdata_types.h"
+
+#include "BLI_math.h"
+#include "BLI_array.h"
+
+#include "BKE_customdata.h"
+
+#include "bmesh.h"
+#include "bmesh_operators_private.h" /* own include */
+
+#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_slot_float_get(op, "mergedist");
+ int i, ototvert, ototedge, axis = BMO_slot_int_get(op, "axis");
+ int mirroru = BMO_slot_int_get(op, "mirror_u");
+ int mirrorv = BMO_slot_int_get(op, "mirror_v");
+
+ ototvert = bm->totvert;
+ ototedge = bm->totedge;
+
+ BMO_slot_mat4_get(op, "mat", mtx);
+ invert_m4_m4(imtx, mtx);
+
+ BMO_op_initf(bm, &dupeop, "dupe geom=%s", op, "geom");
+ BMO_op_exec(bm, &dupeop);
+
+ BMO_slot_buffer_flag_enable(bm, &dupeop, "newout", ELE_NEW, BM_ALL);
+
+ /* create old -> new mappin */
+ i = 0;
+ v2 = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ BMO_ITER(v, &siter, bm, &dupeop, "newout", BM_VERT) {
+ BLI_array_growone(vmap);
+ vmap[i] = v;
+
+ /* BMESH_TODO, double check this is being used, calling following operators will overwrite anyway - campbell */
+ BM_elem_index_set(v2, i); /* set_dirty! */
+ v2 = BM_iter_step(&iter);
+
+ i++;
+ }
+ bm->elem_index_dirty |= BM_VERT;
+
+ /* feed old data to transform bmo */
+ scale[axis] = -1.0f;
+ BMO_op_callf(bm, "transform verts=%fv mat=%m4", ELE_NEW, mtx);
+ BMO_op_callf(bm, "scale verts=%fv vec=%v", ELE_NEW, scale);
+ BMO_op_callf(bm, "transform verts=%fv mat=%m4", ELE_NEW, imtx);
+
+ BMO_op_init(bm, &weldop, "weldverts");
+
+ v = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i = 0; i < ototvert; i++) {
+ if (ABS(v->co[axis]) <= dist) {
+ BMO_slot_map_ptr_insert(bm, &weldop, "targetmap", vmap[i], v);
+ }
+ v = BM_iter_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.0f - luv->uv[0];
+ if (mirrorv)
+ luv->uv[1] = 1.0f - luv->uv[1];
+ }
+ }
+ }
+ }
+
+ BMO_op_exec(bm, &weldop);
+
+ BMO_op_finish(bm, &weldop);
+ BMO_op_finish(bm, &dupeop);
+
+ BMO_slot_from_flag(bm, op, "newout", ELE_NEW, BM_ALL);
+
+ BLI_array_free(vmap);
+ BLI_array_free(emap);
+}
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
new file mode 100644
index 00000000000..f7a1a8f4d06
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -0,0 +1,734 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "ED_mesh.h"
+
+#include "bmesh.h"
+#include "bmesh_private.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] = {
+ {0,1,2},
+ {1,0,5},
+ {0,2,3},
+ {0,3,4},
+ {0,4,5},
+ {1,5,10},
+ {2,1,6},
+ {3,2,7},
+ {4,3,8},
+ {5,4,9},
+ {1,10,6},
+ {2,6,7},
+ {3,7,8},
+ {4,8,9},
+ {5,9,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 */
+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},
+};
+
+#define VERT_MARK 1
+
+#define EDGE_ORIG 1
+#define EDGE_MARK 2
+
+#define FACE_MARK 1
+#define FACE_NEW 2
+
+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_slot_float_get(op, "size");
+ int a, tot = BMO_slot_int_get(op, "xsegments"), seg = BMO_slot_int_get(op, "ysegments");
+
+ if (tot < 2) tot = 2;
+ if (seg < 2) seg = 2;
+
+ BMO_slot_mat4_get(op, "mat", mat);
+
+ /* one segment first: the X axis */
+ phi = 1.0f;
+ phid = 2.0f / ((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_vert_create(bm, vec, NULL);
+ BMO_elem_flag_enable(bm, eve, VERT_MARK);
+
+ if (a) {
+ e = BM_edge_create(bm, preveve, eve, NULL, TRUE);
+ BMO_elem_flag_enable(bm, e, EDGE_ORIG);
+ }
+
+ preveve = eve;
+ phi -= phid;
+ }
+
+ /* extrude and translate */
+ vec[0] = vec[2] = 0.0f;
+ vec[1] = dia * phid;
+ mul_mat3_m4_v3(mat, vec);
+
+ for (a = 0; a < seg - 1; a++) {
+ if (a) {
+ BMO_op_initf(bm, &bmop, "extrude_edge_only edges=%s", &prevop, "geomout");
+ BMO_op_exec(bm, &bmop);
+ BMO_op_finish(bm, &prevop);
+
+ BMO_slot_buffer_flag_enable(bm, &bmop, "geomout", VERT_MARK, BM_VERT);
+ }
+ else {
+ BMO_op_initf(bm, &bmop, "extrude_edge_only edges=%fe", EDGE_ORIG);
+ BMO_op_exec(bm, &bmop);
+ BMO_slot_buffer_flag_enable(bm, &bmop, "geomout", VERT_MARK, BM_VERT);
+ }
+
+ BMO_op_callf(bm, "translate vec=%v verts=%s", vec, &bmop, "geomout");
+ prevop = bmop;
+ }
+
+ if (a)
+ BMO_op_finish(bm, &bmop);
+
+ BMO_slot_from_flag(bm, op, "vertout", VERT_MARK, BM_VERT);
+}
+
+void bmesh_create_uvsphere_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator bmop, prevop;
+ BMVert *eve, *preveve;
+ BMEdge *e;
+ BMIter iter;
+ float vec[3], mat[4][4], cmat[3][3], phi, q[4];
+ float phid, dia = BMO_slot_float_get(op, "diameter");
+ int a, seg = BMO_slot_int_get(op, "segments"), tot = BMO_slot_int_get(op, "revolutions");
+
+ BMO_slot_mat4_get(op, "mat", mat);
+
+ phid = 2.0f * (float)M_PI / tot;
+ phi = 0.25f * (float)M_PI;
+
+ /* one segment first */
+ phi = 0;
+ phid /= 2;
+ for (a = 0; a <= tot; a++) {
+ /* Going in this direction, then edge extruding, makes normals face outward */
+ vec[0] = -dia * sinf(phi);
+ vec[1] = 0.0;
+ vec[2] = dia * cosf(phi);
+ eve = BM_vert_create(bm, vec, NULL);
+ BMO_elem_flag_enable(bm, eve, VERT_MARK);
+
+ if (a != 0) {
+ e = BM_edge_create(bm, preveve, eve, NULL, FALSE);
+ BMO_elem_flag_enable(bm, e, EDGE_ORIG);
+ }
+
+ phi+= phid;
+ preveve = eve;
+ }
+
+ /* extrude and rotate; negative phi to make normals face outward */
+ phi = -M_PI / seg;
+ q[0] = cosf(phi);
+ q[3] = sinf(phi);
+ q[1] = q[2] = 0.0f;
+ quat_to_mat3(cmat, q);
+
+ for (a = 0; a < seg; a++) {
+ if (a) {
+ BMO_op_initf(bm, &bmop, "extrude_edge_only edges=%s", &prevop, "geomout");
+ BMO_op_exec(bm, &bmop);
+ BMO_op_finish(bm, &prevop);
+ }
+ else {
+ BMO_op_initf(bm, &bmop, "extrude_edge_only edges=%fe", EDGE_ORIG);
+ BMO_op_exec(bm, &bmop);
+ }
+
+ BMO_slot_buffer_flag_enable(bm, &bmop, "geomout", VERT_MARK, BM_VERT);
+ BMO_op_callf(bm, "rotate cent=%v mat=%m3 verts=%s", vec, cmat, &bmop, "geomout");
+
+ prevop = bmop;
+ }
+
+ if (a)
+ BMO_op_finish(bm, &bmop);
+
+ {
+ float len, len2, vec2[3];
+
+ len= 2*dia*sinf(phid / 2.0f);
+
+ /* length of one segment in shortest parallen */
+ vec[0]= dia*sinf(phid);
+ vec[1]= 0.0;
+ vec[2]= dia*cosf(phid);
+
+ mul_v3_m3v3(vec2, cmat, vec);
+ len2= len_v3v3(vec, vec2);
+
+ /* use shortest segment length divided by 3 as merge threshold */
+ BMO_op_callf(bm, "removedoubles verts=%fv dist=%f", VERT_MARK, MIN2(len, len2) / 3.0f);
+ }
+
+ /* and now do imat */
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMO_elem_flag_test(bm, eve, VERT_MARK)) {
+ mul_m4_v3(mat, eve->co);
+ }
+ }
+
+ BMO_slot_from_flag(bm, op, "vertout", VERT_MARK, BM_VERT);
+}
+
+void bmesh_create_icosphere_exec(BMesh *bm, BMOperator *op)
+{
+ BMVert *eva[12];
+ BMVert *v;
+ BMIter liter;
+ BMIter viter;
+ BMLoop *l;
+ float vec[3], mat[4][4] /* , phi, phid */;
+ float dia = BMO_slot_float_get(op, "diameter");
+ int a, subdiv = BMO_slot_int_get(op, "subdivisions");
+
+ BMO_slot_mat4_get(op, "mat", mat);
+
+ /* phid = 2.0f * (float)M_PI / subdiv; */ /* UNUSED */
+ /* phi = 0.25f * (float)M_PI; */ /* UNUSED */
+
+ dia /= 200.0f;
+ 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_vert_create(bm, vec, NULL);
+
+ BMO_elem_flag_enable(bm, eva[a], VERT_MARK);
+ }
+
+ 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_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, FALSE);
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, eftemp) {
+ BMO_elem_flag_enable(bm, l->e, EDGE_MARK);
+ }
+
+ BMO_elem_flag_enable(bm, eftemp, FACE_MARK);
+ }
+
+ dia *= 200.0f;
+
+ for (a = 1; a < subdiv; a++) {
+ BMOperator bmop;
+
+ BMO_op_initf(bm, &bmop,
+ "esubd edges=%fe smooth=%f numcuts=%i gridfill=%i beauty=%i",
+ EDGE_MARK, dia, 1, 1, B_SPHERE);
+ BMO_op_exec(bm, &bmop);
+ BMO_slot_buffer_flag_enable(bm, &bmop, "geomout", VERT_MARK, BM_VERT);
+ BMO_slot_buffer_flag_enable(bm, &bmop, "geomout", EDGE_MARK, BM_EDGE);
+ BMO_op_finish(bm, &bmop);
+ }
+
+ /* must transform after becayse of sphere subdivision */
+ BM_ITER(v, &viter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
+ mul_m4_v3(mat, v->co);
+ }
+ }
+
+ BMO_slot_from_flag(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_slot_mat4_get(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_vert_create(bm, v, NULL);
+ BMO_elem_flag_enable(bm, tv[i], VERT_MARK);
+
+ tv[monkeynv + i] = (fabsf(v[0] = -v[0]) < 0.001f) ?
+ tv[i] :
+ (eve = BM_vert_create(bm, v, NULL), mul_m4_v3(mat, eve->co), eve);
+
+ BMO_elem_flag_enable(bm, tv[monkeynv + i], VERT_MARK);
+
+ mul_m4_v3(mat, tv[i]->co);
+ }
+
+ for (i = 0; i < monkeynf; i++) {
+ BM_face_create_quad_tri(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, FALSE);
+
+ BM_face_create_quad_tri(bm,
+ tv[monkeynv + monkeyf[i][2] + i - monkeyo],
+ tv[monkeynv + monkeyf[i][1] + i - monkeyo],
+ tv[monkeynv + monkeyf[i][0] + i - monkeyo],
+ (monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeynv + monkeyf[i][3] + i - monkeyo]: NULL,
+ NULL, FALSE);
+ }
+
+ MEM_freeN(tv);
+
+ BMO_slot_from_flag(bm, op, "vertout", VERT_MARK, BM_VERT);
+}
+
+
+void bmesh_create_circle_exec(BMesh *bm, BMOperator *op)
+{
+ BMVert *v1, *lastv1 = NULL, *cent1, *firstv1 = NULL;
+ float vec[3], mat[4][4], phi, phid;
+ float dia = BMO_slot_float_get(op, "diameter");
+ int cap_ends = BMO_slot_int_get(op, "cap_ends"), segs = BMO_slot_int_get(op, "segments");
+ int cap_tris = BMO_slot_int_get(op, "cap_tris");
+ int a;
+
+ if (!segs)
+ return;
+
+ BMO_slot_mat4_get(op, "mat", mat);
+
+ phid = 2.0f * (float)M_PI / segs;
+ phi = .25f * (float)M_PI;
+
+ if (cap_ends) {
+ vec[0] = vec[1] = 0.0f;
+ vec[2] = 0.0;
+ mul_m4_v3(mat, vec);
+
+ cent1 = BM_vert_create(bm, vec, NULL);
+ }
+
+ for (a = 0; a < segs; a++, phi += phid) {
+ /* Going this way ends up with normal(s) upward */
+ vec[0] = -dia * sinf(phi);
+ vec[1] = dia * cosf(phi);
+ vec[2] = 0.0f;
+ mul_m4_v3(mat, vec);
+ v1 = BM_vert_create(bm, vec, NULL);
+
+ BMO_elem_flag_enable(bm, v1, VERT_MARK);
+
+ if (lastv1)
+ BM_edge_create(bm, v1, lastv1, NULL, FALSE);
+
+ if (a && cap_ends) {
+ BMFace *f;
+
+ f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, FALSE);
+ BMO_elem_flag_enable(bm, f, FACE_NEW);
+ }
+
+ if (!firstv1)
+ firstv1 = v1;
+
+ lastv1 = v1;
+ }
+
+ if (!a)
+ return;
+
+ BM_edge_create(bm, lastv1, firstv1, NULL, FALSE);
+
+ if (cap_ends) {
+ BMFace *f;
+
+ f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, FALSE);
+ BMO_elem_flag_enable(bm, f, FACE_NEW);
+ }
+
+ if (!cap_tris) {
+ BMO_op_callf(bm, "dissolvefaces faces=%ff", FACE_NEW);
+ }
+
+ BMO_slot_from_flag(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_slot_float_get(op, "diameter1");
+ float dia2 = BMO_slot_float_get(op, "diameter2");
+ float depth = BMO_slot_float_get(op, "depth");
+ int cap_ends = BMO_slot_int_get(op, "cap_ends"), segs = BMO_slot_int_get(op, "segments");
+ int cap_tris = BMO_slot_int_get(op, "cap_tris");
+ int a;
+
+ if (!segs)
+ return;
+
+ BMO_slot_mat4_get(op, "mat", mat);
+
+ phid = 2.0f * (float)M_PI / segs;
+ phi = 0.25f * (float)M_PI;
+
+ depth *= 0.5f;
+ if (cap_ends) {
+ vec[0] = vec[1] = 0.0f;
+ vec[2] = -depth;
+ mul_m4_v3(mat, vec);
+
+ cent1 = BM_vert_create(bm, vec, NULL);
+
+ vec[0] = vec[1] = 0.0f;
+ vec[2] = depth;
+ mul_m4_v3(mat, vec);
+
+ cent2 = BM_vert_create(bm, vec, NULL);
+
+ BMO_elem_flag_enable(bm, cent1, VERT_MARK);
+ BMO_elem_flag_enable(bm, cent2, VERT_MARK);
+ }
+
+ for (a = 0; a < segs; a++, phi += phid) {
+ vec[0] = dia1 * sinf(phi);
+ vec[1] = dia1 * cosf(phi);
+ vec[2] = -depth;
+ mul_m4_v3(mat, vec);
+ v1 = BM_vert_create(bm, vec, NULL);
+
+ vec[0] = dia2 * sinf(phi);
+ vec[1] = dia2 * cosf(phi);
+ vec[2] = depth;
+ mul_m4_v3(mat, vec);
+ v2 = BM_vert_create(bm, vec, NULL);
+
+ BMO_elem_flag_enable(bm, v1, VERT_MARK);
+ BMO_elem_flag_enable(bm, v2, VERT_MARK);
+
+ if (a) {
+ if (cap_ends) {
+ BMFace *f;
+
+ f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, FALSE);
+ BMO_elem_flag_enable(bm, f, FACE_NEW);
+ f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, FALSE);
+ BMO_elem_flag_enable(bm, f, FACE_NEW);
+ }
+ BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, FALSE);
+ }
+ else {
+ firstv1 = v1;
+ firstv2 = v2;
+ }
+
+ lastv1 = v1;
+ lastv2 = v2;
+ }
+
+ if (!a)
+ return;
+
+ if (cap_ends) {
+ BMFace *f;
+
+ f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, FALSE);
+ BMO_elem_flag_enable(bm, f, FACE_NEW);
+ f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, FALSE);
+ BMO_elem_flag_enable(bm, f, FACE_NEW);
+ }
+
+ if (!cap_tris) {
+ BMO_op_callf(bm, "dissolvefaces faces=%ff", FACE_NEW);
+ }
+
+ BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, FALSE);
+
+ BMO_op_callf(bm, "removedoubles verts=%fv dist=%f", VERT_MARK, 0.000001);
+ BMO_slot_from_flag(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_slot_float_get(op, "size") / 2.0f;
+
+ BMO_slot_mat4_get(op, "mat", mat);
+
+ if (!off) off = 0.5f;
+
+ vec[0] = -off;
+ vec[1] = -off;
+ vec[2] = -off;
+ mul_m4_v3(mat, vec);
+ v1 = BM_vert_create(bm, vec, NULL);
+ BMO_elem_flag_enable(bm, v1, VERT_MARK);
+
+ vec[0] = -off;
+ vec[1] = off;
+ vec[2] = -off;
+ mul_m4_v3(mat, vec);
+ v2 = BM_vert_create(bm, vec, NULL);
+ BMO_elem_flag_enable(bm, v2, VERT_MARK);
+
+ vec[0] = off;
+ vec[1] = off;
+ vec[2] = -off;
+ mul_m4_v3(mat, vec);
+ v3 = BM_vert_create(bm, vec, NULL);
+ BMO_elem_flag_enable(bm, v3, VERT_MARK);
+
+ vec[0] = off;
+ vec[1] = -off;
+ vec[2] = -off;
+ mul_m4_v3(mat, vec);
+ v4 = BM_vert_create(bm, vec, NULL);
+ BMO_elem_flag_enable(bm, v4, VERT_MARK);
+
+ vec[0] = -off;
+ vec[1] = -off;
+ vec[2] = off;
+ mul_m4_v3(mat, vec);
+ v5 = BM_vert_create(bm, vec, NULL);
+ BMO_elem_flag_enable(bm, v5, VERT_MARK);
+
+ vec[0] = -off;
+ vec[1] = off;
+ vec[2] = off;
+ mul_m4_v3(mat, vec);
+ v6 = BM_vert_create(bm, vec, NULL);
+ BMO_elem_flag_enable(bm, v6, VERT_MARK);
+
+ vec[0] = off;
+ vec[1] = off;
+ vec[2] = off;
+ mul_m4_v3(mat, vec);
+ v7 = BM_vert_create(bm, vec, NULL);
+ BMO_elem_flag_enable(bm, v7, VERT_MARK);
+
+ vec[0] = off;
+ vec[1] = -off;
+ vec[2] = off;
+ mul_m4_v3(mat, vec);
+ v8 = BM_vert_create(bm, vec, NULL);
+ BMO_elem_flag_enable(bm, v8, VERT_MARK);
+
+ /* the four sides */
+ BM_face_create_quad_tri(bm, v5, v6, v2, v1, NULL, FALSE);
+ BM_face_create_quad_tri(bm, v6, v7, v3, v2, NULL, FALSE);
+ BM_face_create_quad_tri(bm, v7, v8, v4, v3, NULL, FALSE);
+ BM_face_create_quad_tri(bm, v8, v5, v1, v4, NULL, FALSE);
+
+ /* top/bottom */
+ BM_face_create_quad_tri(bm, v1, v2, v3, v4, NULL, FALSE);
+ BM_face_create_quad_tri(bm, v8, v7, v6, v5, NULL, FALSE);
+
+ BMO_slot_from_flag(bm, op, "vertout", VERT_MARK, BM_VERT);
+}
diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c
new file mode 100644
index 00000000000..2eb1cf7db3e
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_removedoubles.c
@@ -0,0 +1,590 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_array.h"
+
+#include "BKE_customdata.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include "bmesh_operators_private.h" /* own include */
+
+static void remdoubles_splitface(BMFace *f, BMesh *bm, BMOperator *op)
+{
+ BMIter liter;
+ BMLoop *l;
+ BMVert *v2, *doub;
+ int split = FALSE;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ v2 = BMO_slot_map_ptr_get(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 doubl */
+ if ((v2 && BM_vert_in_face(f, v2)) &&
+ (v2 != l->prev->v) &&
+ (v2 != l->next->v))
+ {
+ doub = l->v;
+ split = TRUE;
+ break;
+ }
+ }
+
+ if (split && doub != v2) {
+ BMLoop *nl;
+ BMFace *f2 = BM_face_split(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 = BM_iter_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 TRUE;
+ }
+ f = BM_iter_step(&vertfaces);
+ }
+ }
+ return FALSE;
+}
+#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 ((v2 = BMO_slot_map_ptr_get(bm, op, "targetmap", v))) {
+ BMO_elem_flag_enable(bm, v, ELE_DEL);
+
+ /* merge the vertex flags, else we get randomly selected/unselected verts */
+ BM_elem_flag_merge(v, v2);
+ }
+ }
+
+ 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_elem_flag_test(bm, e->v1, ELE_DEL) || BMO_elem_flag_test(bm, e->v2, ELE_DEL)) {
+ v = BMO_slot_map_ptr_get(bm, op, "targetmap", e->v1);
+ v2 = BMO_slot_map_ptr_get(bm, op, "targetmap", e->v2);
+
+ if (!v) v = e->v1;
+ if (!v2) v2 = e->v2;
+
+ if (v == v2)
+ BMO_elem_flag_enable(bm, e, EDGE_COL);
+ else if (!BM_edge_exists(v, v2))
+ BM_edge_create(bm, v, v2, e, TRUE);
+
+ BMO_elem_flag_enable(bm, e, ELE_DEL);
+ }
+ }
+
+ /* BMESH_TODO, stop abusing face index here */
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BM_elem_index_set(f, 0); /* set_dirty! */
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ if (BMO_elem_flag_test(bm, l->v, ELE_DEL)) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK|ELE_DEL);
+ }
+ if (BMO_elem_flag_test(bm, l->e, EDGE_COL)) {
+ BM_elem_index_set(f, BM_elem_index_get(f) + 1); /* set_dirty! */
+ }
+ }
+ }
+ bm->elem_index_dirty |= BM_FACE;
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMO_elem_flag_test(bm, f, FACE_MARK))
+ continue;
+
+ if (f->len - BM_elem_index_get(f) < 3) {
+ BMO_elem_flag_enable(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 = l->next->v;
+ if (BMO_elem_flag_test(bm, v, ELE_DEL)) {
+ v = BMO_slot_map_ptr_get(bm, op, "targetmap", v);
+ }
+ if (BMO_elem_flag_test(bm, v2, ELE_DEL)) {
+ v2 = BMO_slot_map_ptr_get(bm, op, "targetmap", v2);
+ }
+
+ e2 = v != v2 ? BM_edge_exists(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_elem_flag_test(bm, v, ELE_DEL)) {
+ v = BMO_slot_map_ptr_get(bm, op, "targetmap", v);
+ }
+ if (BMO_elem_flag_test(bm, v2, ELE_DEL)) {
+ v2 = BMO_slot_map_ptr_get(bm, op, "targetmap", v2);
+ }
+
+ f2 = BM_face_create_ngon(bm, v, v2, edges, a, TRUE);
+ if (f2 && (f2 != f)) {
+ BM_elem_attrs_copy(bm, bm, f, f2);
+
+ a = 0;
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f2) {
+ l2 = loops[a];
+ BM_elem_attrs_copy(bm, bm, l2, l);
+
+ a++;
+ }
+ }
+ }
+
+ BMO_op_callf(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_iter_new(&siter, bm, op, "snapv", BM_VERT);
+ tot = BM_vert_face_count(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_slot_vec_get(op, "mergeco", vec);
+
+ //BMO_op_callf(bm, "collapse_uvs edges=%s", op, "edges");
+ BMO_op_init(bm, &weldop, "weldverts");
+
+ BMO_ITER(v, &siter, bm, op, "verts", BM_VERT) {
+ if (!snapv) {
+ snapv = v;
+ copy_v3_v3(snapv->co, vec);
+ }
+ else {
+ BMO_slot_map_ptr_insert(bm, &weldop, "targetmap", v, snapv);
+ }
+ }
+
+ BMO_op_exec(bm, &weldop);
+ BMO_op_finish(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_op_callf(bm, "collapse_uvs edges=%s", op, "edges");
+ BMO_op_init(bm, &weldop, "weldverts");
+
+ BMO_slot_buffer_flag_enable(bm, op, "edges", EDGE_MARK, BM_EDGE);
+
+ BMW_init(&walker, bm, BMW_SHELL,
+ BMW_MASK_NOP, EDGE_MARK, BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_NIL_LAY);
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BMO_elem_flag_test(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++) {
+ copy_v3_v3(edges[i]->v1->co, min);
+ copy_v3_v3(edges[i]->v2->co, min);
+
+ if (edges[i]->v1 != edges[0]->v1)
+ BMO_slot_map_ptr_insert(bm, &weldop, "targetmap", edges[i]->v1, edges[0]->v1);
+ if (edges[i]->v2 != edges[0]->v1)
+ BMO_slot_map_ptr_insert(bm, &weldop, "targetmap", edges[i]->v2, edges[0]->v1);
+ }
+ }
+
+ BMO_op_exec(bm, &weldop);
+ BMO_op_finish(bm, &weldop);
+
+ BMW_end(&walker);
+ BLI_array_free(edges);
+}
+
+/* uv collapse functio */
+static 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;
+
+ /* clear all short flags */
+ BMO_mesh_flag_disable_all(bm, op, BM_ALL, (1 << 16) - 1);
+
+ BMO_slot_buffer_flag_enable(bm, op, "edges", EDGE_MARK, BM_EDGE);
+
+ BMW_init(&walker, bm, BMW_LOOPDATA_ISLAND,
+ BMW_MASK_NOP, EDGE_MARK, BMW_MASK_NOP, BMW_MASK_NOP,
+ layer);
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ if (BMO_elem_flag_test(bm, l->e, EDGE_MARK)) {
+ /* wal */
+ 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 centroi */
+ 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_finddoubles_common(BMesh *bm, BMOperator *op, BMOperator *optarget, const char *targetmapname)
+{
+ BMOIter oiter;
+ BMVert *v, *v2;
+ BMVert **verts = NULL;
+ BLI_array_declare(verts);
+ float dist, dist3;
+ int i, j, len, keepvert = 0;
+
+ dist = BMO_slot_float_get(op, "dist");
+ dist3 = dist * 3.0f;
+
+ i = 0;
+ BMO_ITER(v, &oiter, bm, op, "verts", BM_VERT) {
+ BLI_array_growone(verts);
+ verts[i++] = v;
+ }
+
+ /* Test whether keepverts arg exists and is non-empty */
+ if (BMO_slot_exists(op, "keepverts")) {
+ keepvert = BMO_iter_new(&oiter, bm, op, "keepverts", BM_VERT) != NULL;
+ }
+
+ /* sort by vertex coordinates added togethe */
+ qsort(verts, BLI_array_count(verts), sizeof(void *), vergaverco);
+
+ /* Flag keepverts */
+ if (keepvert) {
+ BMO_slot_buffer_flag_enable(bm, op, "keepverts", VERT_KEEP, BM_VERT);
+ }
+
+ len = BLI_array_count(verts);
+ for (i = 0; i < len; i++) {
+ v = verts[i];
+ if (BMO_elem_flag_test(bm, v, VERT_DOUBLE)) continue;
+
+ for (j = i + 1; j < len; j++) {
+ v2 = verts[j];
+
+ /* Compare sort values of the verts using 3x tolerance (allowing for the tolerance
+ * on each of the three axes). This avoids the more expensive length comparison
+ * for most vertex pairs. */
+ if ((v2->co[0]+v2->co[1]+v2->co[2])-(v->co[0]+v->co[1]+v->co[2]) > dist3)
+ break;
+
+ if (keepvert) {
+ if (BMO_elem_flag_test(bm, v2, VERT_KEEP) == BMO_elem_flag_test(bm, v, VERT_KEEP))
+ continue;
+ }
+
+ if (compare_len_v3v3(v->co, v2->co, dist)) {
+
+ /* If one vert is marked as keep, make sure it will be the target */
+ if (BMO_elem_flag_test(bm, v2, VERT_KEEP)) {
+ SWAP(BMVert *, v, v2);
+ }
+
+ BMO_elem_flag_enable(bm, v2, VERT_DOUBLE);
+ BMO_elem_flag_enable(bm, v, VERT_TARGET);
+
+ BMO_slot_map_ptr_insert(bm, optarget, targetmapname, v2, v);
+ }
+ }
+ }
+
+ BLI_array_free(verts);
+}
+
+void bmesh_removedoubles_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator weldop;
+
+ BMO_op_init(bm, &weldop, "weldverts");
+ bmesh_finddoubles_common(bm, op, &weldop, "targetmap");
+ BMO_op_exec(bm, &weldop);
+ BMO_op_finish(bm, &weldop);
+}
+
+
+void bmesh_finddoubles_exec(BMesh *bm, BMOperator *op)
+{
+ bmesh_finddoubles_common(bm, op, op, "targetmapout");
+}
+
+void bmesh_automerge_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator findop, weldop;
+ BMIter viter;
+ BMVert *v;
+
+ /* The "verts" input sent to this op is the set of verts that
+ * can be merged away into any other verts. Mark all other verts
+ * as VERT_KEEP. */
+ BMO_slot_buffer_flag_enable(bm, op, "verts", VERT_IN, BM_VERT);
+ BM_ITER(v, &viter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BMO_elem_flag_test(bm, v, VERT_IN)) {
+ BMO_elem_flag_enable(bm, v, VERT_KEEP);
+ }
+ }
+
+ /* Search for doubles among all vertices, but only merge non-VERT_KEEP
+ * vertices into VERT_KEEP vertices. */
+ BMO_op_initf(bm, &findop, "finddoubles verts=%av keepverts=%fv", VERT_KEEP);
+ BMO_slot_copy(op, &findop, "dist", "dist");
+ BMO_op_exec(bm, &findop);
+
+ /* weld the vertices */
+ BMO_op_init(bm, &weldop, "weldverts");
+ BMO_slot_copy(&findop, &weldop, "targetmapout", "targetmap");
+ BMO_op_exec(bm, &weldop);
+
+ BMO_op_finish(bm, &findop);
+ BMO_op_finish(bm, &weldop);
+}
diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c
new file mode 100644
index 00000000000..310762e0e37
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_subdivide.c
@@ -0,0 +1,1104 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_array.h"
+#include "BLI_noise.h"
+
+#include "BKE_customdata.h"
+
+#include "DNA_object_types.h"
+
+#include "ED_mesh.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include "bmesh_operators_private.h" /* own include */
+
+#include "bmo_subdivide.h" /* own include */
+
+/* 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_CUSTOMFILL 4
+#define ELE_INNER 8
+#define ELE_SPLIT 16
+
+/*
+ * 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 */
+static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **r_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 = BM_iter_new(&iter, bm, BM_FACES_OF_VERT, v1); face; face = BM_iter_step(&iter)) {
+ for (v = BM_iter_new(&iter2, bm, BM_VERTS_OF_FACE, face); v; v = BM_iter_step(&iter2)) {
+ if (v == v2) {
+ if (!curf || face->len < curf->len) curf = face;
+ }
+ }
+ }
+
+ if (curf) {
+ face = BM_face_split(bm, curf, v1, v2, &nl, NULL);
+
+ if (r_nf) *r_nf = face;
+ return nl ? nl->e : NULL;
+ }
+
+ return NULL;
+}
+/* calculates offset for co, based on fractal, sphere or smooth settings */
+static void alter_co(BMesh *bm, BMVert *v, BMEdge *UNUSED(origed), const subdparams *params, float perc,
+ BMVert *vsta, BMVert *vend)
+{
+ float tvec[3], prev_co[3], fac;
+ float *co = NULL;
+ int i, totlayer = CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY);
+
+ BM_vert_normal_update_all(bm, v);
+
+ co = CustomData_bmesh_get_n(&bm->vdata, v->head.data, CD_SHAPEKEY, params->origkey);
+ copy_v3_v3(prev_co, co);
+
+ if (params->beauty & B_SMOOTH) {
+ /* we calculate an offset vector vec1[], to be added to *co */
+ float len, 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= dot_v3v3(nor, nor1);
+ mul_v3_v3fl(tvec, nor1, fac);
+
+ /* cosine angle */
+ fac = -dot_v3v3(nor, nor2);
+ madd_v3_v3fl(tvec, nor2, fac);
+
+ /* falloff for multi subdivide */
+ smooth *= sqrtf(fabsf(1.0f - 2.0f * fabsf(0.5f-perc)));
+
+ mul_v3_fl(tvec, smooth * len);
+
+ add_v3_v3(co, tvec);
+ }
+ else if (params->beauty & B_SPHERE) { /* subdivide sphere */
+ normalize_v3(co);
+ mul_v3_fl(co, params->smooth);
+ }
+
+ if (params->beauty & B_FRACTAL) {
+ float len = len_v3v3(vsta->co, vend->co);
+ float vec2[3] = {0.0f, 0.0f, 0.0f}, co2[3];
+
+ fac = params->fractal * len;
+
+ add_v3_v3(vec2, vsta->no);
+ add_v3_v3(vec2, vend->no);
+ mul_v3_fl(vec2, 0.5f);
+
+ add_v3_v3v3(co2, v->co, params->off);
+ tvec[0] = fac * (BLI_gTurbulence(1.0, co2[0], co2[1], co2[2], 15, 0, 1) - 0.5f);
+ tvec[1] = fac * (BLI_gTurbulence(1.0, co2[0], co2[1], co2[2], 15, 0, 1) - 0.5f);
+ tvec[2] = fac * (BLI_gTurbulence(1.0, co2[0], co2[1], co2[2], 15, 0, 1) - 0.5f);
+
+ mul_v3_v3(vec2, tvec);
+
+ /* add displacemen */
+ add_v3_v3v3(co, co, vec2);
+ }
+
+ /* apply the new difference to the rest of the shape keys,
+ * note that this doent take rotations into account, we _could_ support
+ * this by getting the normals and coords for each shape key and
+ * re-calculate the smooth value for each but this is quite involved.
+ * for now its ok to simply apply the difference IMHO - campbell */
+ sub_v3_v3v3(tvec, prev_co, co);
+
+ for (i = 0; i < totlayer; i++) {
+ if (params->origkey != i) {
+ co = CustomData_bmesh_get_n(&bm->vdata, v->head.data, CD_SHAPEKEY, i);
+ sub_v3_v3(co, tvec);
+ }
+ }
+
+}
+
+/* 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,
+ const subdparams *params, float percent,
+ float percent2,
+ BMEdge **out, BMVert *vsta, BMVert *vend)
+{
+ BMVert *ev;
+
+ ev = BM_edge_split(bm, edge->v1, edge, out, percent);
+
+ BMO_elem_flag_enable(bm, ev, ELE_INNER);
+
+ /* offset for smooth or sphere or fractal */
+ alter_co(bm, ev, oedge, params, percent2, vsta, vend);
+
+#if 0 //BMESH_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, const subdparams *params,
+ BMEdge **newe, BMVert *vsta, BMVert *vend)
+{
+ BMVert *ev;
+ float percent, percent2 = 0.0f;
+
+ if (BMO_elem_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1)
+ percent = BMO_slot_map_float_get(bm, params->op, "edgepercents", edge);
+ else {
+ percent = 1.0f / (float)(totpoint + 1-curpoint);
+ percent2 = (float)(curpoint + 1) / (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, const subdparams *params,
+ BMVert *vsta, BMVert *vend)
+{
+ BMEdge *eed = edge, *newe, temp = *edge;
+ BMVert *v, ov1 = *edge->v1, ov2 = *edge->v2, *v1 = edge->v1, *v2 = edge->v2;
+ int i, numcuts = params->numcuts;
+
+ temp.v1 = &ov1;
+ temp.v2 = &ov2;
+
+ for (i = 0; i < numcuts; i++) {
+ v = subdivideedgenum(bm, eed, &temp, i, params->numcuts, params, &newe, vsta, vend);
+
+ BMO_elem_flag_enable(bm, v, SUBD_SPLIT);
+ BMO_elem_flag_enable(bm, eed, SUBD_SPLIT);
+ BMO_elem_flag_enable(bm, newe, SUBD_SPLIT);
+
+ BMO_elem_flag_enable(bm, v, ELE_SPLIT);
+ BMO_elem_flag_enable(bm, eed, ELE_SPLIT);
+ BMO_elem_flag_enable(bm, newe, SUBD_SPLIT);
+
+ BM_CHECK_ELEMENT(bm, v);
+ if (v->e) BM_CHECK_ELEMENT(bm, v->e);
+ if (v->e && v->e->l) BM_CHECK_ELEMENT(bm, v->e->l->f);
+ }
+
+ alter_co(bm, v1, &temp, params, 0, &ov1, &ov2);
+ alter_co(bm, v2, &temp, params, 1.0, &ov1, &ov2);
+}
+
+/* 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, const subdparams *params)
+{
+ BMFace *nf;
+ int i, add, numcuts = params->numcuts;
+
+ /* if it's odd, the middle face is a quad, otherwise it's a triangl */
+ 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);
+ }
+ }
+
+ }
+}
+
+static 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,
+ const 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);
+}
+
+static 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,
+ const subdparams *params)
+{
+ BMFace *nf;
+ BMVert *v, *lastv;
+ BMEdge *e, *ne, olde;
+ 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);
+
+ olde = *e;
+ v = bm_subdivide_edge_addvert(bm, e, &olde, params, 0.5f, 0.5f, &ne, e->v1, e->v2);
+
+ if (i != numcuts - 1) {
+ connect_smallest_face(bm, lastv, v, &nf);
+ }
+
+ lastv = v;
+ }
+
+ connect_smallest_face(bm, lastv, verts[numcuts * 2 + 2], &nf);
+}
+
+static 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 *UNUSED(face), BMVert **verts,
+ const subdparams *params)
+{
+ BMFace *nf;
+ /* BMVert *v; */ /* UNUSED */
+ /* BMVert *lastv = verts[2]; */ /* UNUSED */
+ /* BMEdge *e, *ne; */ /* UNUSED */
+ int i, numcuts = params->numcuts;
+
+ 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);
+ }
+}
+
+static 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 *UNUSED(face), BMVert **verts,
+ const 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);
+ }
+}
+
+static 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 *UNUSED(face), BMVert **verts,
+ const 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_elem_flag_enable(bm, e, ELE_INNER);
+ BMO_elem_flag_enable(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_elem_flag_enable(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_elem_flag_enable(bm, e, ELE_INNER);
+ BMO_elem_flag_enable(bm, nf, ELE_INNER);
+ }
+ }
+
+ MEM_freeN(lines);
+}
+
+/*
+ * v3
+ * / \
+ * / \
+ * / \
+ * / \
+ * / \
+ * v4--v0--v1--v2
+ * s s
+ */
+static void tri_1edge_split(BMesh *bm, BMFace *UNUSED(face), BMVert **verts,
+ const 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);
+ }
+}
+
+static 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 *UNUSED(face), BMVert **verts,
+ const subdparams *params)
+{
+ BMFace *nf;
+ BMEdge *e, *ne, temp;
+ BMVert ***lines, *v, ov1, ov2;
+ void *stackarr[1];
+ int i, j, a, b, numcuts = params->numcuts;
+
+ /* number of verts in each lin */
+ lines = MEM_callocN(sizeof(void *)*(numcuts + 2), "triangle vert table");
+
+ lines[0] = (BMVert **) stackarr;
+ lines[0][0] = verts[numcuts * 2 + 1];
+
+ lines[numcuts + 1] = MEM_callocN(sizeof(void *) * (numcuts + 2), "triangle vert table 2");
+ for (i = 0; i < numcuts; i++) {
+ lines[numcuts + 1][i + 1] = verts[i];
+ }
+ lines[numcuts + 1][0] = verts[numcuts * 3 + 2];
+ lines[numcuts + 1][numcuts + 1] = 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_elem_flag_enable(bm, e, ELE_INNER);
+ BMO_elem_flag_enable(bm, nf, ELE_INNER);
+
+ lines[i + 1][0] = verts[a];
+ lines[i + 1][i + 1] = verts[b];
+
+ temp = *e;
+ ov1 = *verts[a];
+ ov2 = *verts[b];
+ temp.v1 = &ov1;
+ temp.v2 = &ov2;
+ 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_elem_flag_enable(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_elem_flag_enable(bm, e, ELE_INNER);
+ BMO_elem_flag_enable(bm, nf, ELE_INNER);
+
+ e = connect_smallest_face(bm, lines[i][j + 1], lines[i + 1][j + 1], &nf);
+
+ BMO_elem_flag_enable(bm, e, ELE_INNER);
+ BMO_elem_flag_enable(bm, nf, ELE_INNER);
+ }
+ }
+
+cleanup:
+ for (i = 1; i < numcuts + 2; i++) {
+ if (lines[i]) MEM_freeN(lines[i]);
+ }
+
+ MEM_freeN(lines);
+}
+
+static SubDPattern tri_3edge = {
+ {1, 1, 1},
+ tri_3edge_subdivide,
+ 3,
+};
+
+
+static SubDPattern quad_4edge = {
+ {1, 1, 1, 1},
+ quad_4edge_subdivide,
+ 4,
+};
+
+static 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;
+ SubDPattern *pat;
+ subdparams params;
+ subd_facedata *facedata = NULL;
+ BMIter viter, fiter, liter;
+ BMVert *v, **verts = NULL;
+ BMEdge *edge, **edges = NULL;
+ BMLoop *nl, *l, **splits = NULL, **loops = NULL;
+ BMFace *face;
+ BLI_array_declare(splits);
+ BLI_array_declare(loops);
+ BLI_array_declare(facedata);
+ BLI_array_declare(edges);
+ BLI_array_declare(verts);
+ float smooth, fractal;
+ int beauty, cornertype, singleedge, gridfill;
+ int skey, seed, i, j, matched, a, b, numcuts, totesel;
+
+ BMO_slot_buffer_flag_enable(bmesh, op, "edges", SUBD_SPLIT, BM_EDGE);
+
+ numcuts = BMO_slot_int_get(op, "numcuts");
+ seed = BMO_slot_int_get(op, "seed");
+ smooth = BMO_slot_float_get(op, "smooth");
+ fractal = BMO_slot_float_get(op, "fractal");
+ beauty = BMO_slot_int_get(op, "beauty");
+ cornertype = BMO_slot_int_get(op, "quadcornertype");
+ singleedge = BMO_slot_int_get(op, "singleedge");
+ gridfill = BMO_slot_int_get(op, "gridfill");
+
+ BLI_srandom(seed);
+
+ 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;
+ }
+
+ /* add a temporary shapekey layer to store displacements on current geometr */
+ BM_data_layer_add(bmesh, &bmesh->vdata, CD_SHAPEKEY);
+ skey = CustomData_number_of_layers(&bmesh->vdata, CD_SHAPEKEY) - 1;
+
+ BM_ITER(v, &viter, bmesh, BM_VERTS_OF_MESH, NULL) {
+ float *co = CustomData_bmesh_get_n(&bmesh->vdata, v->head.data, CD_SHAPEKEY, skey);
+ copy_v3_v3(co, v->co);
+ }
+
+ /* first go through and tag edge */
+ BMO_slot_from_flag(bmesh, op, "edges",
+ SUBD_SPLIT, BM_EDGE);
+
+ params.numcuts = numcuts;
+ params.op = op;
+ params.smooth = smooth;
+ params.seed = seed;
+ params.fractal = fractal;
+ params.beauty = beauty;
+ params.origkey = skey;
+ params.off[0] = (float)BLI_drand() * 200.0f;
+ params.off[1] = (float)BLI_drand() * 200.0f;
+ params.off[2] = (float)BLI_drand() * 200.0f;
+
+ BMO_slot_map_to_flag(bmesh, op, "custompatterns",
+ FACE_CUSTOMFILL);
+
+ BMO_slot_map_to_flag(bmesh, op, "edgepercents",
+ EDGE_PERCENT);
+
+ for (face = BM_iter_new(&fiter, bmesh, BM_FACES_OF_MESH, NULL);
+ face;
+ face = BM_iter_step(&fiter))
+ {
+ BMEdge *e1 = NULL, *e2 = NULL;
+ float vec1[3], vec2[3];
+
+ /* figure out which pattern to us */
+
+ BLI_array_empty(edges);
+ BLI_array_empty(verts);
+ matched = 0;
+
+ i = 0;
+ totesel = 0;
+ for (nl = BM_iter_new(&liter, bmesh, BM_LOOPS_OF_FACE, face); nl; nl = BM_iter_step(&liter)) {
+ BLI_array_growone(edges);
+ BLI_array_growone(verts);
+ edges[i] = nl->e;
+ verts[i] = nl->v;
+
+ if (BMO_elem_flag_test(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 othe */
+ if (totesel == 2 && BM_edge_share_vert(e1, e2)) {
+ 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 = dot_v3v3(vec1, vec2);
+ angle = fabsf(angle);
+ if (fabsf(angle - 1.0f) < 0.01f) {
+ totesel = 0;
+ }
+ }
+
+ if (BMO_elem_flag_test(bmesh, face, FACE_CUSTOMFILL)) {
+ pat = BMO_slot_map_data_get(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_elem_flag_test(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_elem_flag_enable(bmesh, face, SUBD_SPLIT);
+ break;
+ }
+ }
+
+ /* obvously don't test for other patterns matchin */
+ 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_elem_flag_test(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_elem_flag_enable(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_elem_flag_enable(bmesh, face, SUBD_SPLIT);
+ facedata[j].totedgesel = totesel;
+ facedata[j].face = face;
+ }
+ }
+
+ einput = BMO_slot_get(op, "edges");
+
+ /* go through and split edge */
+ 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 us */
+ 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 har */
+ 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 edge */
+ for (a = 1; a < vlen; a++) {
+ if (!BMO_elem_flag_test(bmesh, loops[a - 1]->v, ELE_INNER) &&
+ BMO_elem_flag_test(bmesh, loops[a]->v, ELE_INNER))
+ {
+ break;
+ }
+ }
+
+ if (BMO_elem_flag_test(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_elem_flag_test(bmesh, loops[b == 0 ? vlen - 1 : b - 1]->v, ELE_INNER) &&
+ BMO_elem_flag_test(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_face_legal_splits(bmesh, face, splits, BLI_array_count(splits)/2);
+
+ for (j = 0; j < BLI_array_count(splits) / 2; j++) {
+ if (splits[j * 2]) {
+ /* BMFace *nf = */ /* UNUSED */
+ BM_face_split(bmesh, face, splits[j * 2]->v, splits[j * 2 + 1]->v, &nl, NULL);
+ }
+ }
+
+ continue;
+ }
+ else if (!pat) {
+ continue;
+ }
+
+ j = a = 0;
+ for (nl = BM_iter_new(&liter, bmesh, BM_LOOPS_OF_FACE, face);
+ nl;
+ nl = BM_iter_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 = BM_iter_new(&liter, bmesh, BM_LOOPS_OF_FACE, face); nl; nl = BM_iter_step(&liter)) {
+ b = (j - a + face->len) % face->len;
+ verts[b] = nl->v;
+ j += 1;
+ }
+
+ BM_CHECK_ELEMENT(bmesh, face);
+ pat->connectexec(bmesh, face, verts, &params);
+ }
+
+ /* copy original-geometry displacements to current coordinate */
+ BM_ITER(v, &viter, bmesh, BM_VERTS_OF_MESH, NULL) {
+ float *co = CustomData_bmesh_get_n(&bmesh->vdata, v->head.data, CD_SHAPEKEY, skey);
+ copy_v3_v3(v->co, co);
+ }
+
+ BM_data_layer_free_n(bmesh, &bmesh->vdata, CD_SHAPEKEY, skey);
+
+ 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_slot_from_flag(bmesh, op, "outinner",
+ ELE_INNER, BM_ALL);
+ BMO_slot_from_flag(bmesh, op, "outsplit",
+ ELE_SPLIT, BM_ALL);
+
+ BMO_slot_from_flag(bmesh, op, "geomout",
+ ELE_INNER|ELE_SPLIT|SUBD_SPLIT, BM_ALL);
+}
+
+/* editmesh-emulating functio */
+void BM_mesh_esubdivideflag(Object *UNUSED(obedit), BMesh *bm, int flag, float smooth,
+ float fractal, int beauty, int numcuts,
+ int seltype, int cornertype, int singleedge,
+ int gridfill, int seed)
+{
+ BMOperator op;
+
+ BMO_op_initf(bm, &op, "esubd edges=%he smooth=%f fractal=%f "
+ "beauty=%d numcuts=%d quadcornertype=%d singleedge=%d "
+ "gridfill=%d seed=%d",
+ flag, smooth, fractal, beauty, numcuts,
+ cornertype, singleedge, gridfill, seed);
+
+ BMO_op_exec(bm, &op);
+
+ if (seltype == SUBDIV_SELECT_INNER) {
+ BMOIter iter;
+ BMHeader *ele;
+ // int i;
+
+ ele = BMO_iter_new(&iter, bm, &op, "outinner", BM_EDGE|BM_VERT);
+ for ( ; ele; ele = BMO_iter_step(&iter)) {
+ BM_elem_select_set(bm, ele, TRUE);
+ }
+ }
+ else if (seltype == SUBDIV_SELECT_LOOPCUT) {
+ BMOIter iter;
+ BMHeader *ele;
+ // int i;
+
+ /* deselect input */
+ BM_mesh_elem_flag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT);
+
+ ele = BMO_iter_new(&iter, bm, &op, "outinner", BM_EDGE|BM_VERT);
+ for ( ; ele; ele = BMO_iter_step(&iter)) {
+ BM_elem_select_set(bm, ele, TRUE);
+
+ if (ele->htype == BM_VERT) {
+ BMEdge *e;
+ BMIter eiter;
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, ele) {
+ if (!BM_elem_flag_test(e, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(e->v1, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(e->v2, BM_ELEM_SELECT))
+ {
+ BM_elem_select_set(bm, e, TRUE);
+ bm->totedgesel += 1;
+ }
+ else if (BM_elem_flag_test(e, BM_ELEM_SELECT) &&
+ (!BM_elem_flag_test(e->v1, BM_ELEM_SELECT) ||
+ !BM_elem_flag_test(e->v2, BM_ELEM_SELECT)))
+ {
+ BM_elem_select_set(bm, e, FALSE);
+ bm->totedgesel -= 1;
+ }
+ }
+ }
+ }
+ }
+
+ BMO_op_finish(bm, &op);
+}
+
+void esplit_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMEdge *e;
+ subdparams params;
+ int skey;
+
+ params.numcuts = BMO_slot_get(op, "numcuts")->data.i;
+ params.op = op;
+
+ BM_data_layer_add(bm, &bm->vdata, CD_SHAPEKEY);
+ skey = CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY) - 1;
+
+ params.origkey = skey;
+
+ /* go through and split edge */
+ BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
+ bm_subdivide_multicut(bm, e, &params, e->v1, e->v2);
+ }
+
+ BMO_slot_from_flag(bm, op, "outsplit", ELE_SPLIT, BM_ALL);
+
+ BM_data_layer_free_n(bm, &bm->vdata, CD_SHAPEKEY, skey);
+}
diff --git a/source/blender/bmesh/operators/bmo_subdivide.h b/source/blender/bmesh/operators/bmo_subdivide.h
new file mode 100644
index 00000000000..dd5198bdc30
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_subdivide.h
@@ -0,0 +1,66 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMO_SUBDIVIDE_H__
+#define __BMO_SUBDIVIDE_H__
+
+/** \file blender/bmesh/operators/bmo_subdivide.h
+ * \ingroup bmesh
+ */
+
+typedef struct subdparams {
+ int numcuts;
+ float smooth;
+ float fractal;
+ int beauty;
+ int seed;
+ int origkey; /* shapekey holding displaced vertex coordinates for current geometry */
+ BMOperator *op;
+ float off[3];
+} subdparams;
+
+typedef void (*subd_pattern_fill_fp)(BMesh *bm, BMFace *face, BMVert **verts,
+ const 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 /* __BMO_SUBDIVIDE_H__ */
diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c
new file mode 100644
index 00000000000..90efe0b6e44
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_triangulate.c
@@ -0,0 +1,219 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_scanfill.h"
+#include "BLI_math.h"
+#include "BLI_array.h"
+#include "BLI_editVert.h"
+#include "BLI_smallhash.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include "bmesh_operators_private.h" /* own include */
+
+#define EDGE_NEW 1
+#define FACE_NEW 1
+
+#define ELE_NEW 1
+#define FACE_MARK 2
+#define EDGE_MARK 4
+
+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_iter_new(&siter, bm, op, "faces", BM_FACE);
+ for ( ; face; face = BMO_iter_step(&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_face_triangulate(bm, face, projectverts, EDGE_NEW, FACE_NEW, newfaces);
+
+ BMO_slot_map_ptr_insert(bm, op, "facemap", face, face);
+ for (i = 0; newfaces[i]; i++) {
+ BMO_slot_map_ptr_insert(bm, op, "facemap",
+ newfaces[i], face);
+
+ }
+ }
+
+ BMO_slot_from_flag(bm, op, "edgeout", EDGE_NEW, BM_EDGE);
+ BMO_slot_from_flag(bm, op, "faceout", FACE_NEW, BM_FACE);
+
+ BLI_array_free(projectverts);
+ BLI_array_free(newfaces);
+}
+
+void bmesh_beautify_fill_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMIter iter;
+ BMFace *f;
+ BMEdge *e;
+ int stop = 0;
+
+ BMO_slot_buffer_flag_enable(bm, op, "constrain_edges", EDGE_MARK, BM_EDGE);
+
+ BMO_ITER(f, &siter, bm, op, "faces", BM_FACE) {
+ if (f->len == 3)
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
+
+ while (!stop) {
+ stop = 1;
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ BMVert *v1, *v2, *v3, *v4;
+
+ if (BM_edge_face_count(e) != 2 || BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ continue;
+ }
+
+ if (!BMO_elem_flag_test(bm, e->l->f, FACE_MARK) ||
+ !BMO_elem_flag_test(bm, e->l->radial_next->f, FACE_MARK))
+ {
+ continue;
+ }
+
+ v1 = e->l->prev->v;
+ v2 = e->l->v;
+ v3 = e->l->radial_next->prev->v;
+ v4 = e->l->next->v;
+
+ if (is_quad_convex_v3(v1->co, v2->co, v3->co, v4->co)) {
+ float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2;
+ /* 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);
+
+ if (fac1 > fac2) {
+ e = BM_edge_rotate(bm, e, 0);
+ if (e) {
+ BMO_elem_flag_enable(bm, e, ELE_NEW);
+
+ BMO_elem_flag_enable(bm, e->l->f, FACE_MARK|ELE_NEW);
+ BMO_elem_flag_enable(bm, e->l->radial_next->f, FACE_MARK|ELE_NEW);
+ stop = 0;
+ }
+ }
+ }
+ }
+ }
+
+ BMO_slot_from_flag(bm, op, "geomout", ELE_NEW, BM_EDGE|BM_FACE);
+}
+
+void bmesh_triangle_fill_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMEdge *e;
+ BMOperator bmop;
+ EditEdge *eed;
+ EditVert *eve, *v1, *v2;
+ EditFace *efa;
+ SmallHash hash;
+
+ BLI_smallhash_init(&hash);
+
+ BLI_begin_edgefill();
+
+ BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
+ BMO_elem_flag_enable(bm, e, EDGE_MARK);
+
+ if (!BLI_smallhash_haskey(&hash, (uintptr_t)e->v1)) {
+ eve = BLI_addfillvert(e->v1->co);
+ eve->tmp.p = e->v1;
+ BLI_smallhash_insert(&hash, (uintptr_t)e->v1, eve);
+ }
+
+ if (!BLI_smallhash_haskey(&hash, (uintptr_t)e->v2)) {
+ eve = BLI_addfillvert(e->v2->co);
+ eve->tmp.p = e->v2;
+ BLI_smallhash_insert(&hash, (uintptr_t)e->v2, eve);
+ }
+
+ v1 = BLI_smallhash_lookup(&hash, (uintptr_t)e->v1);
+ v2 = BLI_smallhash_lookup(&hash, (uintptr_t)e->v2);
+ eed = BLI_addfilledge(v1, v2);
+ eed->tmp.p = e;
+ }
+
+ BLI_edgefill(0);
+
+ for (efa = fillfacebase.first; efa; efa = efa->next) {
+ BMFace *f = BM_face_create_quad_tri(bm,
+ efa->v1->tmp.p, efa->v2->tmp.p, efa->v3->tmp.p, NULL,
+ NULL, TRUE);
+ BMLoop *l;
+ BMIter liter;
+
+ BMO_elem_flag_enable(bm, f, ELE_NEW);
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ if (!BMO_elem_flag_test(bm, l->e, EDGE_MARK)) {
+ BMO_elem_flag_enable(bm, l->e, ELE_NEW);
+ }
+ }
+ }
+
+ BLI_end_edgefill();
+ BLI_smallhash_release(&hash);
+
+ /* clean up fill */
+ BMO_op_initf(bm, &bmop, "beautify_fill faces=%ff constrain_edges=%fe", ELE_NEW, EDGE_MARK);
+ BMO_op_exec(bm, &bmop);
+ BMO_slot_buffer_flag_enable(bm, &bmop, "geomout", ELE_NEW, BM_FACE|BM_EDGE);
+ BMO_op_finish(bm, &bmop);
+
+ BMO_slot_from_flag(bm, op, "geomout", ELE_NEW, BM_EDGE|BM_FACE);
+}
diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c
new file mode 100644
index 00000000000..f4dd89e1848
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_utils.c
@@ -0,0 +1,1311 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_meshdata_types.h"
+
+#include "BLI_math.h"
+#include "BLI_array.h"
+#include "BLI_heap.h"
+
+#include "BKE_customdata.h"
+
+#include "bmesh.h"
+
+#include "bmesh_operators_private.h" /* own include */
+
+/*
+ * UTILS.C
+ *
+ * utility bmesh operators, e.g. transform,
+ * translate, rotate, scale, etc.
+ *
+ */
+
+void bmesh_makevert_exec(BMesh *bm, BMOperator *op)
+{
+ float vec[3];
+
+ BMO_slot_vec_get(op, "co", vec);
+
+ BMO_elem_flag_enable(bm, BM_vert_create(bm, vec, NULL), 1);
+ BMO_slot_from_flag(bm, op, "newvertout", 1, BM_VERT);
+}
+
+void bmesh_transform_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter iter;
+ BMVert *v;
+ float mat[4][4];
+
+ BMO_slot_mat4_get(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_slot_vec_get(op, "vec", vec);
+
+ unit_m4(mat);
+ copy_v3_v3(mat[3], vec);
+
+ BMO_op_callf(bm, "transform mat=%m4 verts=%s", mat, op, "verts");
+}
+
+void bmesh_scale_exec(BMesh *bm, BMOperator *op)
+{
+ float mat[3][3], vec[3];
+
+ BMO_slot_vec_get(op, "vec", vec);
+
+ unit_m3(mat);
+ mat[0][0] = vec[0];
+ mat[1][1] = vec[1];
+ mat[2][2] = vec[2];
+
+ BMO_op_callf(bm, "transform mat=%m3 verts=%s", mat, op, "verts");
+}
+
+void bmesh_rotate_exec(BMesh *bm, BMOperator *op)
+{
+ float vec[3];
+
+ BMO_slot_vec_get(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.0f);
+ BMO_op_callf(bm, "translate verts=%s vec=%v", op, "verts", vec);
+
+ BMO_op_callf(bm, "transform mat=%s verts=%s", op, "mat", op, "verts");
+
+ mul_v3_fl(vec, -1.0f);
+ BMO_op_callf(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_face_normal_flip(bm, f);
+ }
+}
+
+void bmesh_edgerotate_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMEdge *e, *e2;
+ int ccw = BMO_slot_int_get(op, "ccw");
+
+ BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
+ if (!(e2 = BM_edge_rotate(bm, e, ccw))) {
+ BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Could not rotate edge");
+ return;
+ }
+
+ BMO_elem_flag_enable(bm, e2, 1);
+ }
+
+ BMO_slot_from_flag(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_elem_flag_test(bm, e, SEL_ORIG))
+ break;
+ }
+
+ if (e) {
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ BMO_elem_flag_enable(bm, e, SEL_FLAG);
+ BMO_elem_flag_enable(bm, BM_edge_other_vert(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_elem_flag_test(bm, f2, SEL_ORIG))
+ BMO_elem_flag_enable(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_elem_flag_test(bm, e, SEL_ORIG))
+ break;
+ }
+
+ if (e) {
+ BMO_elem_flag_enable(bm, v, SEL_FLAG);
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ BMO_elem_flag_enable(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_elem_flag_test(bm, f2, SEL_ORIG)) {
+ BMO_elem_flag_enable(bm, f, SEL_FLAG);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+void bmesh_regionextend_exec(BMesh *bm, BMOperator *op)
+{
+ int usefaces = BMO_slot_int_get(op, "usefaces");
+ int constrict = BMO_slot_int_get(op, "constrict");
+
+ BMO_slot_buffer_flag_enable(bm, op, "geom", SEL_ORIG, BM_ALL);
+
+ if (constrict)
+ bmesh_regionextend_constrict(bm, op, usefaces);
+ else
+ bmesh_regionextend_extend(bm, op, usefaces);
+
+ BMO_slot_from_flag(bm, op, "geomout", SEL_FLAG, BM_ALL);
+}
+
+/********* righthand faces implementation ****** */
+
+#define FACE_VIS 1
+#define FACE_FLAG 2
+#define FACE_MARK 4
+#define FACE_FLIP 8
+
+/* 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. */
+
+/* NOTE: BM_ELEM_TAG is used on faces to tell if they are flipped. */
+
+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, flagflip = BMO_slot_int_get(op, "doflip");
+
+ startf = NULL;
+ maxx = -1.0e10;
+
+ BMO_slot_buffer_flag_enable(bm, op, "faces", FACE_FLAG, BM_FACE);
+
+ /* find a starting face */
+ BMO_ITER(f, &siter, bm, op, "faces", BM_FACE) {
+
+ /* clear dirty flag */
+ BM_elem_flag_disable(f, BM_ELEM_TAG);
+
+ if (BMO_elem_flag_test(bm, f, FACE_VIS))
+ continue;
+
+ if (!startf) startf = f;
+
+ BM_face_center_bounds_calc(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_face_center_bounds_calc(bm, startf, cent);
+
+ /* make sure the starting face has the correct winding */
+ if (dot_v3v3(cent, startf->no) < 0.0f) {
+ BM_face_normal_flip(bm, startf);
+ BMO_elem_flag_toggle(bm, startf, FACE_FLIP);
+
+ if (flagflip)
+ BM_elem_flag_toggle(startf, BM_ELEM_TAG);
+ }
+
+ /* 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_elem_flag_enable(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_elem_flag_test(bm, l2->f, FACE_FLAG) || l2 == l)
+ continue;
+
+ if (!BMO_elem_flag_test(bm, l2->f, FACE_VIS)) {
+ BMO_elem_flag_enable(bm, l2->f, FACE_VIS);
+ i++;
+
+ if (l2->v == l->v) {
+ BM_face_normal_flip(bm, l2->f);
+
+ BMO_elem_flag_toggle(bm, l2->f, FACE_FLIP);
+ if (flagflip)
+ BM_elem_flag_toggle(l2->f, BM_ELEM_TAG);
+ }
+ else if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) || BM_elem_flag_test(l->f, BM_ELEM_TAG)) {
+ if (flagflip) {
+ BM_elem_flag_disable(l->f, BM_ELEM_TAG);
+ BM_elem_flag_disable(l2->f, BM_ELEM_TAG);
+ }
+ }
+
+ 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_elem_flag_test(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_slot_float_get(op, "clipdist");
+ int i, j, clipx, clipy, clipz;
+
+ clipx = BMO_slot_int_get(op, "mirror_clip_x");
+ clipy = BMO_slot_int_get(op, "mirror_clip_y");
+ clipz = BMO_slot_int_get(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_edge_other_vert(e, v)->co;
+ add_v3_v3v3(co, co, co2);
+ j += 1;
+ }
+
+ if (!j) {
+ copy_v3_v3(co, v->co);
+ i++;
+ continue;
+ }
+
+ mul_v3_fl(co, 1.0f / (float)j);
+ mid_v3_v3v3(co, co, v->co);
+
+ if (clipx && fabsf(v->co[0]) <= clipdist)
+ co[0] = 0.0f;
+ if (clipy && fabsf(v->co[1]) <= clipdist)
+ co[1] = 0.0f;
+ if (clipz && fabsf(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 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) {
+ copy_v3_v3(v, l->v->co);
+ copy_v3_v3(sv, l->v->co);
+ }
+ else {
+ perimeter += len_v3v3(v, l->v->co);
+ copy_v3_v3(v, l->v->co);
+ }
+ 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;
+
+ BM_face_center_mean_calc(bm, f, c);
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ if (num_verts == 0) {
+ copy_v3_v3(v, l->v->co);
+ copy_v3_v3(sv, l->v->co);
+ num_verts++;
+ }
+ else {
+ area += area_tri_v3(v, c, l->v->co);
+ copy_v3_v3(v, l->v->co);
+ 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_slot_int_get(op, "type");
+ float thresh = BMO_slot_float_get(op, "thresh");
+
+ num_total = BM_mesh_elem_count(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_elem_flag_test(bm, fs, FACE_MARK)) { /* is this really needed ? */
+ BMO_elem_flag_enable(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_elem_flag_test(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 */
+ BM_face_center_mean_calc(bm, f_ext[i].f, f_ext[i].c);
+
+ /* 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_elem_flag_test(bm, fm, FACE_MARK) && !BM_elem_flag_test(fm, BM_ELEM_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_elem_flag_enable(bm, fm, FACE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMFACE_IMAGE:
+ if (f_ext[i].t == f_ext[indices[idx]].t) {
+ BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMFACE_NORMAL:
+ angle = RAD2DEGF(angle_v3v3(fs->no, fm->no)); /* if the angle between the normals -> 0 */
+ if (angle / 180.0f <= thresh) {
+ BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMFACE_COPLANAR:
+ angle = RAD2DEGF(angle_v3v3(fs->no, fm->no)); /* angle -> 0 */
+ if (angle / 180.0f <= thresh) { /* and dot product difference -> 0 */
+ if (fabsf(f_ext[i].d - f_ext[indices[idx]].d) <= thresh) {
+ BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ cont = 0;
+ }
+ }
+ break;
+
+ case SIMFACE_AREA:
+ if (fabsf(f_ext[i].area - f_ext[indices[idx]].area) <= thresh) {
+ BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMFACE_PERIMETER:
+ if (fabsf(f_ext[i].perim - f_ext[indices[idx]].perim) <= thresh) {
+ BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMFACE_FREESTYLE:
+ if (BM_elem_flag_test(fm, BM_ELEM_FREESTYLE) == BM_elem_flag_test(fs, BM_ELEM_FREESTYLE)) {
+ BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ cont = 0;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ MEM_freeN(f_ext);
+ MEM_freeN(indices);
+
+ /* transfer all marked faces to the output slot */
+ BMO_slot_from_flag(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, *f_prev = NULL;
+
+ /* first edge faces, dont account for 3+ */
+
+ BM_ITER(f, &fiter, bm, BM_FACES_OF_EDGE, e) {
+ if (f_prev == NULL) {
+ f_prev = f;
+ }
+ else {
+ return angle_v3v3(f_prev->no, f->no);
+ }
+ }
+
+ return 0.0f;
+}
+/*
+ * extra edge information
+ */
+typedef struct tmp_edge_ext {
+ BMEdge *e;
+ union {
+ float dir[3];
+ float angle; /* angle between the face */
+ };
+
+ 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_slot_int_get(op, "type");
+ float thresh = BMO_slot_float_get(op, "thresh");
+
+ num_total = BM_mesh_elem_count(bm, BM_EDGE);
+
+ /* iterate through all selected edges and mark them */
+ BMO_ITER(es, &es_iter, bm, op, "edges", BM_EDGE) {
+ BMO_elem_flag_enable(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_elem_flag_test(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_face_count(e_ext[i].e);
+ break;
+
+ case SIMEDGE_FACE_ANGLE:
+ e_ext[i].faces = BM_edge_face_count(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_elem_flag_test(bm, e, EDGE_MARK) && !BM_elem_flag_test(e, BM_ELEM_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 (fabsf(e_ext[i].length - e_ext[indices[idx]].length) <= thresh) {
+ BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMEDGE_DIR:
+ /* compute the angle between the two edges */
+ angle = RAD2DEGF(angle_v3v3(e_ext[i].dir, e_ext[indices[idx]].dir));
+
+ if (angle > 90.0f) /* use the smallest angle between the edges */
+ angle = fabsf(angle - 180.0f);
+
+ if (angle / 90.0f <= thresh) {
+ BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMEDGE_FACE:
+ if (e_ext[i].faces == e_ext[indices[idx]].faces) {
+ BMO_elem_flag_enable(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 (fabsf(e_ext[i].angle - e_ext[indices[idx]].angle) <= thresh) {
+ BMO_elem_flag_enable(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 && fabsf(*c1 - *c2) <= thresh) {
+ BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ cont = 0;
+ }
+ }
+ break;
+
+ case SIMEDGE_SEAM:
+ if (BM_elem_flag_test(e, BM_ELEM_SEAM) == BM_elem_flag_test(es, BM_ELEM_SEAM)) {
+ BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMEDGE_SHARP:
+ if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == BM_elem_flag_test(es, BM_ELEM_SMOOTH)) {
+ BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ cont = 0;
+ }
+ break;
+
+ case SIMEDGE_FREESTYLE:
+ if (BM_elem_flag_test(e, BM_ELEM_FREESTYLE) == BM_elem_flag_test(es, BM_ELEM_FREESTYLE)) {
+ BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ cont = 0;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ MEM_freeN(e_ext);
+ MEM_freeN(indices);
+
+ /* transfer all marked edges to the output slot */
+ BMO_slot_from_flag(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_slot_int_get(op, "type");
+ float thresh = BMO_slot_float_get(op, "thresh");
+
+ num_total = BM_mesh_elem_count(bm, BM_VERT);
+
+ /* iterate through all selected edges and mark them */
+ BMO_ITER(vs, &vs_iter, bm, op, "verts", BM_VERT) {
+ BMO_elem_flag_enable(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_elem_flag_test(bm, v, VERT_MARK)) {
+ indices[idx] = i;
+ idx++;
+ }
+
+ switch (type) {
+ case SIMVERT_FACE:
+ /* calling BM_vert_face_count every time is time consumming, so call it only once per vertex */
+ v_ext[i].num_faces = BM_vert_face_count(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_elem_flag_test(bm, v, VERT_MARK) && !BM_elem_flag_test(v, BM_ELEM_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 (RAD2DEGF(angle_v3v3(v->no, vs->no)) / 180.0f <= thresh) {
+ BMO_elem_flag_enable(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_elem_flag_enable(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_elem_flag_enable(bm, v, VERT_MARK);
+ cont = 0;
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ MEM_freeN(indices);
+ MEM_freeN(v_ext);
+
+ BMO_slot_from_flag(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_slot_int_get(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;
+ copy_v2_v2(p_uv, luv->uv);
+ }
+ else {
+ copy_v2_v2(t_uv, luv->uv);
+ copy_v2_v2(luv->uv, p_uv);
+ copy_v2_v2(p_uv, t_uv);
+ }
+ n++;
+ }
+
+ copy_v2_v2(f_luv->uv, p_uv);
+ }
+ 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;
+ copy_v2_v2(t_uv, luv->uv);
+ }
+ else {
+ copy_v2_v2(p_luv->uv, luv->uv);
+ p_luv = luv;
+ }
+ n++;
+ }
+
+ copy_v2_v2(luv->uv, t_uv);
+ }
+ }
+ }
+
+}
+
+/******************************************************************************
+** 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_slot_int_get(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_slot_int_get(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_mesh_elem_count(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;
+ BM_elem_index_set(v, i); /* set_inline */
+ i++;
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+
+ /*
+ ** we now have everything we need, start Dijkstra path finding algorithm
+ */
+
+ /* set the distance/weight of the start vertex to 0 */
+ vert_list[BM_elem_index_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[BM_elem_index_get(v)].weight == FLT_MAX) /* this means that there is no path */
+ break;
+
+ v_weight = vert_list[BM_elem_index_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[BM_elem_index_get(u)].weight) { /* is this path shorter ? */
+ /* add it if so */
+ vert_list[BM_elem_index_get(u)].parent = v;
+ vert_list[BM_elem_index_get(u)].weight = e_weight;
+
+ /* we should do a heap update node function!!! :-/ */
+ BLI_heap_remove(h, vert_list[BM_elem_index_get(u)].hn);
+ BLI_heap_insert(h, e_weight, u);
+ }
+ }
+ }
+
+ /* now we trace the path (if it exists) */
+ v = ev;
+
+ while (vert_list[BM_elem_index_get(v)].parent != NULL) {
+ BMO_elem_flag_enable(bm, v, VERT_MARK);
+ v = vert_list[BM_elem_index_get(v)].parent;
+ }
+
+ BLI_heap_free(h, NULL);
+ MEM_freeN(vert_list);
+
+ BMO_slot_from_flag(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..b20b7316eb4
--- /dev/null
+++ b/source/blender/bmesh/tools/BME_bevel.c
@@ -0,0 +1,1011 @@
+/*
+ * ***** 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): 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_tessmesh.h"
+#include "BKE_bmesh.h"
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+
+#include "bmesh.h"
+#include "bmesh_private.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, "BME_init_transdata gh");
+ td->ma = BLI_memarena_new(bufsize, "BME_TransData arena");
+ 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) {
+ copy_v3_v3(vtd->co, co);
+ }
+
+ if (org == NULL && is_new) {
+ copy_v3_v3(vtd->org, v->co); /* default */
+ }
+ else if (org != NULL) {
+ copy_v3_v3(vtd->org, org);
+ }
+
+ if (vec != NULL) {
+ copy_v3_v3(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));
+}
+
+/* BM_disk_dissolve is a real mess, and crashes bevel if called instead of this.
+ * The drawback, though, is that this code doesn't merge customdata. */
+static int BME_Bevel_Dissolve_Disk(BMesh *bm, BMVert *v)
+{
+ BMIter iter;
+ BMEdge *e, *elast;
+ BMLoop *l1, *l2;
+
+ if (!BM_vert_is_manifold(bm, v)) {
+ return 0;
+ }
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
+ if (BM_edge_face_count(e) != 2) {
+ return 0;
+ }
+ }
+
+ if (BM_vert_edge_count(v) > 2) {
+ while (BM_vert_edge_count(v) > 2) {
+ e = v->e;
+ l1 = e->l;
+ l2 = l1->radial_next;
+ bmesh_jfke(bm, l1->f, l2->f, e);
+ }
+
+ e = v->e;
+ elast = bmesh_disk_nextedge(e, v);
+ bmesh_jekv(bm, e, v);
+
+ l1 = elast->l;
+ l2 = l1->radial_next;
+ bmesh_jfke(bm, l1->f, l2->f, elast);
+ }
+
+ return 1;
+}
+
+static int BME_bevel_is_split_vert(BMesh *bm, 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 ( !BMO_elem_flag_test(bm, l->v, BME_BEVEL_ORIG) &&
+ BMO_elem_flag_test(bm, l->e, BME_BEVEL_ORIG) &&
+ BMO_elem_flag_test(bm, l->prev->e, 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)) {
+ sub_v3_v3v3(vec, v2->co, v1->co);
+ if (len_v3(vec) < 0.000001f) {
+ zero_v3(vec);
+ }
+ return 0;
+ }
+ else {
+ sub_v3_v3v3(vec, vtd2->org, vtd1->org);
+ if (len_v3(vec) < 0.000001f) {
+ zero_v3(vec);
+ }
+ 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 *UNUSED(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 (fabsf(c1) < 0.000001f || fabsf(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_edge_other_vert(e1, v);
+ v3 = BM_edge_other_vert(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_edge_other_vert(e1, v);
+ sv = BM_edge_split(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 */
+ BMO_elem_flag_enable(bm, sv, BME_BEVEL_BEVEL);
+ BMO_elem_flag_enable(bm, ne, 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(bm, lv1)) {
+ is_split_vert = 1;
+ sv = v1;
+ v1 = forward ? l->next->next->v : l->prev->v;
+ }
+ else {
+ is_split_vert = 0;
+ ov = BM_edge_other_vert(l->e, v);
+ sv = BM_edge_split(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 */
+ BMO_elem_flag_enable(bm, sv, BME_BEVEL_BEVEL);
+ BMO_elem_flag_enable(bm, ne, BME_BEVEL_ORIG); /* mark edge as original, even though it isn't */
+ }
+
+ if (BME_bevel_is_split_vert(bm, lv2)) {
+ v2 = forward ? lv2->prev->v : 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 = BMO_elem_flag_test(bm, v1, BME_BEVEL_ORIG) ? len / 3 : len / 2;
+ if (is_edge || dis > maxfactor * value) {
+ dis = maxfactor * value;
+ }
+ madd_v3_v3v3fl(sv->co, v->co, vec1, dis);
+ sub_v3_v3v3(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;
+}
+
+#if 0 /* UNUSED */
+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 {
+ copy_v3_v3(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 {
+ copy_v3_v3(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;
+}
+#endif
+
+#if 0 /* UNUSED */
+static BMVert *BME_bevel_wire(BMesh *bm, BMVert *v, float value, int res, int UNUSED(options), BME_TransData_Head *td)
+{
+ BMVert *ov1, *ov2, *v1, *v2;
+
+ ov1 = BM_edge_other_vert(v->e, v);
+ ov2 = BM_edge_other_vert(bmesh_disk_nextedge(v->e, v), v);
+
+ /* split the edges */
+ v1 = BME_bevel_split_edge(bm, v, ov1, NULL, NULL, value, td);
+ BMO_elem_flag_enable(bm, v1, BME_BEVEL_NONMAN);
+ v2 = BME_bevel_split_edge(bm, v, ov2, NULL, NULL, value, td);
+ BMO_elem_flag_enable(bm, v2, 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_vert_collapse_faces(BMesh *bm, BMEdge *ke, BMVert *kv, float fac, int calcnorm){
+ //hrm, why is there a fac here? it just removes a vert
+ BM_vert_collapse_edges(bm, v->e, v);
+ }
+
+ return v1;
+}
+#endif
+
+static BMLoop *BME_bevel_edge(BMesh *bm, BMLoop *l, float value, int UNUSED(options), float *up_vec, BME_TransData_Head *td)
+{
+ BMVert *v1, *v2, *kv;
+ BMLoop *kl = NULL, *nl;
+ BMEdge *e, *ke, *se;
+ BMFace *f, *jf;
+
+ f = l->f;
+ e = l->e;
+
+ /* sanity check */
+ if ( !BMO_elem_flag_test(bm, l->e, BME_BEVEL_BEVEL) &&
+ (BMO_elem_flag_test(bm, l->v, BME_BEVEL_BEVEL) || BMO_elem_flag_test(bm, l->next->v, BME_BEVEL_BEVEL)))
+ {
+ return l;
+ }
+
+ /* checks and operations for prev edge */
+ /* first, check to see if this edge was inset previously */
+ if ( !BMO_elem_flag_test(bm, l->prev->e, BME_BEVEL_ORIG) &&
+ !BMO_elem_flag_test(bm, l->v, BME_BEVEL_NONMAN))
+ {
+ kl = l->prev->radial_next;
+ kl = (kl->v == l->v) ? kl->prev : kl->next;
+ kv = l->v;
+ }
+ else {
+ kv = NULL;
+ }
+ /* get/make the first vert to be used in SFME */
+ if (BMO_elem_flag_test(bm, l->v, 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) {
+ se = l->next->e;
+ jf = NULL;
+ if (kl->v == kv) {
+ BM_face_split(bm, kl->f, kl->prev->v, kl->next->v, &nl, kl->prev->e);
+ ke = kl->e;
+ /* BMESH-TODO: jfke doesn't handle customdata */
+ jf = bmesh_jfke(bm, kl->prev->radial_next->f, kl->f, kl->prev->e);
+ BM_vert_collapse_edges(bm, ke, kv);
+ }
+ else {
+ BM_face_split(bm, kl->f, kl->next->next->v, kl->v, &nl, kl->next->e);
+ ke = kl->e;
+ /* BMESH-TODO: jfke doesn't handle customdata */
+ jf = bmesh_jfke(bm, kl->next->radial_next->f, kl->f, kl->next->e);
+ BM_vert_collapse_edges(bm, ke, kv);
+ }
+ /* find saved loop pointer */
+ l = se->l;
+ while (l->f != jf) {
+ l = bmesh_radial_nextloop(l);
+ BLI_assert(l != se->l);
+ }
+ l = l->prev;
+ }
+
+ /* checks and operations for the next edge */
+ /* first, check to see if this edge was inset previously */
+ if ( !BMO_elem_flag_test(bm, l->next->e, BME_BEVEL_ORIG) &&
+ !BMO_elem_flag_test(bm, l->next->v, BME_BEVEL_NONMAN))
+ {
+ kl = l->next->radial_next;
+ kl = (kl->v == l->next->v) ? kl->prev : kl->next;
+ kv = l->next->v;
+ }
+ else {
+ kv = NULL;
+ }
+ /* get/make the second vert to be used in SFME */
+ if (BMO_elem_flag_test(bm, l->next->v, 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) {
+ se = l->e;
+ jf = NULL;
+ if (kl->v == kv) {
+ BM_face_split(bm, kl->f, kl->prev->v, kl->next->v, &nl, kl->prev->e);
+ ke = kl->e;
+ /* BMESH-TODO: jfke doesn't handle customdata */
+ jf = bmesh_jfke(bm, kl->prev->radial_next->f, kl->f, kl->prev->e);
+ BM_vert_collapse_edges(bm, ke, kv);
+ }
+ else {
+ BM_face_split(bm, kl->f, kl->next->next->v, kl->v, &nl, kl->next->e);
+ ke = kl->e;
+ /* BMESH-TODO: jfke doesn't handle customdata */
+ jf = bmesh_jfke(bm, kl->next->radial_next->f, kl->f, kl->next->e);
+ BM_vert_collapse_edges(bm, ke, kv);
+ }
+ /* find saved loop pointer */
+ l = se->l;
+ while (l->f != jf) {
+ l = bmesh_radial_nextloop(l);
+ BLI_assert(l != se->l);
+ }
+ }
+
+ if (!BMO_elem_flag_test(bm, v1, BME_BEVEL_NONMAN) || !BMO_elem_flag_test(bm, v2, BME_BEVEL_NONMAN)) {
+ BM_face_split(bm, f, v2, v1, &l, e);
+ BMO_elem_flag_enable(bm, l->e, 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 UNUSED(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_face_split(bm, l->f, v2, v1, NULL, l->e);
+
+ return l;
+}
+
+/*
+ * BME_bevel_poly
+ *
+ * Polygon inset tool:
+ *
+ * Insets a polygon/face based on the flagss 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/*, *o */;
+ BME_TransData *vtd1, *vtd2;
+ float up_vec[3], vec1[3], vec2[3], vec3[3], fac1, fac2, max = -1;
+ int len, i;
+ BMIter iter;
+
+ zero_v3(up_vec);
+
+ /* find a good normal for this face (there's better ways, I'm sure) */
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
+ BME_bevel_get_vec(vec1, l->v, l->next->v, td);
+ BME_bevel_get_vec(vec2, l->prev->v, l->v, td);
+ cross_v3_v3v3(vec3, vec2, vec1);
+ add_v3_v3(up_vec, vec3);
+ }
+ normalize_v3(up_vec);
+
+ /* Can't use a BM_LOOPS_OF_FACE iterator here, because the loops are being modified
+ * and so the end condition will never hi */
+ for (l = BM_FACE_FIRST_LOOP(f)->prev, i = 0, len = f->len; i < len; i++, l = l->next) {
+ if (BMO_elem_flag_test(bm, l->e, BME_BEVEL_BEVEL) && BMO_elem_flag_test(bm, l->e, BME_BEVEL_ORIG)) {
+ max = 1.0f;
+ l = BME_bevel_edge(bm, l, value, options, up_vec, td);
+ }
+ else if ( BMO_elem_flag_test(bm, l->v, BME_BEVEL_BEVEL) &&
+ BMO_elem_flag_test(bm, l->v, BME_BEVEL_ORIG) &&
+ !BMO_elem_flag_test(bm, l->prev->e, BME_BEVEL_BEVEL))
+ {
+ max = 1.0f;
+ l = BME_bevel_vert(bm, l, value, options, up_vec, td);
+ }
+ }
+
+ f = l->f;
+
+ /* max pass */
+ if (value > 0.5f && max > 0) {
+ max = -1;
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
+ if (BMO_elem_flag_test(bm, l->e, BME_BEVEL_BEVEL) || BMO_elem_flag_test(bm, l->e, 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 {
+ copy_v3_v3(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 {
+ copy_v3_v3(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; */
+ return NULL;
+}
+
+static void BME_bevel_add_vweight(BME_TransData_Head *td, BMesh *bm, BMVert *v, float weight, float factor, int options)
+{
+ BME_TransData *vtd;
+
+ if (BMO_elem_flag_test(bm, v, BME_BEVEL_NONMAN)) return;
+ BMO_elem_flag_enable(bm, v, 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 void bevel_init_verts(BMesh *bm, int options, BME_TransData_Head *td)
+{
+ BMVert *v;
+ BMIter iter;
+ float weight;
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ weight = 0.0;
+ if (!BMO_elem_flag_test(bm, v, BME_BEVEL_NONMAN)) {
+ /* modifiers should not use selection */
+ if(options & BME_BEVEL_SELECT){
+ if(BM_elem_flag_test(v, BM_ELEM_SELECT)) weight = 1.0;
+ }
+ /* bevel weight NYI */
+ else if(options & BME_BEVEL_WEIGHT)
+ weight = BM_elem_float_data_get(&bm->vdata, v, CD_BWEIGHT);
+ else
+ weight = 1.0;
+ if(weight > 0.0){
+ BMO_elem_flag_enable(bm, v, BME_BEVEL_BEVEL);
+ BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 1.0, weight, -1, NULL);
+ }
+ }
+ }
+}
+
+static void bevel_init_edges(BMesh *bm, int options, BME_TransData_Head *td)
+{
+ BMEdge *e;
+ int count;
+ float weight;
+ BMIter iter;
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ weight = 0.0;
+ if (!BMO_elem_flag_test(bm, e, BME_BEVEL_NONMAN)) {
+ if(options & BME_BEVEL_SELECT){
+ if(BM_elem_flag_test(e, BM_ELEM_SELECT)) weight = 1.0;
+ }
+ else if(options & BME_BEVEL_WEIGHT) {
+ weight = BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT);
+ }
+ else {
+ weight = 1.0;
+ }
+ if(weight > 0.0){
+ BMO_elem_flag_enable(bm, e, BME_BEVEL_BEVEL);
+ BMO_elem_flag_enable(bm, e->v1, BME_BEVEL_BEVEL);
+ BMO_elem_flag_enable(bm, e->v2, 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 edg */
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if(BMO_elem_flag_test(bm, e, BME_BEVEL_BEVEL)) {
+ count = BM_face_share_edges(e->l->f, e->l->radial_next->f);
+ if(count > 1) BMO_elem_flag_disable(bm, e, BME_BEVEL_BEVEL);
+ }
+ }
+}
+
+static BMesh *BME_bevel_initialize(BMesh *bm, int options, int UNUSED(defgrp_index), float UNUSED(angle), BME_TransData_Head *td)
+{
+ BMVert *v/*, *v2 */;
+ BMEdge *e/*, *curedg */;
+ BMFace *f;
+ BMIter iter;
+ int /* wire, */ len;
+
+ /* tag non-manifold geometr */
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BMO_elem_flag_enable(bm, v, BME_BEVEL_ORIG);
+ if(v->e){
+ BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 0, -1, -1, NULL);
+ if (!BM_vert_is_manifold(bm, v))
+ BMO_elem_flag_enable(bm, v, BME_BEVEL_NONMAN);
+ /* test wire ver */
+ len = BM_vert_edge_count(v);
+ if (len == 2 && BM_vert_is_wire(bm, v))
+ BMO_elem_flag_disable(bm, v, BME_BEVEL_NONMAN);
+ }
+ else
+ BMO_elem_flag_enable(bm, v, BME_BEVEL_NONMAN);
+ }
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ BMO_elem_flag_enable(bm, e, BME_BEVEL_ORIG);
+ if (!BM_edge_is_manifold(bm, e)) {
+ BMO_elem_flag_enable(bm, e->v1, BME_BEVEL_NONMAN);
+ BMO_elem_flag_enable(bm, e->v2, BME_BEVEL_NONMAN);
+ BMO_elem_flag_enable(bm, e, BME_BEVEL_NONMAN);
+ }
+ if(BMO_elem_flag_test(bm, e->v1, BME_BEVEL_NONMAN) || BMO_elem_flag_test(bm, e->v2, BME_BEVEL_NONMAN)) BMO_elem_flag_enable(bm, e, BME_BEVEL_NONMAN);
+ }
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL)
+ BMO_elem_flag_enable(bm, f, BME_BEVEL_ORIG);
+ if(options & BME_BEVEL_VERT) bevel_init_verts(bm, options, td);
+ else bevel_init_edges(bm, options, td);
+ return bm;
+
+}
+
+#if 0
+
+static BMesh *BME_bevel_reinitialize(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+ BMIter iter;
+
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BMO_elem_flag_enable(bm, v, BME_BEVEL_ORIG);
+ }
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ BMO_elem_flag_enable(bm, e, BME_BEVEL_ORIG);
+ }
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BMO_elem_flag_enable(bm, f, BME_BEVEL_ORIG);
+ }
+ return bm;
+
+}
+
+#endif
+
+/**
+ * BME_bevel_mesh
+ *
+ * Mesh beveling tool:
+ *
+ * Bevels an entire mesh. It currently uses the flags 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 BMesh *BME_bevel_mesh(BMesh *bm, float value, int UNUSED(res), int options, int UNUSED(defgrp_index), BME_TransData_Head *td)
+{
+ BMVert *v;
+ BMEdge *e, *curedge;
+ BMLoop *l, *l2;
+ BMFace *f;
+ BMIter iter;
+
+ /* unsigned int i, len; */
+
+ /* bevel poly */
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if(BMO_elem_flag_test(bm, f, BME_BEVEL_ORIG)) {
+ BME_bevel_poly(bm, f, value, options, td);
+ }
+ }
+
+ /* get rid of beveled edge */
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if(BMO_elem_flag_test(bm, e, BME_BEVEL_BEVEL) && BMO_elem_flag_test(bm, e, BME_BEVEL_ORIG)) {
+ BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e);
+ }
+ }
+
+ /* link up corners and cli */
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(BMO_elem_flag_test(bm, v, BME_BEVEL_ORIG) && BMO_elem_flag_test(bm, 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_face_split(bm, l->f, l->next->v, l->prev->v, &l, l->e); /* clip this corner off */
+ if(l2->f->len > 3)
+ BM_face_split(bm, l2->f, l2->next->v, l2->prev->v, &l, l2->e); /* clip this corner off */
+ curedge = bmesh_disk_nextedge(curedge, v);
+ } while(curedge != v->e);
+ BME_Bevel_Dissolve_Disk(bm, v);
+ }
+ }
+
+ /* Debug print, remov */
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if(f->len == 2){
+ printf("warning");
+ }
+ }
+
+ return bm;
+}
+
+BMesh *BME_bevel(BMEditMesh *em, float value, int res, int options, int defgrp_index, float angle, BME_TransData_Head **rtd)
+{
+ BMesh *bm = em->bm;
+ BMVert *v;
+ BMIter iter;
+
+ 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++) {
+ BMO_push(bm, NULL);
+ BME_bevel_initialize(bm, options, defgrp_index, angle, td);
+ //if (i != 0) BME_bevel_reinitialize(bm);
+ bmesh_begin_edit(bm, 0);
+ BME_bevel_mesh(bm, (float)d, res, options, defgrp_index, td);
+ bmesh_end_edit(bm, 0);
+ d /= (i == 0) ? 3.0 : 2.0;
+ BMO_pop(bm);
+ }
+
+ BMEdit_RecalcTesselation(em);
+
+ /* interactive preview? */
+ if (rtd) {
+ *rtd = td;
+ return bm;
+ }
+
+ /* otherwise apply transforms */
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if ( (vtd = BME_get_transdata(td, v)) ) {
+ if (vtd->max && (*vtd->max > 0 && value > *vtd->max)) {
+ d = *vtd->max;
+ }
+ else {
+ d = value;
+ }
+ madd_v3_v3v3fl(v->co, vtd->org, vtd->vec, vtd->factor * d);
+ }
+ }
+
+ BME_free_transdata(td);
+ return bm;
+}
diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp
index 0e89f2db74b..9399ce6771d 100644
--- a/source/blender/collada/ArmatureExporter.cpp
+++ b/source/blender/collada/ArmatureExporter.cpp
@@ -43,6 +43,7 @@
#include "GeometryExporter.h"
#include "ArmatureExporter.h"
+#include "SceneExporter.h"
// XXX exporter writes wrong data for shared armatures. A separate
// controller should be written for each armature-mesh binding how do
@@ -50,14 +51,16 @@
ArmatureExporter::ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryControllers(sw), export_settings(export_settings) {}
// write bone nodes
-void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene *sce)
+void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene* sce,
+ SceneExporter* se,
+ std::list<Object*>& child_objects)
{
// write bone nodes
bArmature *arm = (bArmature*)ob_arm->data;
for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) {
// start from root bones
if (!bone->parent)
- add_bone_node(bone, ob_arm);
+ add_bone_node(bone, ob_arm, sce, se, child_objects);
}
}
@@ -163,7 +166,9 @@ std::string ArmatureExporter::get_joint_sid(Bone *bone, Object *ob_arm)
}
// parent_mat is armature-space
-void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm)
+void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene* sce,
+ SceneExporter* se,
+ std::list<Object*>& child_objects)
{
std::string node_id = get_joint_id(bone, ob_arm);
std::string node_name = std::string(bone->name);
@@ -183,14 +188,54 @@ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm)
add_bone_transform(ob_arm, bone, node);
+ // Write nodes of childobjects, remove written objects from list
+ std::list<Object*>::iterator i = child_objects.begin();
+
+ while( i != child_objects.end() )
+ {
+ if((*i)->partype == PARBONE && (0 == strcmp((*i)->parsubstr, bone->name)))
+ {
+ float backup_parinv[4][4];
+
+ // SECOND_LIFE_COMPATIBILITY
+ // crude, temporary change to parentinv
+ // so transform gets exported correctly.
+ // TODO: when such objects are animated as
+ // single matrix the tweak must be applied
+ // to the result.
+ if(export_settings->second_life)
+ {
+ copy_m4_m4(backup_parinv, (*i)->parentinv);
+ // tweak objects parentinverse to match
+ // the second life- compatibility
+ float temp[4][4];
+
+ copy_m4_m4(temp, bone->arm_mat);
+ temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
+
+ mult_m4_m4m4((*i)->parentinv, temp, backup_parinv);
+ }
+
+ se->writeNodes(*i, sce);
+
+ // restore original parentinv
+ if(export_settings->second_life)
+ {
+ copy_m4_m4((*i)->parentinv, backup_parinv);
+ }
+ child_objects.erase(i++);
+ }
+ else i++;
+ }
+
for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next) {
- add_bone_node(child, ob_arm);
+ add_bone_node(child, ob_arm, sce, se, child_objects);
}
node.end();
//}
}
-void ArmatureExporter::add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADASW::Node& node)
+/*void ArmatureExporter::add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADASW::Node& node)
{
node.start();
@@ -201,11 +246,11 @@ void ArmatureExporter::add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADA
node.addExtraTechniqueParameter("blender", "tip_z", bone->tail[2] );
for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next) {
- add_bone_node(child, ob_arm);
+ add_bone_node(child, ob_arm, sce, se, child_objects);
}
node.end();
-}
+}*/
void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node)
{
bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
@@ -296,10 +341,64 @@ void ArmatureExporter::export_controller(Object* ob, Object *ob_arm)
std::string joints_source_id = add_joints_source(ob_arm, &ob->defbase, controller_id);
std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, &ob->defbase, controller_id);
- std::string weights_source_id = add_weights_source(me, controller_id);
+ std::list<int> vcounts;
+ std::list<int> joints;
+ std::list<float> weights;
+
+ {
+ int i, j;
+
+ // def group index -> joint index
+ std::vector<int> joint_index_by_def_index;
+ bDeformGroup *def;
+
+ for (def = (bDeformGroup*)ob->defbase.first, i = 0, j = 0; def; def = def->next, i++) {
+ if (is_bone_defgroup(ob_arm, def))
+ joint_index_by_def_index.push_back(j++);
+ else
+ joint_index_by_def_index.push_back(-1);
+ }
+
+ for (i = 0; i < me->totvert; i++) {
+ MDeformVert *vert = &me->dvert[i];
+ std::map<int, float> jw;
+
+ // We're normalizing the weights later
+ float sumw = 0.0f;
+
+ for (j = 0; j < vert->totweight; j++) {
+ int joint_index = joint_index_by_def_index[vert->dw[j].def_nr];
+ if(joint_index != -1 && vert->dw[j].weight > 0.0f)
+ {
+ jw[joint_index] += vert->dw[j].weight;
+ sumw += vert->dw[j].weight;
+ }
+ }
+
+ if(sumw > 0.0f)
+ {
+ float invsumw = 1.0f/sumw;
+ vcounts.push_back(jw.size());
+ for(std::map<int, float>::iterator m = jw.begin(); m != jw.end(); ++m)
+ {
+ joints.push_back((*m).first);
+ weights.push_back(invsumw*(*m).second);
+ }
+ }
+ else
+ {
+ vcounts.push_back(0);
+ /*vcounts.push_back(1);
+ joints.push_back(-1);
+ weights.push_back(1.0f);*/
+ }
+ }
+ }
+
+ std::string weights_source_id = add_weights_source(me, controller_id, weights);
add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id);
- add_vertex_weights_element(weights_source_id, joints_source_id, me, ob_arm, &ob->defbase);
+ add_vertex_weights_element(weights_source_id, joints_source_id, vcounts, joints);
closeSkin();
closeController();
@@ -445,21 +544,14 @@ bool ArmatureExporter::is_bone_defgroup(Object *ob_arm, bDeformGroup* def)
return get_bone_from_defgroup(ob_arm, def) != NULL;
}
-std::string ArmatureExporter::add_weights_source(Mesh *me, const std::string& controller_id)
+std::string ArmatureExporter::add_weights_source(Mesh *me, const std::string& controller_id, const std::list<float>& weights)
{
std::string source_id = controller_id + WEIGHTS_SOURCE_ID_SUFFIX;
- int i;
- int totweight = 0;
-
- for (i = 0; i < me->totvert; i++) {
- totweight += me->dvert[i].totweight;
- }
-
COLLADASW::FloatSourceF source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(totweight);
+ source.setAccessorCount(weights.size());
source.setAccessorStride(1);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
@@ -467,13 +559,8 @@ std::string ArmatureExporter::add_weights_source(Mesh *me, const std::string& co
source.prepareToAppendValues();
- // NOTE: COLLADA spec says weights should be normalized
-
- for (i = 0; i < me->totvert; i++) {
- MDeformVert *vert = &me->dvert[i];
- for (int j = 0; j < vert->totweight; j++) {
- source.appendValues(vert->dw[j].weight);
- }
+ for(std::list<float>::const_iterator i = weights.begin(); i != weights.end(); ++i) {
+ source.appendValues(*i);
}
source.finish();
@@ -481,11 +568,12 @@ std::string ArmatureExporter::add_weights_source(Mesh *me, const std::string& co
return source_id;
}
-void ArmatureExporter::add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, Mesh *me,
- Object *ob_arm, ListBase *defbase)
+void ArmatureExporter::add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id,
+ const std::list<int>& vcounts,
+ const std::list<int>& joints)
{
- COLLADASW::VertexWeightsElement weights(mSW);
- COLLADASW::InputList &input = weights.getInputList();
+ COLLADASW::VertexWeightsElement weightselem(mSW);
+ COLLADASW::InputList &input = weightselem.getInputList();
int offset = 0;
input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::JOINT, // constant declared in COLLADASWInputList.h
@@ -493,40 +581,25 @@ void ArmatureExporter::add_vertex_weights_element(const std::string& weights_sou
input.push_back(COLLADASW::Input(COLLADASW::InputSemantic::WEIGHT,
COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, weights_source_id), offset++));
- weights.setCount(me->totvert);
+ weightselem.setCount(vcounts.size());
// write number of deformers per vertex
- COLLADASW::PrimitivesBase::VCountList vcount;
- int i;
- for (i = 0; i < me->totvert; i++) {
- vcount.push_back(me->dvert[i].totweight);
- }
+ COLLADASW::PrimitivesBase::VCountList vcountlist;
- weights.prepareToAppendVCountValues();
- weights.appendVertexCount(vcount);
+ vcountlist.resize(vcounts.size());
+ std::copy(vcounts.begin(), vcounts.end(), vcountlist.begin());
- // def group index -> joint index
- std::map<int, int> joint_index_by_def_index;
- bDeformGroup *def;
- int j;
- for (def = (bDeformGroup*)defbase->first, i = 0, j = 0; def; def = def->next, i++) {
- if (is_bone_defgroup(ob_arm, def))
- joint_index_by_def_index[i] = j++;
- else
- joint_index_by_def_index[i] = -1;
- }
+ weightselem.prepareToAppendVCountValues();
+ weightselem.appendVertexCount(vcountlist);
- weights.CloseVCountAndOpenVElement();
+ weightselem.CloseVCountAndOpenVElement();
// write deformer index - weight index pairs
int weight_index = 0;
- for (i = 0; i < me->totvert; i++) {
- MDeformVert *dvert = &me->dvert[i];
- for (int j = 0; j < dvert->totweight; j++) {
- weights.appendValues(joint_index_by_def_index[dvert->dw[j].def_nr]);
- weights.appendValues(weight_index++);
- }
+ for(std::list<int>::const_iterator i = joints.begin(); i != joints.end(); ++i)
+ {
+ weightselem.appendValues(*i, weight_index++);
}
- weights.finish();
+ weightselem.finish();
}
diff --git a/source/blender/collada/ArmatureExporter.h b/source/blender/collada/ArmatureExporter.h
index 925e65c9b69..e9ee38d36cf 100644
--- a/source/blender/collada/ArmatureExporter.h
+++ b/source/blender/collada/ArmatureExporter.h
@@ -28,6 +28,7 @@
#ifndef __ARMATUREEXPORTER_H__
#define __ARMATUREEXPORTER_H__
+#include <list>
#include <string>
//#include <vector>
@@ -47,6 +48,8 @@
#include "ExportSettings.h"
+class SceneExporter;
+
// XXX exporter writes wrong data for shared armatures. A separate
// controller should be written for each armature-mesh binding how do
// we make controller ids then?
@@ -56,7 +59,8 @@ public:
ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
// write bone nodes
- void add_armature_bones(Object *ob_arm, Scene *sce);
+ void add_armature_bones(Object *ob_arm, Scene* sce, SceneExporter* se,
+ std::list<Object*>& child_objects);
bool is_skinned_mesh(Object *ob);
@@ -85,8 +89,10 @@ private:
std::string get_joint_sid(Bone *bone, Object *ob_arm);
- // parent_mat is armature-space
- void add_bone_node(Bone *bone, Object *ob_arm);
+ // Scene, SceneExporter and the list of child_objects
+ // are required for writing bone parented objects
+ void add_bone_node(Bone *bone, Object *ob_arm, Scene* sce, SceneExporter* se,
+ std::list<Object*>& child_objects);
void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node);
@@ -111,10 +117,11 @@ private:
bool is_bone_defgroup(Object *ob_arm, bDeformGroup* def);
- std::string add_weights_source(Mesh *me, const std::string& controller_id);
+ std::string add_weights_source(Mesh *me, const std::string& controller_id,
+ const std::list<float>& weights);
- void add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, Mesh *me,
- Object *ob_arm, ListBase *defbase);
+ void add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id,
+ const std::list<int>& vcount, const std::list<int>& joints);
};
#endif
diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp
index 4a838e928da..8dffb17a19f 100644
--- a/source/blender/collada/GeometryExporter.cpp
+++ b/source/blender/collada/GeometryExporter.cpp
@@ -322,8 +322,8 @@ std::string GeometryExporter::makeTexcoordSourceId(std::string& geom_id, int lay
void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
{
#if 0
- int totfaces = dm->getNumFaces(dm);
- MFace *mfaces = dm->getFaceArray(dm);
+ int totfaces = dm->getNumTessFaces(dm);
+ MFace *mfaces = dm->getTessFaceArray(dm);
#endif
int totfaces = me->totface;
MFace *mfaces = me->mface;
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 1e5783f8ad0..ebfeb0c6301 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -746,6 +746,9 @@ MTex *MeshImporter::assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBindi
const CustomData *data = &me->fdata;
int layer_index = CustomData_get_layer_index(data, CD_MTFACE);
+
+ if(layer_index == -1) return NULL;
+
CustomDataLayer *cdl = &data->layers[layer_index+setindex];
/* set uvname to bind_vertex_input semantic */
@@ -958,8 +961,8 @@ bool MeshImporter::write_geometry(const COLLADAFW::Geometry* geom)
read_faces(mesh, me, new_tris);
make_edges(me, 0);
-
- mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+
+ mesh_calc_normals_mapping(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL);
return true;
}
diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp
index 5dd452faa41..b6be8a57f7a 100644
--- a/source/blender/collada/SceneExporter.cpp
+++ b/source/blender/collada/SceneExporter.cpp
@@ -77,6 +77,29 @@ void SceneExporter::writeNodes(Object *ob, Scene *sce)
node.start();
bool is_skinned_mesh = arm_exporter->is_skinned_mesh(ob);
+ std::list<Object*> child_objects;
+
+ // list child objects
+ Base *b = (Base*) sce->base.first;
+ while(b) {
+ // cob - child object
+ Object *cob = b->object;
+
+ if (cob->parent == ob) {
+ switch(cob->type) {
+ case OB_MESH:
+ case OB_CAMERA:
+ case OB_LAMP:
+ case OB_EMPTY:
+ case OB_ARMATURE:
+ child_objects.push_back(cob);
+ break;
+ }
+ }
+
+ b = b->next;
+ }
+
if (ob->type == OB_MESH && is_skinned_mesh)
// for skinned mesh we write obmat in <bind_shape_matrix>
@@ -101,7 +124,7 @@ void SceneExporter::writeNodes(Object *ob, Scene *sce)
// <instance_controller>
else if (ob->type == OB_ARMATURE) {
- arm_exporter->add_armature_bones(ob, sce);
+ arm_exporter->add_armature_bones(ob, sce, this, child_objects);
// XXX this looks unstable...
node.end();
@@ -131,28 +154,12 @@ void SceneExporter::writeNodes(Object *ob, Scene *sce)
}
}
- // write nodes for child objects
- Base *b = (Base*) sce->base.first;
- while(b) {
- // cob - child object
- Object *cob = b->object;
-
- if (cob->parent == ob) {
- switch(cob->type) {
- case OB_MESH:
- case OB_CAMERA:
- case OB_LAMP:
- case OB_EMPTY:
- case OB_ARMATURE:
- // write node...
- writeNodes(cob, sce);
- break;
- }
- }
-
- b = b->next;
+ for(std::list<Object*>::iterator i= child_objects.begin(); i != child_objects.end(); ++i)
+ {
+ writeNodes(*i, sce);
}
+
if (ob->type != OB_ARMATURE)
node.end();
}
diff --git a/source/blender/collada/SceneExporter.h b/source/blender/collada/SceneExporter.h
index de01eb6e459..31b471a3e4c 100644
--- a/source/blender/collada/SceneExporter.h
+++ b/source/blender/collada/SceneExporter.h
@@ -97,6 +97,8 @@ public:
void exportScene(Scene *sce);
private:
+ // required for writeNodes() for bone-parented objects
+ friend class ArmatureExporter;
void exportHierarchy(Scene *sce);
void writeNodes(Object *ob, Scene *sce);
diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp
index c806cd48587..0cf26a03107 100644
--- a/source/blender/collada/TransformWriter.cpp
+++ b/source/blender/collada/TransformWriter.cpp
@@ -95,20 +95,24 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob)
*/
/* Using parentinv should allow use of existing curves */
- // If parentinv is identity don't add it.
- bool add_parinv = false;
- for(int i = 0; i < 16; ++i)
+ if(ob->parent)
{
- float f = (i%4 == i/4) ? 1.0f : 0.0f ;
- if(ob->parentinv[i%4][i/4] != f) add_parinv = true;
- }
-
- if(add_parinv && ob->parent)
- {
- double dmat[4][4];
- UnitConverter converter;
- converter.mat4_to_dae_double(dmat, ob->parentinv);
- node.addMatrix("parentinverse", dmat);
+ // If parentinv is identity don't add it.
+ bool add_parinv = false;
+
+ for(int i = 0; i < 16; ++i)
+ {
+ float f = (i%4 == i/4) ? 1.0f : 0.0f ;
+ add_parinv |= (ob->parentinv[i%4][i/4] != f);
+ }
+
+ if(add_parinv)
+ {
+ double dmat[4][4];
+ UnitConverter converter;
+ converter.mat4_to_dae_double(dmat, ob->parentinv);
+ node.addMatrix("parentinverse", dmat);
+ }
}
add_transform(node, ob->loc, ob->rot, ob->size);
diff --git a/source/blender/editors/animation/SConscript b/source/blender/editors/animation/SConscript
index 96b05b8bccc..3e5133c1174 100644
--- a/source/blender/editors/animation/SConscript
+++ b/source/blender/editors/animation/SConscript
@@ -4,6 +4,6 @@ Import ('env')
sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../makesrna ../../imbuf'
-incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include ../../blenloader'
+incs += ' ../../bmesh ../../windowmanager #/intern/guardedalloc #/extern/glew/include ../../blenloader'
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 ded82b3dfb7..b85a13ced85 100644
--- a/source/blender/editors/armature/SConscript
+++ b/source/blender/editors/armature/SConscript
@@ -5,6 +5,7 @@ sources = env.Glob('*.c')
incs = '../include ../../blenfont ../../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'] == 'linux':
diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c
index e8c9a2cf4da..e16063b50c6 100644
--- a/source/blender/editors/armature/editarmature.c
+++ b/source/blender/editors/armature/editarmature.c
@@ -2126,7 +2126,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 *UNUSED(data))
{
UndoArmature *uarm= uarmv;
bArmature *arm= armv;
@@ -2159,7 +2159,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 *UNUSED(obdata))
{
bArmature *arm= armv;
UndoArmature *uarm;
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 005f5f6da95..bb493d3fec4 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -41,14 +41,15 @@
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
+#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_edgehash.h"
#include "BLI_memarena.h"
-#include "BLI_utildefines.h"
#include "BLI_string.h"
#include "BKE_DerivedMesh.h"
#include "BKE_modifier.h"
+#include "BKE_mesh.h"
#ifdef RIGID_DEFORM
@@ -651,10 +652,12 @@ static float heat_limit_weight(float weight)
void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], int *selected, const char **err_str)
{
LaplacianSystem *sys;
- MFace *mface;
+ MPoly *mp;
+ MLoop *ml;
+ MFace *mf;
float solution, weight;
int *vertsflipped = NULL, *mask= NULL;
- int a, totface, j, bbone, firstsegment, lastsegment;
+ int a, tottri, j, bbone, firstsegment, lastsegment;
MVert *mvert = me->mvert;
int use_vert_sel= FALSE;
@@ -669,33 +672,34 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
mask= MEM_callocN(sizeof(int)*me->totvert, "heat_bone_weighting mask");
}
- for(totface=0, a=0, mface=me->mface; a<me->totface; a++, mface++) {
- totface++;
- if(mface->v4) totface++;
-
+ for(a = 0, mp=me->mpoly; a < me->totpoly; mp++, a++) {
/* (added selectedVerts content for vertex mask, they used to just equal 1) */
if(use_vert_sel) {
- mask[mface->v1]= (mvert[mface->v1].flag & SELECT) != 0;
- mask[mface->v2]= (mvert[mface->v2].flag & SELECT) != 0;
- mask[mface->v3]= (mvert[mface->v3].flag & SELECT) != 0;
- if(mface->v4) {
- mask[mface->v4]= (mvert[mface->v4].flag & SELECT) != 0;
+ for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) {
+ if (use_vert_sel) {
+ mask[ml->v] = (mvert[ml->v].flag & SELECT) != 0;
+ }
}
}
else if (use_face_sel) {
- if (mface->flag & ME_FACE_SEL) {
- mask[mface->v1]= 1;
- mask[mface->v2]= 1;
- mask[mface->v3]= 1;
- if(mface->v4) {
- mask[mface->v4]= 1;
+ if (mp->flag & ME_FACE_SEL) {
+ for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) {
+ mask[ml->v] = 1;
}
}
}
}
+ /* bone heat needs triangulated faces */
+ BKE_mesh_tessface_ensure(me);
+
+ for(tottri = 0, a = 0, mf = me->mface; a < me->totface; mf++, a++) {
+ tottri++;
+ if(mf->v4) tottri++;
+ }
+
/* create laplacian */
- sys = laplacian_system_construct_begin(me->totvert, totface, 1);
+ sys = laplacian_system_construct_begin(me->totvert, tottri, 1);
sys->heat.mface= me->mface;
sys->heat.totface= me->totface;
@@ -715,7 +719,7 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
for(a=0; a<me->totvert; a++)
vertsflipped[a] = mesh_get_x_mirror_vert(ob, a);
}
-
+
/* compute weights per bone */
for(j=0; j<numsource; j++) {
if(!selected[j])
@@ -1188,8 +1192,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);
@@ -1879,9 +1883,9 @@ 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);
+ int totface= dm->getNumTessFaces(dm);
float solution, weight;
int a, tottri, j, thrownerror = 0;
diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c
index bcdda8e9eb1..cb0857d41e6 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"
@@ -3377,9 +3378,12 @@ static int iteratorStopped(void *arg)
ReebGraph *BIF_ReebGraphMultiFromEditMesh(bContext *C)
{
+ (void)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;
@@ -3475,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..95dd7fc6233 100644
--- a/source/blender/editors/curve/SConscript
+++ b/source/blender/editors/curve/SConscript
@@ -5,7 +5,7 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
-incs += ' ../../gpu ../../blenloader'
+incs += ' ../../bmesh ../../gpu ../../blenloader'
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 5c762ca61cc..495c8a8f842 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -6461,12 +6461,12 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
ListBase *editnurb;
Nurb *nu;
int newob= 0;
- int enter_editmode;
+ int enter_editmode, is_aligned;
unsigned int layer;
float loc[3], rot[3];
float mat[4][4];
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
+ if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, &is_aligned))
return OPERATOR_CANCELLED;
if (!isSurf) { /* adding curve */
@@ -6861,10 +6861,9 @@ 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 *UNUSED(edata), void *cu_v)
{
- Object *obedit= obe;
- Curve *cu= (Curve*)obedit->data;
+ Curve *cu= cu_v;
UndoCurve *undoCurve= ucu;
ListBase *undobase= &undoCurve->nubase;
ListBase *editbase= curve_editnurbs(cu);
@@ -6907,14 +6906,15 @@ static void undoCurve_to_editCurve(void *ucu, void *obe)
cu->lastsel= lastsel;
cu->actnu= undoCurve->actnu;
-
+ /* BMESH_TODO */
+#if 0
ED_curve_updateAnimPaths(obedit);
+#endif
}
-static void *editCurve_to_undoCurve(void *obe)
+static void *editCurve_to_undoCurve(void *UNUSED(edata), void *cu_v)
{
- Object *obedit= obe;
- Curve *cu= (Curve*)obedit->data;
+ Curve *cu= cu_v;
ListBase *nubase= curve_editnurbs(cu);
UndoCurve *undoCurve;
EditNurb *editnurb= cu->editnurb, tmpEditnurb;
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 493fc6e277b..efde93b4ad7 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -1739,7 +1739,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 *UNUSED(obdata))
{
Curve *cu= (Curve *)ecu;
EditFont *ef= cu->editfont;
@@ -1756,7 +1756,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 *UNUSED(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..6c23e77208a 100644
--- a/source/blender/editors/gpencil/SConscript
+++ b/source/blender/editors/gpencil/SConscript
@@ -5,7 +5,7 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
-incs += ' ../../gpu ../../blenloader'
+incs += ' ../../gpu ../../blenloader ../../bmesh'
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/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 6e289fb5a2a..12524a9fd2e 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -61,6 +61,16 @@ 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 ToolSettings;
struct Material;
struct Object;
struct rcti;
@@ -85,111 +95,148 @@ struct rcti;
#define B_FRACTAL 0x2000
#define B_SPHERE 0x4000
-/* meshtools.c */
-
-intptr_t mesh_octree_table(struct Object *ob, struct EditMesh *em, float *co, char mode);
-int mesh_mirrtopo_table(struct Object *ob, char mode);
-
-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);
+intptr_t mesh_octree_table(struct Object *ob, struct BMEditMesh *em, float *co, char mode);
+int mesh_mirrtopo_table(struct Object *ob, char mode);
-int join_mesh_exec(struct bContext *C, struct wmOperator *op);
-int join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op);
+/* bmeshutils.c */
-/* 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, const short use_select); /* note, replaces EM_cache_x_mirror_vert in trunk */
+
+/*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_ClearMirrorVert(struct BMEditMesh *em, struct BMVert *v);
+void EDBM_EndMirrorCache(struct BMEditMesh *em);
+void EDBM_ApplyMirrorCache(struct BMEditMesh *em, const int sel_from, const int sel_to);
+
+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);
+
+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_select_more(struct BMEditMesh *em);
+void EDBM_select_less(struct BMEditMesh *em);
+
+int EDBM_get_actSelection(struct BMEditMesh *em, struct BMEditSelection *ese);
+
+void EDBM_selectmode_flush_ex(struct BMEditMesh *em, int selectmode);
+void EDBM_selectmode_flush(struct BMEditMesh *em);
+
+void EDBM_deselect_flush(struct BMEditMesh *em);
+void EDBM_select_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_hide_mesh(struct BMEditMesh *em, int swap);
+void EDBM_reveal_mesh(struct BMEditMesh *em);
-void recalc_editnormals(struct EditMesh *em);
+int EDBM_check_backbuf(unsigned int index);
+int EDBM_mask_init_backbuf_border(struct ViewContext *vc, int 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 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);
+void EDBM_deselect_by_material(struct BMEditMesh *em, const short index, const short select);
-void undo_push_mesh(struct bContext *C, const char *name);
+int EDBM_select_interior_faces(struct BMEditMesh *em);
-void paintvert_flush_flags(struct Object *ob);
-void paintvert_deselect_all_visible(struct Object *ob, int action, short flush_flags);
+struct UvElementMap *EDBM_make_uv_element_map(struct BMEditMesh *em, int selected, int doIslands);
+void EDBM_free_uv_element_map(struct UvElementMap *vmap);
-/* editmesh_lib.c */
+void EDBM_add_data_layer(struct BMEditMesh *em, struct CustomData *data, int type, const char *name);
+void EDBM_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_select_swap(struct BMEditMesh *em); /* exported for UV */
-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);
+int EDBM_texFaceCheck(struct BMEditMesh *em);
+struct MTexPoly *EDBM_get_active_mtexpoly(struct BMEditMesh *em, struct BMFace **act_efa, int sloppy);
- /* 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 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 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);
+void EDBM_toggle_select_all(struct BMEditMesh *em);
+void EDBM_flag_enable_all(struct BMEditMesh *em, const char hflag);
+void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag);
+void EDBM_select_mirrored(struct Object *obedit, struct BMEditMesh *em, int extend);
+void EDBM_automerge(struct Scene *scene, struct Object *ob, int update);
-struct UvElementMap *EM_make_uv_element_map(struct EditMesh *em, int selected, int doIslands);
-void EM_free_uv_element_map(struct UvElementMap *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);
+int mouse_mesh(struct bContext *C, const int mval[2], short extend);
-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, const int mval[2], short extend);
-int EM_check_backbuf(unsigned int index);
-int EM_mask_init_backbuf_border(struct ViewContext *vc, int 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);
+/* bmesh_tools.c (could be moved) */
+void EMBM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct Object *obedit, struct BMEditMesh *em);
/* 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, const int 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);
@@ -199,6 +246,9 @@ int paintface_minmax(struct Object *ob, float *min, float *max);
void paintface_hide(struct Object *ob, const int unselected);
void paintface_reveal(struct Object *ob);
+void paintvert_deselect_all_visible(struct Object *ob, int action, short flush_flags);
+void paintvert_flush_flags(struct Object *ob);
+
/* object_vgroup.c */
#define WEIGHT_REPLACE 1
@@ -221,18 +271,26 @@ 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);
+void ED_mesh_polys_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_faces_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count);
+void ED_mesh_loops_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_vertices_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_faces_remove(struct Mesh *mesh, struct ReportList *reports, int count);
@@ -246,10 +304,16 @@ void ED_mesh_update(struct Mesh *mesh, struct bContext *C, int calc_edges);
int ED_mesh_uv_texture_add(struct bContext *C, struct Mesh *me, const char *name, int active_set);
int ED_mesh_uv_texture_remove(struct bContext *C, struct Object *ob, struct Mesh *me);
+int ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me);
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);
int ED_mesh_color_remove_named(struct bContext *C, struct Object *ob, struct Mesh *me, const char *name);
+void EDBM_selectmode_to_scene(struct bContext *C);
+void EDBM_ClearMesh(struct BMEditMesh *em);
+
+#include "../mesh/editmesh_bvh.h"
+
/* mirrtopo */
typedef struct MirrTopoStore_t {
@@ -264,9 +328,18 @@ void ED_mesh_mirrtopo_init(struct Mesh *me, const int ob_mode, MirrTopoStore_t *
const short skip_em_vert_array_init);
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store);
+#define SUBDIV_SELECT_ORIG 0
+#define SUBDIV_SELECT_INNER 1
+#define SUBDIV_SELECT_INNER_SEL 2
+#define SUBDIV_SELECT_LOOPCUT 3
+
+/* edge subdivide corner cut types */
+#define SUBDIV_CORNER_PATH 0
+#define SUBDIV_CORNER_INNERVERT 1
+#define SUBDIV_CORNER_FAN 2
+
#ifdef __cplusplus
}
#endif
#endif /* __ED_MESH_H__ */
-
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index c808e63d320..3e78a5649e5 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -127,8 +127,8 @@ float ED_object_new_primitive_matrix(struct bContext *C, struct Object *editob,
void ED_object_add_generic_props(struct wmOperatorType *ot, int do_editmode);
int ED_object_add_generic_invoke(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
-int ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op,
- float *loc, float *rot, int *enter_editmode, unsigned int *layer);
+int ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op,
+ float *loc, float *rot, int *enter_editmode, unsigned int *layer, int *is_view_aligned);
struct Object *ED_object_add_type(struct bContext *C, int type, float *loc,
float *rot, int enter_editmode, unsigned int layer);
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index d082f3449fa..9bde252e776 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -38,7 +38,7 @@ struct ARegion;
struct uiBlock;
struct wmOperator;
struct wmOperatorType;
-struct EditMesh;
+struct BMEditMesh;
struct Mesh;
/* ed_util.c */
@@ -70,8 +70,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 *));
@@ -79,7 +79,7 @@ void undo_editmode_clear (void);
/* 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 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 4d8bceb044f..6c74eea3a5e 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -42,6 +42,10 @@ struct SpaceImage;
struct bContext;
struct bNode;
struct wmKeyConfig;
+struct BMEditMesh;
+struct BMLoop;
+struct BMFace;
+struct MTexPoly;
/* uvedit_ops.c */
void ED_operatortypes_uvedit(void);
@@ -57,18 +61,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 63c03cd2963..2d4e267ba80 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -38,8 +38,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;
int mval[2];
} ViewContext;
@@ -190,9 +193,9 @@ void ED_view3d_from_object(struct Object *ob, float ofs[3], float quat[4], float
*/
void ED_view3d_to_object(struct Object *ob, const float ofs[3], const float quat[4], const float dist);
-#if 0 /* UNUSED */
+//#if 0 /* UNUSED */
void view3d_unproject(struct bglMats *mats, float out[3], const short x, const short y, const float z);
-#endif
+//#endif
/* Depth buffer */
void ED_view3d_depth_update(struct ARegion *ar);
@@ -219,12 +222,13 @@ int ED_view3d_viewplane_get(struct View3D *v3d, struct RegionView3D *rv3d, int w
void ED_view3d_ob_project_mat_get(struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]);
void ED_view3d_project_float(const struct ARegion *a, const float vec[3], float adr[2], float mat[4][4]);
void ED_view3d_calc_camera_border(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, struct RegionView3D *rv3d, struct rctf *viewborder_r, short no_shift);
+void ED_view3d_project_float_v3(struct ARegion *a, float *vec, float *adr, float mat[4][4]);
void ED_view3d_calc_camera_border_size(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, struct RegionView3D *rv3d, float size_r[2]);
/* drawobject.c iterators */
-void mesh_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct EditVert *eve, int x, int y, int index), void *userData, eV3DClipTest 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, eV3DClipTest 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, eV3DClipTest 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, eV3DClipTest 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/interface/SConscript b/source/blender/editors/interface/SConscript
index ec5ae99755d..2d6d5cd235e 100644
--- a/source/blender/editors/interface/SConscript
+++ b/source/blender/editors/interface/SConscript
@@ -8,7 +8,7 @@ for source in env.Glob('*_api.c'):
incs = '../include ../../blenlib ../../blenfont ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../makesrna ../../windowmanager #/intern/guardedalloc ../../gpu'
-incs += ' #/extern/glew/include ../../blenloader'
+incs += ' #/extern/glew/include ../../blenloader ../../bmesh'
incs += ' ../../python/' # python button eval
defs = []
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index ce0362759dc..3e7049b5b1e 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -2124,7 +2124,7 @@ static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, Pointe
name= (namebuf)? namebuf: "";
/* hardcoded types */
- if(itemptr->type == &RNA_MeshTextureFaceLayer || itemptr->type == &RNA_MeshColorLayer) {
+ if(itemptr->type == &RNA_MeshTexturePolyLayer || itemptr->type == &RNA_MeshLoopColorLayer) {
uiItemL(sub, name, icon);
uiBlockSetEmboss(block, UI_EMBOSSN);
uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render", 0, 0, 0, 0, 0, NULL);
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 7849b71307b..9d2229b52f4 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -20,9 +20,11 @@
set(INC
../include
+ ../uvedit
../../blenkernel
../../blenlib
../../blenloader
+ ../../bmesh
../../imbuf
../../makesdna
../../makesrna
@@ -36,18 +38,20 @@ set(INC_SYS
)
set(SRC
+ bmesh_select.c
+ bmesh_selecthistory.c
+ bmesh_tools.c
+ bmesh_utils.c
editface.c
- editmesh.c
editmesh_add.c
- editmesh_lib.c
- editmesh_loop.c
- editmesh_mods.c
- editmesh_tools.c
+ editmesh_bvh.c
+ knifetool.c
loopcut.c
mesh_data.c
mesh_ops.c
meshtools.c
+ editmesh_bvh.h
mesh_intern.h
)
diff --git a/source/blender/editors/mesh/SConscript b/source/blender/editors/mesh/SConscript
index 6546a44adeb..8142faf67a1 100644
--- a/source/blender/editors/mesh/SConscript
+++ b/source/blender/editors/mesh/SConscript
@@ -9,6 +9,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 ../uvedit '
if env['OURPLATFORM'] == 'linux':
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..89bccf8f00e
--- /dev/null
+++ b/source/blender/editors/mesh/bmesh_select.c
@@ -0,0 +1,2767 @@
+/*
+ * ***** 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 *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_array.h"
+#include "BLI_smallhash.h"
+#include "BLI_heap.h"
+
+#include "BKE_context.h"
+#include "BKE_displist.h"
+#include "BKE_depsgraph.h"
+#include "BKE_report.h"
+#include "BKE_paint.h"
+#include "BKE_tessmesh.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#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 "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+
+#include "mesh_intern.h"
+
+
+/* ****************************** MIRROR **************** */
+
+void EDBM_select_mirrored(Object *UNUSED(obedit), BMEditMesh *em, int extend)
+{
+ BMVert *v1, *v2;
+ BMIter iter;
+
+ BM_ITER(v1, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(v1, BM_ELEM_SELECT) || BM_elem_flag_test(v1, BM_ELEM_HIDDEN)) {
+ BM_elem_flag_disable(v1, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_enable(v1, BM_ELEM_TAG);
+ }
+ }
+
+ EDBM_CacheMirrorVerts(em, TRUE);
+
+ if (!extend)
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+
+ BM_ITER(v1, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(v1, BM_ELEM_TAG) || BM_elem_flag_test(v1, BM_ELEM_HIDDEN))
+ continue;
+
+ v2 = EDBM_GetMirrorVert(em, v1);
+ if (v2 && !BM_elem_flag_test(v2, BM_ELEM_HIDDEN)) {
+ BM_elem_select_set(em->bm, v2, TRUE);
+ }
+ }
+
+ EDBM_EndMirrorCache(em);
+}
+
+void EDBM_automerge(Scene *scene, Object *obedit, int update)
+{
+ BMEditMesh *em;
+
+ if ((scene->toolsettings->automerge) &&
+ (obedit && obedit->type == OB_MESH))
+ {
+ em = ((Mesh *)obedit->data)->edit_btmesh;
+ if (!em)
+ return;
+
+ BMO_op_callf(em->bm, "automerge verts=%hv dist=%f", BM_ELEM_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(int 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, int 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 if (paint_vertsel_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++) {
+ glVertex2iv(mcords[a]);
+ }
+ 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 if (paint_vertsel_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_elem_flag_test(eve, BM_ELEM_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 = BM_vert_at_index(em->bm, index - 1);
+
+ if (eve && BM_elem_flag_test(eve, BM_ELEM_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 = BM_vert_at_index(vc->em->bm, 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 && BM_vert_at_index(vc->em->bm, 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, V3D_CLIP_TEST_RV3D_CLIPPING);
+
+ if (data.dist > 3) {
+ data.pass = 1;
+ mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_CLIP_TEST_RV3D_CLIPPING);
+ }
+
+ *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(const float v1[3], const float v2[3], const float v3[3])
+{
+ 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 UNUSED(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_elem_flag_test(eed, BM_ELEM_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 (ED_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 = BM_edge_at_index(vc->em->bm, 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 UNUSED(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 = BM_face_at_index(vc->em->bm, 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 && BM_face_at_index(vc->em->bm, 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_ELEM_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", ""},
+ {SIMEDGE_FREESTYLE, "FREESTYLE_EDGE", 0, "Freestyle Edge Marks", ""},
+
+ {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", ""},
+ {SIMFACE_FREESTYLE, "FREESTYLE_FACE", 0, "Freestyle Face Marks", ""},
+
+ {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)
+{
+ 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_ELEM_SELECT, type, thresh);
+
+ /* execute the operator */
+ BMO_op_exec(em->bm, &bmop);
+
+ /* clear the existing selection */
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+
+ /* select the output */
+ BMO_slot_buffer_hflag_enable(em->bm, &bmop, "faceout", BM_ELEM_SELECT, BM_ALL);
+
+ /* finish the operator */
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ 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)
+{
+ 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_ELEM_SELECT, type, thresh);
+
+ /* execute the operator */
+ BMO_op_exec(em->bm, &bmop);
+
+ /* clear the existing selection */
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+
+ /* select the output */
+ BMO_slot_buffer_hflag_enable(em->bm, &bmop, "edgeout", BM_ELEM_SELECT, BM_ALL);
+ EDBM_selectmode_flush(em);
+
+ /* finish the operator */
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ 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)
+{
+ 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_ELEM_SELECT, type, thresh);
+
+ /* execute the operator */
+ BMO_op_exec(em->bm, &bmop);
+
+ /* clear the existing selection */
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+
+ /* select the output */
+ BMO_slot_buffer_hflag_enable(em->bm, &bmop, "vertout", BM_ELEM_SELECT, BM_ALL);
+
+ /* finish the operator */
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ 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 *UNUSED(ptr), PropertyRNA *UNUSED(prop),
+ int *free)
+{
+ Object *obedit = CTX_data_edit_object(C);
+
+ if (obedit && obedit->type == OB_MESH) {
+ EnumPropertyItem *item = NULL;
+ int a, totitem = 0;
+ 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_FREESTYLE; 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 = ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
+ RNA_def_enum_funcs(prop, select_similar_type_itemf);
+}
+
+/* ***************************************************** */
+
+/* **************** LOOP SELECTS *************** */
+
+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,
+ BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_NIL_LAY);
+ h = BMW_begin(&walker, start);
+ for ( ; h; h = BMW_step(&walker)) {
+ if (!select) {
+ BM_select_history_remove(bm, h);
+ }
+ BM_elem_select_set(bm, h, select);
+ }
+ BMW_end(&walker);
+}
+
+static int loop_multiselect(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ BMEdge *eed;
+ BMEdge **edarray;
+ int edindex;
+ int looptype = RNA_boolean_get(op->ptr, "ring");
+
+ BMIter iter;
+ int totedgesel = 0;
+
+ for (eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ eed; eed = BM_iter_step(&iter)) {
+
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ totedgesel++;
+ }
+ }
+
+
+ edarray = MEM_mallocN(sizeof(BMEdge *)*totedgesel,"edge array");
+ edindex = 0;
+
+ for (eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ eed;
+ eed = BM_iter_step(&iter))
+ {
+
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ edarray[edindex] = eed;
+ edindex++;
+ }
+ }
+
+ if (looptype) {
+ for (edindex = 0; edindex < totedgesel; edindex += 1) {
+ eed = edarray[edindex];
+ walker_select(em, BMW_EDGERING, eed, 1);
+ }
+ EDBM_selectmode_flush(em);
+ }
+ else{
+ for (edindex = 0; edindex < totedgesel; edindex += 1) {
+ eed = edarray[edindex];
+ walker_select(em, BMW_LOOP, eed, 1);
+ }
+ EDBM_selectmode_flush(em);
+ }
+ MEM_freeN(edarray);
+// if (EM_texFaceCheck())
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ 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, int mval[2], short extend, short ring)
+{
+ ViewContext vc;
+ BMEditMesh *em;
+ BMEdge *eed;
+ int select = TRUE;
+ 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_flag_disable_all(em, BM_ELEM_SELECT);
+ }
+
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT) == 0) {
+ select = TRUE;
+ }
+ else if (extend) {
+ select = FALSE;
+ }
+
+ 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) {
+ if (em->selectmode & SCE_SELECT_VERTEX) {
+ /* TODO: would be nice if the edge vertex chosen here
+ * was the one closer to the selection pointer, instead
+ * of arbitrarily selecting the first one */
+ EDBM_store_selection(em, eed->v1);
+ }
+ else if (em->selectmode & SCE_SELECT_EDGE) {
+ EDBM_store_selection(em, eed);
+ }
+ /* TODO: would be nice if the nearest face that
+ * belongs to the selected edge could be set to
+ * active here in face select mode */
+ }
+
+ 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";
+ ot->description = "Select a loop";
+
+ /* api callbacks */
+ ot->invoke = mesh_select_loop_invoke;
+ ot->poll = ED_operator_editmesh_region_view3d;
+ 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", "Extend the selection");
+ RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "Select ring");
+}
+
+void MESH_OT_edgering_select (wmOperatorType *ot)
+{
+ /* description */
+ ot->name = "Edge Ring Select";
+ ot->idname = "MESH_OT_edgering_select";
+ ot->description = "Select an edge ring";
+
+ /* callbacks */
+ ot->invoke = mesh_select_loop_invoke;
+ ot->poll = ED_operator_editmesh_region_view3d;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
+ RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring");
+}
+
+/* ******************* edgetag_shortest_path and helpers ****************** */
+
+static float edgetag_cut_cost(BMEditMesh *UNUSED(em), BMEdge *e1, BMEdge *e2, BMVert *v)
+{
+ BMVert *v1 = (e1->v1 == v) ? e1->v2 : e1->v1;
+ BMVert *v2 = (e2->v1 == v) ? e2->v2 : e2->v1;
+ float cost, d1[3], d2[3];
+
+ /* The cost is based on the simple sum of the length of the two edgees... */
+ sub_v3_v3v3(d1, v->co, v1->co);
+ sub_v3_v3v3(d2, v2->co, v->co);
+ cost = len_v3(d1);
+ cost += len_v3(d2);
+
+ /*.but is biased to give higher values to sharp turns, so that it will take
+ * paths with fewer "turns" when selecting between equal-weighted paths between
+ * the two edges */
+ cost = cost + 0.5f * cost * (2.0f - sqrt(fabs(dot_v3v3(d1, d2))));
+
+ return cost;
+}
+
+static void edgetag_add_adjacent(BMEditMesh *em, SmallHash *visithash, Heap *heap, int mednum, int vertnum,
+ int *nedges, int *edges, int *prevedge, float *cost)
+{
+ BMEdge *e1 = EDBM_get_edge_for_index(em, mednum);
+ BMVert *v = EDBM_get_vert_for_index(em, vertnum);
+ int startadj, endadj = nedges[vertnum + 1];
+
+ for (startadj = nedges[vertnum]; startadj < endadj; startadj++) {
+ int adjnum = edges[startadj];
+ BMEdge *e2 = EDBM_get_edge_for_index(em, adjnum);
+ float newcost;
+ float cutcost;
+
+ if (BLI_smallhash_haskey(visithash, (uintptr_t)e2))
+ continue;
+
+ cutcost = edgetag_cut_cost(em, e1, e2, v);
+ newcost = cost[mednum] + cutcost;
+
+ if (cost[adjnum] > newcost) {
+ cost[adjnum] = newcost;
+ prevedge[adjnum] = mednum;
+ BLI_heap_insert(heap, newcost, SET_INT_IN_POINTER(adjnum));
+ }
+ }
+}
+
+static void edgetag_context_set(BMEditMesh *em, Scene *scene, BMEdge *e, int val)
+{
+
+ switch (scene->toolsettings->edge_mode) {
+ case EDGE_MODE_SELECT:
+ BM_elem_select_set(em->bm, e, val);
+ break;
+ case EDGE_MODE_TAG_SEAM:
+ if (val) {BM_elem_flag_enable(e, BM_ELEM_SEAM);}
+ else {BM_elem_flag_disable(e, BM_ELEM_SEAM);}
+ break;
+ case EDGE_MODE_TAG_SHARP:
+ if (val) {BM_elem_flag_enable(e, BM_ELEM_SEAM);}
+ else {BM_elem_flag_disable(e, BM_ELEM_SEAM);}
+ break;
+ case EDGE_MODE_TAG_FREESTYLE:
+ if (val) {BM_elem_flag_enable(e, BM_ELEM_FREESTYLE);}
+ else {BM_elem_flag_disable(e, BM_ELEM_FREESTYLE);}
+ break;
+ case EDGE_MODE_TAG_CREASE:
+ {
+ float *crease = CustomData_bmesh_get(&em->bm->edata, e->head.data, CD_CREASE);
+
+ if (val) {*crease = 1.0f;}
+ else {*crease = 0.0f;}
+ break;
+ }
+ case EDGE_MODE_TAG_BEVEL:
+ {
+ float *bweight = CustomData_bmesh_get(&em->bm->edata, e->head.data, CD_BWEIGHT);
+
+ if (val) {*bweight = 1.0f;}
+ else {*bweight = 0.0f;}
+ break;
+ }
+ }
+}
+
+static int edgetag_context_check(Scene *scene, BMEditMesh *em, BMEdge *e)
+{
+ switch (scene->toolsettings->edge_mode) {
+ case EDGE_MODE_SELECT:
+ return BM_elem_flag_test(e, BM_ELEM_SELECT) ? 1 : 0;
+ case EDGE_MODE_TAG_SEAM:
+ return BM_elem_flag_test(e, BM_ELEM_SEAM);
+ case EDGE_MODE_TAG_SHARP:
+ return !BM_elem_flag_test(e, BM_ELEM_SMOOTH);
+ case EDGE_MODE_TAG_FREESTYLE:
+ return !BM_elem_flag_test(e, BM_ELEM_FREESTYLE);
+ case EDGE_MODE_TAG_CREASE:
+ return BM_elem_float_data_get(&em->bm->edata, e, CD_CREASE) ? 1 : 0;
+ case EDGE_MODE_TAG_BEVEL:
+ return BM_elem_float_data_get(&em->bm->edata, e, CD_BWEIGHT) ? 1 : 0;
+ }
+ return 0;
+}
+
+static int edgetag_shortest_path(Scene *scene, BMEditMesh *em, BMEdge *source, BMEdge *target)
+{
+ BMEdge *e;
+ BMIter iter;
+ Heap *heap;
+ SmallHash visithash;
+ float *cost;
+ int i, totvert = 0, totedge = 0, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0;
+ int targetnum;
+
+ BLI_smallhash_init(&visithash);
+
+ /* note, would pass BM_EDGE except we are looping over all edges anyway */
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT /* | BM_EDGE */);
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ e->oflags[0].f = 0; /* XXX, whats this for, BMESH_TODO, double check if this is needed */
+ if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ BLI_smallhash_insert(&visithash, (uintptr_t)e, NULL);
+ }
+
+ BM_elem_index_set(e, totedge); /* set_inline */
+ totedge++;
+ }
+ em->bm->elem_index_dirty &= ~BM_EDGE;
+
+ /* alloc */
+ totvert = em->bm->totvert;
+ nedges = MEM_callocN(sizeof(*nedges) * totvert + 1, "SeamPathNEdges");
+ edges = MEM_mallocN(sizeof(*edges) * totedge * 2, "SeamPathEdges");
+ prevedge = MEM_mallocN(sizeof(*prevedge) * totedge, "SeamPathPrevious");
+ cost = MEM_mallocN(sizeof(*cost) * totedge, "SeamPathCost");
+
+ /* count edges, compute adjacent edges offsets and fill adjacent */
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ nedges[BM_elem_index_get(e->v1) + 1]++;
+ nedges[BM_elem_index_get(e->v2) + 1]++;
+ }
+
+ for (i = 1; i < totvert; i++) {
+ int newswap = nedges[i + 1];
+ nedges[i + 1] = nedgeswap + nedges[i];
+ nedgeswap = newswap;
+ }
+ nedges[0] = nedges[1] = 0;
+
+ i = 0;
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ edges[nedges[BM_elem_index_get(e->v1) + 1]++] = i;
+ edges[nedges[BM_elem_index_get(e->v2) + 1]++] = i;
+
+ cost[i] = 1e20f;
+ prevedge[i] = -1;
+ i++;
+ }
+
+ /*
+ * Arrays are now filled as follows:
+ *
+ * nedges[n] = sum of the # of edges incident to all vertices numbered 0 thru n - 1
+ * edges[edges[n]..edges[n - 1]] = the indices of of the edges incident to vertex n
+ *
+ * As the search continues, prevedge[n] will be the previous edge on the shortest
+ * path found so far to edge n. The visitedhash will of course contain entries
+ * for edges that have been visited, cost[n] will contain the length of the shortest
+ * path to edge n found so far, Finally, heap is a priority heap which is built on the
+ * the same data as the cost arry, but inverted: it is a worklist of edges prioritized
+ * by the shortest path found so far to the edge.
+ */
+
+#if 0 /* UNUSED */ /* this block does nothing, not sure why its here? - campbell */
+ for (i = 0; i < totvert; i++) {
+ int start = nedges[i], end = nedges[i + 1], cur;
+ for (cur = start; cur < end; cur++) {
+ BMEdge *e = EDBM_get_edge_for_index(em, edges[cur]);
+ }
+ }
+#endif
+
+ /* regular dijkstra shortest path, but over edges instead of vertices */
+ heap = BLI_heap_new();
+ BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(BM_elem_index_get(source)));
+ cost[BM_elem_index_get(source)] = 0.0f;
+ EDBM_init_index_arrays(em, 1, 1, 0);
+ targetnum = BM_elem_index_get(target);
+
+ while (!BLI_heap_empty(heap)) {
+ mednum = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
+ e = EDBM_get_edge_for_index(em, mednum);
+
+ if (mednum == targetnum)
+ break;
+
+ if (BLI_smallhash_haskey(&visithash, (uintptr_t)e))
+ continue;
+
+ BLI_smallhash_insert(&visithash, (uintptr_t)e, NULL);
+
+ edgetag_add_adjacent(em, &visithash, heap, mednum, BM_elem_index_get(e->v1), nedges, edges, prevedge, cost);
+ edgetag_add_adjacent(em, &visithash, heap, mednum, BM_elem_index_get(e->v2), nedges, edges, prevedge, cost);
+ }
+
+ if (mednum == targetnum) {
+ short allseams = 1;
+
+ /* Check whether the path is already completely tagged.
+ * if it is, the tags will be cleared instead of set. */
+ mednum = targetnum;
+ do {
+ e = EDBM_get_edge_for_index(em, mednum);
+ if (!edgetag_context_check(scene, em, e)) {
+ allseams = 0;
+ break;
+ }
+ mednum = prevedge[mednum];
+ } while (mednum != BM_elem_index_get(source));
+
+ /* Follow path back and source and add or remove tags */
+ mednum = targetnum;
+ do {
+ e = EDBM_get_edge_for_index(em, mednum);
+ if (allseams)
+ edgetag_context_set(em, scene, e, 0);
+ else
+ edgetag_context_set(em, scene, e, 1);
+ mednum = prevedge[mednum];
+ } while (mednum != -1);
+ }
+
+ EDBM_free_index_arrays(em);
+ MEM_freeN(nedges);
+ MEM_freeN(edges);
+ MEM_freeN(prevedge);
+ MEM_freeN(cost);
+ BLI_heap_free(heap, NULL);
+ BLI_smallhash_release(&visithash);
+
+ return 1;
+}
+
+/* ******************* 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, int mval[2])
+{
+ Object *ob = CTX_data_edit_object(C);
+ ViewContext vc;
+ BMEditMesh *em;
+ BMEdge *e;
+ int dist = 50;
+
+ em_setup_viewcontext(C, &vc);
+ vc.mval[0] = mval[0];
+ vc.mval[1] = mval[1];
+ em = vc.em;
+
+ e = EDBM_findnearestedge(&vc, &dist);
+ if (e) {
+ Mesh *me = vc.obedit->data;
+ int path = 0;
+
+ if (em->bm->selected.last) {
+ BMEditSelection *ese = em->bm->selected.last;
+
+ if (ese && ese->htype == BM_EDGE) {
+ BMEdge *e_act;
+ e_act = (BMEdge *)ese->data;
+ if (e_act != e) {
+ if (edgetag_shortest_path(vc.scene, em, e_act, e)) {
+ EDBM_remove_selection(em, e_act);
+ path = 1;
+ }
+ }
+ }
+ }
+ if (path == 0) {
+ int act = (edgetag_context_check(vc.scene, em, e) == 0);
+ edgetag_context_set(em, vc.scene, e, act); /* switch the edge option */
+ }
+
+ EDBM_selectmode_flush(em);
+
+ /* even if this is selected it may not be in the selection list */
+ if (edgetag_context_check(vc.scene, em, e) == 0)
+ EDBM_remove_selection(em, e);
+ else
+ EDBM_store_selection(em, e);
+
+ /* 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;
+ case EDGE_MODE_TAG_FREESTYLE:
+ me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
+ break;
+ }
+
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->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;
+}
+
+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, const int 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_flag_disable_all(vc.em, BM_ELEM_SELECT);
+
+ if (efa) {
+ /* set the last selected face */
+ BM_active_face_set(vc.em->bm, efa);
+
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ EDBM_store_selection(vc.em, efa);
+ BM_elem_select_set(vc.em->bm, efa, TRUE);
+ }
+ else if (extend) {
+ EDBM_remove_selection(vc.em, efa);
+ BM_elem_select_set(vc.em->bm, efa, FALSE);
+ }
+ }
+ else if (eed) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ EDBM_store_selection(vc.em, eed);
+ BM_elem_select_set(vc.em->bm, eed, TRUE);
+ }
+ else if (extend) {
+ EDBM_remove_selection(vc.em, eed);
+ BM_elem_select_set(vc.em->bm, eed, FALSE);
+ }
+ }
+ else if (eve) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ EDBM_store_selection(vc.em, eve);
+ BM_elem_select_set(vc.em->bm, eve, TRUE);
+ }
+ else if (extend) {
+ EDBM_remove_selection(vc.em, eve);
+ BM_elem_select_set(vc.em->bm, eve, FALSE);
+ }
+ }
+
+ 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->htype == 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->htype == 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->htype == 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) {
+ EDBM_select_flush(em);
+ }
+ else if (em->selectmode & SCE_SELECT_EDGE) {
+ /* deselect vertices, and select again based on edge select */
+ eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for ( ; eve; eve = BM_iter_step(&iter)) BM_elem_select_set(em->bm, eve, FALSE);
+
+ eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed = BM_iter_step(&iter)) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ BM_elem_select_set(em->bm, eed, TRUE);
+ }
+ }
+
+ /* 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 = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed = BM_iter_step(&iter)) BM_elem_select_set(em->bm, eed, FALSE);
+
+ efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa = BM_iter_step(&iter)) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_elem_select_set(em->bm, efa, TRUE);
+ }
+ }
+ }
+}
+
+void EDBM_convertsel(BMEditMesh *em, short oldmode, short selectmode)
+{
+ 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 = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed = BM_iter_step(&iter)) {
+ if ( (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)))
+ {
+ BM_elem_select_set(em->bm, eed, TRUE);
+ }
+ }
+ }
+ else if (selectmode == SCE_SELECT_FACE) {
+ BMIter liter;
+ BMLoop *l;
+
+ /* select all faces associated with every selected vertex */
+ efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa = BM_iter_step(&iter)) {
+ l = BM_iter_new(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l = BM_iter_step(&liter)) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_SELECT)) {
+ BM_elem_select_set(em->bm, efa, TRUE);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (oldmode == SCE_SELECT_EDGE) {
+ if (selectmode == SCE_SELECT_FACE) {
+ BMIter liter;
+ BMLoop *l;
+
+ /* select all faces associated with every selected vertex */
+ efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa = BM_iter_step(&iter)) {
+ l = BM_iter_new(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l = BM_iter_step(&liter)) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_SELECT)) {
+ BM_elem_select_set(em->bm, efa, TRUE);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void EDBM_deselect_by_material(struct BMEditMesh *em, const short index, const short select)
+{
+ BMIter iter;
+ BMFace *efa;
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
+ continue;
+ if (efa->mat_nr == index) {
+ BM_elem_select_set(em->bm, efa, select);
+ }
+ }
+}
+
+
+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_elem_flag_test(eve, BM_ELEM_HIDDEN))
+ continue;
+ BM_elem_select_set(em->bm, eve, !BM_elem_flag_test(eve, BM_ELEM_SELECT));
+ }
+ }
+ else if (em->selectmode & SCE_SELECT_EDGE) {
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
+ continue;
+ BM_elem_select_set(em->bm, eed, !BM_elem_flag_test(eed, BM_ELEM_SELECT));
+ }
+ }
+ else {
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
+ continue;
+ BM_elem_select_set(em->bm, efa, !BM_elem_flag_test(efa, BM_ELEM_SELECT));
+ }
+
+ }
+// if (EM_texFaceCheck())
+}
+
+int EDBM_select_interior_faces(struct BMEditMesh *em)
+{
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMIter eiter;
+ BMFace *efa;
+ BMEdge *eed;
+ int ok;
+ int change = FALSE;
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
+ continue;
+
+
+ ok = TRUE;
+ BM_ITER(eed, &eiter, bm, BM_EDGES_OF_FACE, efa) {
+ if (BM_edge_face_count(eed) < 3) {
+ ok = FALSE;
+ break;
+ }
+ }
+
+ if (ok) {
+ BM_elem_select_set(bm, efa, TRUE);
+ change = TRUE;
+ }
+ }
+
+ return change;
+}
+
+static void linked_limit_default(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "limit")) {
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ if (em->selectmode == SCE_SELECT_FACE)
+ RNA_boolean_set(op->ptr, "limit", TRUE);
+ else
+ RNA_boolean_set(op->ptr, "limit", FALSE);
+ }
+}
+
+static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ ViewContext vc;
+ BMesh *bm;
+ BMWalker walker;
+ BMEditMesh *em;
+ BMVert *eve;
+ BMEdge *e, *eed;
+ BMFace *efa;
+ 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);
+ em = vc.em;
+
+ if (em->bm->totedge == 0)
+ return OPERATOR_CANCELLED;
+
+ bm = em->bm;
+
+ vc.mval[0] = event->mval[0];
+ vc.mval[1] = event->mval[1];
+
+ /* return warning! */
+
+ if (unified_findnearest(&vc, &eve, &eed, &efa) == 0) {
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_CANCELLED;
+ }
+
+ if (em->selectmode == SCE_SELECT_FACE) {
+ BMIter iter;
+
+ if (efa == NULL)
+ return OPERATOR_CANCELLED;
+
+ if (limit) {
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(e, BM_ELEM_SEAM)) BMO_elem_flag_enable(bm, e, BM_ELEM_SELECT);
+ else BMO_elem_flag_disable(bm, e, BM_ELEM_SELECT); /* is this needed ? */
+ }
+ }
+
+ /* walk */
+ BMW_init(&walker, bm, BMW_ISLAND,
+ BMW_MASK_NOP, limit ? BM_ELEM_SELECT : BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_NIL_LAY);
+
+ e = BMW_begin(&walker, efa);
+ for (; efa; efa = BMW_step(&walker)) {
+ BM_elem_select_set(bm, efa, sel);
+ }
+ BMW_end(&walker);
+ }
+ else {
+ if (efa) {
+ eed = BM_FACE_FIRST_LOOP(efa)->e;
+ }
+ else if (!eed) {
+ if (!eve || !eve->e)
+ return OPERATOR_CANCELLED;
+
+ eed = eve->e;
+ }
+
+ BMW_init(&walker, bm, BMW_SHELL,
+ BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_NIL_LAY);
+
+ e = BMW_begin(&walker, eed->v1);
+ for ( ; e; e = BMW_step(&walker)) {
+ BM_elem_select_set(bm, e, sel);
+ }
+ BMW_end(&walker);
+ }
+
+ 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;
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMVert *v;
+ BMEdge *e;
+ BMWalker walker;
+
+ int limit;
+
+ linked_limit_default(C, op);
+
+ limit = RNA_boolean_get(op->ptr, "limit");
+
+ if (em->selectmode == SCE_SELECT_FACE) {
+ BMFace *efa;
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ }
+ }
+
+ if (limit) {
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(e, BM_ELEM_SEAM)) BMO_elem_flag_enable(bm, e, BM_ELEM_SELECT);
+ else BMO_elem_flag_disable(bm, e, BM_ELEM_SELECT); /* is this needed ? */
+ }
+ }
+
+ BMW_init(&walker, bm, BMW_ISLAND,
+ BMW_MASK_NOP, limit ? BM_ELEM_SELECT : BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_NIL_LAY);
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ e = BMW_begin(&walker, efa);
+ for (; efa; efa = BMW_step(&walker)) {
+ BM_elem_select_set(bm, efa, TRUE);
+ }
+ }
+ }
+ BMW_end(&walker);
+ }
+ else {
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) && !BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ }
+ }
+
+ BMW_init(&walker, em->bm, BMW_SHELL,
+ BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_NIL_LAY);
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ e = BMW_begin(&walker, v);
+ for (; e; e = BMW_step(&walker)) {
+ BM_elem_select_set(em->bm, e->v1, TRUE);
+ BM_elem_select_set(em->bm, e->v2, TRUE);
+ }
+ }
+ }
+ BMW_end(&walker);
+ }
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
+
+ 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 *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = (((Mesh *)obedit->data))->edit_btmesh;
+
+ EDBM_select_more(em);
+
+ 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 *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = (((Mesh *)obedit->data))->edit_btmesh;
+
+ EDBM_select_less(em);
+
+ 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;
+}
+
+/* Walk all reachable elements of the same type as h_act in breadth-first
+ order, starting from h_act. Deselects elements if the depth when they
+ are reached is not a multiple of "nth". */
+static void walker_deselect_nth(BMEditMesh *em, int nth, int offset, BMHeader *h_act)
+{
+ BMHeader *h;
+ BMesh *bm = em->bm;
+ BMWalker walker;
+ BMIter iter;
+ int walktype = 0, itertype = 0, flushtype = 0;
+ short mask_vert = 0, mask_edge = 0, mask_loop = 0, mask_face = 0;
+
+ /* No active element from which to start - nothing to do */
+ if (h_act == NULL) {
+ return;
+ }
+
+ /* Determine which type of iter, walker, and select flush to use
+ * based on type of the elements being deselected */
+ switch (h_act->htype) {
+ case BM_VERT:
+ itertype = BM_VERTS_OF_MESH;
+ walktype = BMW_CONNECTED_VERTEX;
+ flushtype = SCE_SELECT_VERTEX;
+ mask_vert = BM_ELEM_SELECT;
+ break;
+ case BM_EDGE:
+ itertype = BM_EDGES_OF_MESH;
+ walktype = BMW_SHELL;
+ flushtype = SCE_SELECT_EDGE;
+ mask_edge = BM_ELEM_SELECT;
+ break;
+ case BM_FACE:
+ itertype = BM_FACES_OF_MESH;
+ walktype = BMW_ISLAND;
+ flushtype = SCE_SELECT_FACE;
+ mask_face = BM_ELEM_SELECT;
+ break;
+ }
+
+ /* Walker restrictions uses BMO flags, not header flags,
+ * so transfer BM_ELEM_SELECT from HFlags onto a BMO flag layer. */
+ BMO_push(bm, NULL);
+ BM_ITER(h, &iter, bm, itertype, NULL) {
+ if (BM_elem_flag_test(h, BM_ELEM_SELECT)) {
+ BMO_elem_flag_enable(bm, (BMElemF *)h, BM_ELEM_SELECT);
+ }
+ }
+
+ /* Walk over selected elements starting at active */
+ BMW_init(&walker, bm, walktype,
+ mask_vert, mask_edge, mask_loop, mask_face,
+ BMW_NIL_LAY);
+
+ BLI_assert(walker.order == BMW_BREADTH_FIRST);
+ for (h = BMW_begin(&walker, h_act); h != NULL; h = BMW_step(&walker)) {
+ /* Deselect elements that aren't at "nth" depth from active */
+ if ((offset + BMW_current_depth(&walker)) % nth) {
+ BM_elem_select_set(bm, h, FALSE);
+ }
+ }
+ BMW_end(&walker);
+
+ BMO_pop(bm);
+
+ /* Flush selection up */
+ EDBM_selectmode_flush_ex(em, flushtype);
+}
+
+static void deselect_nth_active(BMEditMesh *em, BMVert **v_p, BMEdge **e_p, BMFace **f_p)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+ BMIter iter;
+ BMEditSelection *ese;
+
+ *v_p = NULL;
+ *e_p = NULL;
+ *f_p = NULL;
+
+ EDBM_selectmode_flush(em);
+ ese = (BMEditSelection *)em->bm->selected.last;
+
+ if (ese) {
+ switch(ese->htype) {
+ case BM_VERT:
+ *v_p = (BMVert *)ese->data;
+ return;
+ case BM_EDGE:
+ *e_p = (BMEdge *)ese->data;
+ return;
+ case BM_FACE:
+ *f_p = (BMFace *)ese->data;
+ return;
+ }
+ }
+
+ if (em->selectmode & SCE_SELECT_VERTEX) {
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ *v_p = v;
+ return;
+ }
+ }
+ }
+ else if (em->selectmode & SCE_SELECT_EDGE) {
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ *e_p = e;
+ return;
+ }
+ }
+ }
+ else if (em->selectmode & SCE_SELECT_FACE) {
+ f = BM_active_face_get(em->bm, TRUE);
+ if (f) {
+ *f_p = f;
+ return;
+ }
+ }
+}
+
+static int EM_deselect_nth(BMEditMesh *em, int nth, int offset)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ deselect_nth_active(em, &v, &e, &f);
+
+ if (v) {
+ walker_deselect_nth(em, nth, offset, &v->head);
+ return 1;
+ }
+ else if (e) {
+ walker_deselect_nth(em, nth, offset, &e->head);
+ return 1;
+ }
+ else if (f) {
+ walker_deselect_nth(em, nth, offset, &f->head);
+ return 1;
+ }
+
+ return 0;
+}
+
+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");
+ int offset = RNA_int_get(op->ptr, "offset");
+
+ offset = MIN2(nth, offset);
+
+ if (EM_deselect_nth(em, nth, offset) == 0) {
+ BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face");
+ 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_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);
+ RNA_def_int(ot->srna, "offset", 0, 0, 100, "Offset", "", 0, INT_MAX);
+}
+
+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;
+ BMLoop *l1, *l2;
+ float sharp = RNA_float_get(op->ptr, "sharpness"), angle;
+
+ sharp = DEG2RADF(sharp);
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) || !e->l)
+ continue;
+
+ l1 = e->l;
+ l2 = l1->radial_next;
+
+ if (l1 == l2)
+ continue;
+
+ /* edge has exactly two neighboring faces, check angle */
+ angle = angle_normalized_v3v3(l1->f->no, l2->f->no);
+
+ if (fabsf(angle) > sharp) {
+ BM_elem_select_set(em->bm, e, TRUE);
+ }
+
+ }
+
+ 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) {
+ BM_elem_flag_disable(f, BM_ELEM_TAG);
+ }
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN) || !BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_TAG))
+ continue;
+
+ BLI_array_empty(stack);
+ i = 1;
+
+ BLI_array_growone(stack);
+ stack[i - 1] = f;
+
+ while (i) {
+ f = stack[i - 1];
+ i--;
+
+ BM_elem_select_set(em->bm, f, TRUE);
+
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
+
+ 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 (BM_elem_flag_test(l2->f, BM_ELEM_TAG) || BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN))
+ continue;
+
+ /* edge has exactly two neighboring faces, check angle */
+ angle = angle_normalized_v3v3(f->no, l2->f->no);
+
+ /* invalidate: edge too sharp */
+ if (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_elem_flag_test(em->bm, BM_ELEM_HIDDEN) && !BM_vert_is_manifold(em->bm, v)) {
+ BM_elem_select_set(em->bm, v, TRUE);
+ }
+ }
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(em->bm, BM_ELEM_HIDDEN) && BM_edge_face_count(e) != 2) {
+ BM_elem_select_set(em->bm, e, TRUE);
+ }
+ }
+
+ 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_flag_disable_all(em, BM_ELEM_SELECT);
+
+ if (em->selectmode & SCE_SELECT_VERTEX) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BLI_frand() < randfac) {
+ BM_elem_select_set(em->bm, eve, TRUE);
+ }
+ }
+ EDBM_selectmode_flush(em);
+ }
+ else if (em->selectmode & SCE_SELECT_EDGE) {
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BLI_frand() < randfac) {
+ BM_elem_select_set(em->bm, eed, TRUE);
+ }
+ }
+ EDBM_selectmode_flush(em);
+ }
+ else {
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BLI_frand() < randfac) {
+ BM_elem_select_set(em->bm, efa, TRUE);
+ }
+ }
+ 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");
+}
+
+static int select_next_loop(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = (((Mesh *)obedit->data))->edit_btmesh;
+ BMFace *f;
+ BMVert *v;
+ BMIter iter;
+
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ }
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BMLoop *l;
+ BMIter liter;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) && !BM_elem_flag_test(l->v, BM_ELEM_HIDDEN)) {
+ BM_elem_flag_enable(l->next->v, BM_ELEM_TAG);
+ BM_elem_select_set(em->bm, l->v, FALSE);
+ }
+ }
+ }
+
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ BM_elem_select_set(em->bm, v, TRUE);
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_next_loop(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Next Loop";
+ ot->idname = "MESH_OT_select_next_loop";
+ ot->description = "";
+
+ /* api callbacks */
+ ot->exec = select_next_loop;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+
+static int region_to_loop(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ BMFace *f;
+ BMEdge *e;
+ BMIter iter;
+ ViewContext vc;
+
+ em_setup_viewcontext(C, &vc);
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ }
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BMLoop *l1, *l2;
+ BMIter liter1, liter2;
+
+ BM_ITER(l1, &liter1, em->bm, BM_LOOPS_OF_FACE, f) {
+ int tot = 0, totsel = 0;
+
+ BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_EDGE, l1->e) {
+ tot++;
+ totsel += BM_elem_flag_test(l2->f, BM_ELEM_SELECT) != 0;
+ }
+
+ if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1))
+ BM_elem_flag_enable(l1->e, BM_ELEM_TAG);
+ }
+ }
+
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
+ BM_edge_select_set(em->bm, e, TRUE);
+ }
+
+ /* If in face-only select mode, switch to edge select mode so that
+ an edge-only selection is not inconsistent state */
+ if (em->selectmode == SCE_SELECT_FACE) {
+ em->selectmode = SCE_SELECT_EDGE;
+ EDBM_selectmode_set(em);
+ EDBM_selectmode_to_scene(C);
+ }
+
+ 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 = "Select Boundary 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_find_region(BMEditMesh *em, BMLoop *l, int flag,
+ SmallHash *fhash, BMFace ***region_out)
+{
+ BLI_array_declare(region);
+ BLI_array_declare(stack);
+ BMFace **region = NULL, *f;
+ BMFace **stack = NULL;
+
+ BLI_array_append(stack, l->f);
+ BLI_smallhash_insert(fhash, (uintptr_t)l->f, NULL);
+
+ while (BLI_array_count(stack) > 0) {
+ BMIter liter1, liter2;
+ BMLoop *l1, *l2;
+
+ f = BLI_array_pop(stack);
+ BLI_array_append(region, f);
+
+ BM_ITER(l1, &liter1, em->bm, BM_LOOPS_OF_FACE, f) {
+ if (BM_elem_flag_test(l1->e, flag))
+ continue;
+
+ BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_EDGE, l1->e) {
+ if (BLI_smallhash_haskey(fhash, (uintptr_t)l2->f))
+ continue;
+
+ BLI_array_append(stack, l2->f);
+ BLI_smallhash_insert(fhash, (uintptr_t)l2->f, NULL);
+ }
+ }
+ }
+
+ BLI_array_free(stack);
+
+ *region_out = region;
+ return BLI_array_count(region);
+}
+
+static int verg_radial(const void *va, const void *vb)
+{
+ BMEdge *e1 = *((void **)va);
+ BMEdge *e2 = *((void **)vb);
+ int a, b;
+
+ a = BM_edge_face_count(e1);
+ b = BM_edge_face_count(e2);
+
+ if (a > b) return -1;
+ if (a == b) return 0;
+ if (a < b) return 1;
+
+ return -1;
+}
+
+static int loop_find_regions(BMEditMesh *em, int selbigger)
+{
+ SmallHash visithash;
+ BMIter iter;
+ BMEdge *e, **edges = NULL;
+ BLI_array_declare(edges);
+ BMFace *f;
+ int count = 0, i;
+
+ BLI_smallhash_init(&visithash);
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BM_elem_flag_disable(f, BM_ELEM_TAG);
+ }
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ BLI_array_append(edges, e);
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ }
+ }
+
+ /* sort edges by radial cycle length */
+ qsort(edges, BLI_array_count(edges), sizeof(void *), verg_radial);
+
+ for (i = 0; i < BLI_array_count(edges); i++) {
+ BMIter liter;
+ BMLoop *l;
+ BMFace **region = NULL, **r;
+ int c, tot = 0;
+
+ e = edges[i];
+
+ if (!BM_elem_flag_test(e, BM_ELEM_TAG))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_EDGE, e) {
+ if (BLI_smallhash_haskey(&visithash, (uintptr_t)l->f))
+ continue;
+
+ c = loop_find_region(em, l, BM_ELEM_SELECT, &visithash, &r);
+
+ if (!region || (selbigger ? c >= tot : c < tot)) {
+ /* this region is the best seen so far */
+ tot = c;
+ if (region) {
+ /* free the previous best */
+ MEM_freeN(region);
+ }
+ /* track the current region as the new best */
+ region = r;
+ }
+ else {
+ /* this region is not as good as best so far, just free it */
+ MEM_freeN(r);
+ }
+ }
+
+ if (region) {
+ int j;
+
+ for (j = 0; j < tot; j++) {
+ BM_elem_flag_enable(region[j], BM_ELEM_TAG);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, region[j]) {
+ BM_elem_flag_disable(l->e, BM_ELEM_TAG);
+ }
+ }
+
+ count += tot;
+
+ MEM_freeN(region);
+ }
+ }
+
+ BLI_array_free(edges);
+ BLI_smallhash_release(&visithash);
+
+ return count;
+}
+
+static int loop_to_region(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ BMIter iter;
+ BMFace *f;
+ int selbigger = RNA_boolean_get(op->ptr, "select_bigger");
+ int a, b;
+
+ /* find the set of regions with smallest number of total faces */
+ a = loop_find_regions(em, selbigger);
+ b = loop_find_regions(em, !selbigger);
+
+ if ((a <= b) ^ selbigger) {
+ loop_find_regions(em, selbigger);
+ }
+
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(f, BM_ELEM_TAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ BM_face_select_set(em->bm, f, TRUE);
+ }
+ }
+
+ 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 = "Select Loop Inner-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;
+
+ RNA_def_boolean(ot->srna, "select_bigger", 0, "Select Bigger", "Select bigger regions instead of smaller ones");
+}
diff --git a/source/blender/editors/mesh/bmesh_selecthistory.c b/source/blender/editors/mesh/bmesh_selecthistory.c
new file mode 100644
index 00000000000..a242356f1ab
--- /dev/null
+++ b/source/blender/editors/mesh/bmesh_selecthistory.c
@@ -0,0 +1,69 @@
+/*
+ * ***** 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 *****
+ */
+
+/* ********* Selection History ************ */
+
+#include "BKE_tessmesh.h"
+
+
+/* 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 along 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_select_history_remove(em->bm, data);
+}
+
+void EDBM_store_selection(BMEditMesh *em, void *data)
+{
+ BM_select_history_store(em->bm, data);
+}
+
+void EDBM_validate_selections(BMEditMesh *em)
+{
+ BM_select_history_validate(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..b403aaca5dc
--- /dev/null
+++ b/source/blender/editors/mesh/bmesh_tools.c
@@ -0,0 +1,4690 @@
+/*
+ * ***** 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): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_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_rand.h"
+
+#include "BKE_material.h"
+#include "BKE_context.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_depsgraph.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+#include "BKE_texture.h"
+#include "BKE_main.h"
+#include "BKE_tessmesh.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+#include "ED_view3d.h"
+#include "ED_screen.h"
+#include "ED_transform.h"
+#include "ED_object.h"
+
+#include "RE_render_ext.h"
+
+#include "mesh_intern.h"
+
+
+static void add_normal_aligned(float nor[3], const float add[3])
+{
+ if (dot_v3v3(nor, add) < -0.9999f)
+ sub_v3_v3(nor, add);
+ else
+ sub_v3_v3(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")/2.5;
+ int flag = 0;
+
+ if (smooth != 0.0f)
+ flag |= B_SMOOTH;
+ if (fractal != 0.0f)
+ flag |= B_FRACTAL;
+
+ if (RNA_boolean_get(op->ptr, "quadtri") &&
+ RNA_enum_get(op->ptr, "quadcorner") == SUBD_STRAIGHT_CUT)
+ {
+ RNA_enum_set(op->ptr, "quadcorner", SUBD_INNERVERT);
+ }
+
+ BM_mesh_esubdivideflag(obedit, em->bm, BM_ELEM_SELECT,
+ smooth, fractal,
+ ts->editbutflag|flag,
+ cuts, 0, RNA_enum_get(op->ptr, "quadcorner"),
+ RNA_boolean_get(op->ptr, "quadtri"),
+ 1, RNA_int_get(op->ptr, "seed"));
+
+ 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, INT_MAX, "Number of Cuts", "", 1, 10);
+ /* BMESH_TODO, this currently does nothing, just add to stop UI from erroring out! */
+ RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor (BMESH TODO)", 0.0f, 1.0f);
+
+ RNA_def_boolean(ot->srna, "quadtri", 0, "Quad/Tri Mode", "Tries to prevent ngons");
+ RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_STRAIGHT_CUT,
+ "Quad Corner Type", "How to subdivide quad corners (anything other then Straight Cut will prevent ngons)");
+
+ RNA_def_float(ot->srna, "fractal", 0.0f, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor", 0.0f, 1000.0f);
+ RNA_def_int(ot->srna, "seed", 0, 0, 10000, "Random Seed", "Seed for the random number generator", 0, 50);
+}
+
+
+void EMBM_project_snap_verts(bContext *C, ARegion *ar, Object *obedit, BMEditMesh *em)
+{
+ BMIter iter;
+ BMVert *eve;
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(eve, BM_ELEM_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);
+ }
+ }
+ }
+}
+
+
+/* individual face extrude */
+/* will use vertex normals for extrusion directions, so *nor is unaffected */
+static short EDBM_Extrude_face_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor))
+{
+ BMOIter siter;
+ BMIter liter;
+ BMFace *f;
+ BMLoop *l;
+ BMOperator bmop;
+
+ EDBM_InitOpf(em, &bmop, op, "extrude_face_indiv faces=%hf", hflag);
+
+ /* deselect original verts */
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+
+ BMO_op_exec(em->bm, &bmop);
+
+ BMO_ITER(f, &siter, em->bm, &bmop, "faceout", BM_FACE) {
+ BM_elem_select_set(em->bm, f, TRUE);
+
+ /* set face vertex normals to face normal */
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
+ copy_v3_v3(l->v->no, f->no);
+ }
+ }
+
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ return 0;
+ }
+
+ return 's'; // s is shrink/fatten
+}
+
+/* extrudes individual edges */
+static short EDBM_Extrude_edges_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor))
+{
+ BMOperator bmop;
+
+ EDBM_InitOpf(em, &bmop, op, "extrude_edge_only edges=%he", hflag);
+
+ /* deselect original verts */
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+
+ BMO_op_exec(em->bm, &bmop);
+ BMO_slot_buffer_hflag_enable(em->bm, &bmop, "geomout", BM_ELEM_SELECT, BM_VERT|BM_EDGE);
+
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ return 0;
+ }
+
+ return 'n'; // n is normal grab
+}
+
+/* extrudes individual vertices */
+static short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor))
+{
+ BMOperator bmop;
+
+ EDBM_InitOpf(em, &bmop, op, "extrude_vert_indiv verts=%hv", hflag);
+
+ /* deselect original verts */
+ BMO_slot_buffer_hflag_disable(em->bm, &bmop, "verts", BM_ELEM_SELECT, BM_VERT);
+
+ BMO_op_exec(em->bm, &bmop);
+ BMO_slot_buffer_hflag_enable(em->bm, &bmop, "vertout", BM_ELEM_SELECT, BM_VERT);
+
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ return 0;
+ }
+
+ return 'g'; // g is grab
+}
+
+static short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, const char hflag, float nor[3])
+{
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMOIter siter;
+ BMOperator extop;
+ BMEdge *edge;
+ BMFace *f;
+ ModifierData *md;
+ BMHeader *el;
+
+ BMO_op_init(bm, &extop, "extrudefaceregion");
+ BMO_slot_from_hflag(bm, &extop, "edgefacein",
+ hflag, 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) && (md->mode & eModifierMode_Realtime)) {
+ MirrorModifierData *mmd = (MirrorModifierData *) md;
+
+ if (mmd->flag & MOD_MIR_CLIPPING) {
+ float mtx[4][4];
+ if (mmd->mirror_ob) {
+ float imtx[4][4];
+ invert_m4_m4(imtx, mmd->mirror_ob->obmat);
+ mult_m4_m4m4(mtx, imtx, obedit->obmat);
+ }
+
+ for (edge = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL);
+ edge;
+ edge = BM_iter_step(&iter))
+ {
+ if (BM_elem_flag_test(edge, hflag)) {
+ float co1[3], co2[3];
+
+ copy_v3_v3(co1, edge->v1->co);
+ copy_v3_v3(co2, edge->v2->co);
+
+ if (mmd->mirror_ob) {
+ mul_v3_m4v3(co1, mtx, co1);
+ mul_v3_m4v3(co2, mtx, co2);
+ }
+
+ if (mmd->flag & MOD_MIR_AXIS_X) {
+ if ( (fabs(co1[0]) < mmd->tolerance) &&
+ (fabs(co2[0]) < mmd->tolerance) )
+ {
+ BMO_slot_map_ptr_insert(bm, &extop, "exclude", edge, NULL);
+ }
+ }
+ if (mmd->flag & MOD_MIR_AXIS_Y) {
+ if ( (fabs(co1[1]) < mmd->tolerance) &&
+ (fabs(co2[1]) < mmd->tolerance) )
+ {
+ BMO_slot_map_ptr_insert(bm, &extop, "exclude", edge, NULL);
+ }
+ }
+ if (mmd->flag & MOD_MIR_AXIS_Z) {
+ if ( (fabs(co1[2]) < mmd->tolerance) &&
+ (fabs(co2[2]) < mmd->tolerance) )
+ {
+ BMO_slot_map_ptr_insert(bm, &extop, "exclude", edge, NULL);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+
+ BMO_op_exec(bm, &extop);
+
+ nor[0] = nor[1] = nor[2] = 0.0f;
+
+ BMO_ITER(el, &siter, bm, &extop, "geomout", BM_ALL) {
+ BM_elem_select_set(bm, el, TRUE);
+
+ if (el->htype == BM_FACE) {
+ f = (BMFace *)el;
+ add_normal_aligned(nor, f->no);
+ };
+ }
+
+ normalize_v3(nor);
+
+ BMO_op_finish(bm, &extop);
+
+ if (nor[0] == 0.0f && nor[1] == 0.0f && nor[2] == 0.0f) return 'g'; // grab
+ return 'n'; // normal constraint
+
+}
+static short EDBM_Extrude_vert(Object *obedit, BMEditMesh *em, const char hflag, float *nor)
+{
+ BMIter iter;
+ BMEdge *eed;
+
+ /* ensure vert flags are consistent for edge selections */
+ eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed = BM_iter_step(&iter)) {
+ if (BM_elem_flag_test(eed, hflag)) {
+ if (hflag & BM_ELEM_SELECT) {
+ BM_elem_select_set(em->bm, eed->v1, TRUE);
+ BM_elem_select_set(em->bm, eed->v2, TRUE);
+ }
+
+ BM_elem_flag_enable(eed->v1, hflag & ~BM_ELEM_SELECT);
+ BM_elem_flag_enable(eed->v2, hflag & ~BM_ELEM_SELECT);
+ }
+ else {
+ if (BM_elem_flag_test(eed->v1, hflag) && BM_elem_flag_test(eed->v2, hflag)) {
+ if (hflag & BM_ELEM_SELECT) {
+ BM_elem_select_set(em->bm, eed, TRUE);
+ }
+
+ BM_elem_flag_enable(eed, hflag & ~BM_ELEM_SELECT);
+ }
+ }
+ }
+
+ return EDBM_Extrude_edge(obedit, em, hflag, 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 */
+ normalize_v3_v3(dvec, rv3d->persinv[2]);
+ mul_v3_fl(dvec, 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_ELEM_SELECT, nor);
+ //BMO_op_callf(em->bm, "extrudefaceregion edgefacein=%hef", BM_ELEM_SELECT);
+ BMO_op_callf(em->bm, "translate vec=%v verts=%hv", (float *)dvec, BM_ELEM_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 */
+static 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, BM_ELEM_SELECT, nor);
+ else if (nr == 1) transmode = EDBM_Extrude_edge(obedit, em, BM_ELEM_SELECT, nor);
+ else if (nr == 4) transmode = EDBM_Extrude_verts_indiv(em, op, BM_ELEM_SELECT, nor);
+ else if (nr == 3) transmode = EDBM_Extrude_edges_indiv(em, op, BM_ELEM_SELECT, nor);
+ else transmode = EDBM_Extrude_face_indiv(em, op, BM_ELEM_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);
+
+ /* This normally happens when pushing undo but modal operators
+ * like this one don't push undo data until after modal mode is
+ * done.*/
+ EDBM_RecalcNormals(em);
+ BMEdit_RecalcTesselation(em);
+
+ 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_ELEM_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_ELEM_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_ELEM_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_flag_disable_all(em, BM_ELEM_SELECT);
+ else
+ EDBM_flag_enable_all(em, BM_ELEM_SELECT);
+}
+
+static int mesh_select_all_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ int action = RNA_enum_get(op->ptr, "action");
+
+ switch (action) {
+ case SEL_TOGGLE:
+ EDBM_toggle_select_all(em);
+ break;
+ case SEL_SELECT:
+ EDBM_flag_enable_all(em, BM_ELEM_SELECT);
+ break;
+ case SEL_DESELECT:
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ break;
+ case SEL_INVERT:
+ EDBM_select_swap(em);
+ break;
+ }
+
+ 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 = mesh_select_all_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ WM_operator_properties_select_all(ot);
+}
+
+static int mesh_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+
+ if (EDBM_select_interior_faces(em)) {
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+
+}
+
+void MESH_OT_select_interior_faces(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Interior Faces";
+ ot->idname = "MESH_OT_select_interior_faces";
+ ot->description = "Select faces where all edges have more than 2 face users";
+
+ /* api callbacks */
+ ot->exec = mesh_faces_select_interior_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/* *************** add-click-mesh (extrude) operator ************** */
+/* in trunk see: 'editmesh_add.c' */
+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;
+ 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);
+
+ INIT_MINMAX(min, max);
+
+ BM_ITER(v1, &iter, vc.em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(v1, BM_ELEM_SELECT)) {
+ DO_MINMAX(v1->co, min, max);
+ done = 1;
+ }
+ }
+
+ /* call extrude? */
+ if (done) {
+ const short rot_src = RNA_boolean_get(op->ptr, "rotate_source");
+ BMEdge *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];
+
+ /* 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_elem_flag_test(eed, BM_ELEM_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, TRUE);
+ 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 = dot_v3v3(vec, nor);
+
+ if (fabsf(dot) < 0.999f) {
+ 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 = sinf(dot);
+ q1[0] = cosf(dot);
+ q1[1] = cross[0] * si;
+ q1[2] = cross[1] * si;
+ q1[3] = cross[2] * si;
+ quat_to_mat3(mat, q1);
+ }
+ }
+
+ if (rot_src) {
+ EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
+ BM_ELEM_SELECT, cent, mat);
+
+ /* also project the source, for retopo workflow */
+ if (use_proj)
+ EMBM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);
+ }
+
+ EDBM_Extrude_edge(vc.obedit, vc.em, BM_ELEM_SELECT, nor);
+ EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
+ BM_ELEM_SELECT, cent, mat);
+ EDBM_CallOpf(vc.em, op, "translate verts=%hv vec=%v",
+ BM_ELEM_SELECT, min);
+ }
+ else {
+ float *curs = give_cursor(vc.scene, vc.v3d);
+ BMOperator bmop;
+ BMOIter oiter;
+
+ copy_v3_v3(min, curs);
+ view3d_get_view_aligned_coordinate(&vc, min, event->mval, 0);
+
+ 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_op_exec(vc.em->bm, &bmop);
+
+ BMO_ITER(v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) {
+ BM_elem_select_set(vc.em->bm, v1, TRUE);
+ }
+
+ if (!EDBM_FinishOp(vc.em, &bmop, op, TRUE)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (use_proj)
+ EMBM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);
+
+ /* This normally happens when pushing undo but modal operators
+ * like this one don't push undo data until after modal mode is
+ * done. */
+ EDBM_RecalcNormals(vc.em);
+ BMEdit_RecalcTesselation(vc.em);
+
+ 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;
+
+ RNA_def_boolean(ot->srna, "rotate_source", 1, "Rotate Source", "Rotate initial selection giving better shape");
+}
+
+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_ELEM_SELECT, DEL_VERTS))
+ return OPERATOR_CANCELLED;
+ }
+ else if (event == 11) {
+ //"Edge Loop"
+ if (!EDBM_CallOpf(bem, op, "dissolveedgeloop edges=%he", BM_ELEM_SELECT))
+ return OPERATOR_CANCELLED;
+ }
+ else if (event == 7) {
+ int use_verts = RNA_boolean_get(op->ptr, "use_verts");
+ //"Dissolve"
+ if (bem->selectmode & SCE_SELECT_FACE) {
+ if (!EDBM_CallOpf(bem, op, "dissolvefaces faces=%hf use_verts=%i", BM_ELEM_SELECT, use_verts))
+ return OPERATOR_CANCELLED;
+ }
+ else if (bem->selectmode & SCE_SELECT_EDGE) {
+ if (!EDBM_CallOpf(bem, op, "dissolveedges edges=%he use_verts=%i", BM_ELEM_SELECT, use_verts))
+ return OPERATOR_CANCELLED;
+ }
+ else if (bem->selectmode & SCE_SELECT_VERTEX) {
+ if (!EDBM_CallOpf(bem, op, "dissolveverts verts=%hv", BM_ELEM_SELECT))
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else if (event == 4) {
+ //Edges and Faces
+ if (!EDBM_CallOpf(bem, op, "del geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES))
+ return OPERATOR_CANCELLED;
+ }
+ else if (event == 1) {
+ //"Erase Edges"
+ if (!EDBM_CallOpf(bem, op, "del geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES))
+ return OPERATOR_CANCELLED;
+ }
+ else if (event == 2) {
+ //"Erase Faces";
+ if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES))
+ return OPERATOR_CANCELLED;
+ }
+ else if (event == 5) {
+ //"Erase Only Faces";
+ if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%d",
+ BM_ELEM_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", ""},
+ {12, "COLLAPSE", 0, "Collapse", ""},
+ {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);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ Scene *scene = CTX_data_scene(C);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ if (type != 12) {
+ if (delete_mesh(C, obedit, op, type, scene) == OPERATOR_CANCELLED)
+ return OPERATOR_CANCELLED;
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ }
+ else {
+ if (!EDBM_CallOpf(em, op, "collapse edges=%he", BM_ELEM_SELECT))
+ return OPERATOR_CANCELLED;
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ }
+
+ 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");
+
+ /* TODO, move dissolve into its own operator so this doesnt confuse non-dissolve options */
+ RNA_def_boolean(ot->srna, "use_verts", 0, "Dissolve Verts",
+ "When dissolving faaces/edges, also dissolve remaining vertices");
+}
+
+
+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_ELEM_SELECT))
+ return OPERATOR_CANCELLED;
+
+ BMO_op_exec(em->bm, &bmop);
+ BMO_slot_buffer_hflag_enable(em->bm, &bmop, "faceout", BM_ELEM_SELECT, BM_FACE);
+
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ 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;
+}
+
+/* ************************* 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(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
+ continue;
+
+ BM_elem_flag_disable(eed, BM_ELEM_SEAM);
+ }
+ }
+ else {
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
+ continue;
+ BM_elem_flag_enable(eed, BM_ELEM_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(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
+ continue;
+
+ BM_elem_flag_disable(eed, BM_ELEM_SMOOTH);
+ }
+ }
+ else {
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
+ continue;
+
+ BM_elem_flag_enable(eed, BM_ELEM_SMOOTH);
+ }
+ }
+
+
+ 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;
+
+ if (!EDBM_InitOpf(em, &bmop, op, "connectverts verts=%hv", BM_ELEM_SELECT)) {
+ return OPERATOR_CANCELLED;
+ }
+ BMO_op_exec(bm, &bmop);
+ len = BMO_slot_get(&bmop, "edgeout")->len;
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ 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;
+
+ if (!EDBM_InitOpf(em, &bmop, op, "edgesplit edges=%he numcuts=%d",
+ BM_ELEM_SELECT, RNA_int_get(op->ptr,"number_cuts"))) {
+ return OPERATOR_CANCELLED;
+ }
+ BMO_op_exec(bm, &bmop);
+ len = BMO_slot_get(&bmop, "outsplit")->len;
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ 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_ELEM_SELECT);
+
+ BMO_op_exec(em->bm, &bmop);
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+
+ BMO_slot_buffer_hflag_enable(em->bm, &bmop, "newout", BM_ELEM_SELECT, BM_ALL);
+
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ 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 *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);
+}
+
+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_ELEM_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;
+}
+
+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;
+ const int do_ccw = RNA_enum_get(op->ptr, "direction") == 1;
+ int do_deselect = FALSE; /* do we deselect */
+
+ 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_face_count(eed) == 2) {
+ if ((BM_elem_flag_test(eed->l->f, BM_ELEM_SELECT) && BM_elem_flag_test(eed->l->radial_next->f, BM_ELEM_SELECT))
+ && !(BM_elem_flag_test(eed->l->f, BM_ELEM_HIDDEN) || BM_elem_flag_test(eed->l->radial_next->f, BM_ELEM_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(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ /* de-select the edge before */
+ do_deselect = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* this should never happen */
+ if (!eed)
+ return OPERATOR_CANCELLED;
+
+ EDBM_InitOpf(em, &bmop, op, "edgerotate edges=%e ccw=%d", eed, do_ccw);
+
+ /* avoid adding to the selection if we start off with only a selected edge,
+ * we could also just deselect the single edge easily but use the BMO api
+ * since it seems this is more 'correct' */
+ if (do_deselect) BMO_slot_buffer_hflag_disable(em->bm, &bmop, "edges", BM_ELEM_SELECT, BM_EDGE);
+
+ BMO_op_exec(em->bm, &bmop);
+ BMO_slot_buffer_hflag_enable(em->bm, &bmop, "edgeout", BM_ELEM_SELECT, BM_EDGE);
+
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ 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");
+}
+
+/* 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_elem_flag_test(h, BM_ELEM_SELECT) ^ swap)
+ BM_elem_hide_set(em->bm, h, TRUE);
+ }
+
+ EDBM_selectmode_flush(em);
+
+ /* 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)
+{
+ const char iter_types[3] = {BM_VERTS_OF_MESH,
+ BM_EDGES_OF_MESH,
+ BM_FACES_OF_MESH};
+
+ int sels[3] = {(em->selectmode & SCE_SELECT_VERTEX),
+ (em->selectmode & SCE_SELECT_EDGE),
+ (em->selectmode & SCE_SELECT_FACE),
+ };
+
+ BMIter iter;
+ BMHeader *ele;
+ int i;
+
+ /* Use index field to remember what was hidden before all is revealed. */
+ for (i = 0; i < 3; i++) {
+ BM_ITER(ele, &iter, em->bm, iter_types[i], NULL) {
+ if (BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
+ BM_elem_flag_enable(ele, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_disable(ele, BM_ELEM_TAG);
+ }
+ }
+ }
+
+ /* Reveal everything */
+ EDBM_flag_disable_all(em, BM_ELEM_HIDDEN);
+
+ /* Select relevant just-revealed elements */
+ for (i = 0; i < 3; i++) {
+ if (!sels[i]) {
+ continue;
+ }
+
+ BM_ITER(ele, &iter, em->bm, iter_types[i], NULL) {
+ if (BM_elem_flag_test(ele, BM_ELEM_TAG)) {
+ BM_elem_select_set(em->bm, ele, TRUE);
+ }
+ }
+ }
+
+ EDBM_selectmode_flush(em);
+}
+
+static int reveal_mesh_exec(bContext *C, wmOperator *UNUSED(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;
+
+ /* doflip has to do with bmesh_rationalize_normals, it's an internal
+ * thing */
+ if (!EDBM_CallOpf(em, op, "righthandfaces faces=%hf doflip=%d", BM_ELEM_SELECT, 1))
+ return OPERATOR_CANCELLED;
+
+ if (RNA_boolean_get(op->ptr, "inside"))
+ EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_ELEM_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;
+ float clipdist = 0.0f;
+
+ /* mirror before smooth */
+ if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
+ EDBM_CacheMirrorVerts(em, TRUE);
+ }
+
+ /* 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 && (md->mode & eModifierMode_Realtime)) {
+ 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;
+
+ clipdist = mmd->tolerance;
+ }
+ }
+ }
+
+ 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 clipdist=%f",
+ BM_ELEM_SELECT, mirrx, mirry, mirrz, clipdist))
+ {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ /* apply mirror */
+ if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
+ EDBM_ApplyMirrorCache(em, BM_ELEM_SELECT, 0);
+ EDBM_EndMirrorCache(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_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 *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ ARegion *ar = CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ BMBVHTree *tree = BMBVH_NewBVH(em, 0, NULL, NULL);
+ BMIter iter;
+ BMEdge *e;
+
+ /* hide all back edges */
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(e, BM_ELEM_SELECT))
+ continue;
+
+ if (!BMBVH_EdgeVisible(tree, e, ar, v3d, obedit))
+ BM_elem_select_set(em->bm, e, FALSE);
+ }
+
+ 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, BMW_NIL_LAY);
+
+ 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 *************************/
+
+static 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_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ if (smooth)
+ BM_elem_flag_enable(efa, BM_ELEM_SMOOTH);
+ else
+ BM_elem_flag_disable(efa, BM_ELEM_SMOOTH);
+ }
+ }
+}
+
+static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(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 *UNUSED(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_ELEM_SELECT, dir);
+
+ /* execute the operator */
+ BMO_op_exec(em->bm, &bmop);
+
+ /* finish the operator */
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ 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);
+
+ /* 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_ELEM_SELECT);
+
+ /* execute the operator */
+ BMO_op_exec(em->bm, &bmop);
+
+ /* finish the operator */
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ 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);
+
+ /* 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_ELEM_SELECT, dir);
+
+ /* execute the operator */
+ BMO_op_exec(em->bm, &bmop);
+
+ /* finish the operator */
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ 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_ELEM_SELECT);
+
+ /* execute the operator */
+ BMO_op_exec(em->bm, &bmop);
+
+ /* finish the operator */
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ 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;
+}
+
+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_CCW, "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_elem_flag_test(mergevert, BM_ELEM_SELECT))
+ return OPERATOR_CANCELLED;
+
+ if (uvmerge) {
+ if (!EDBM_CallOpf(em, wmop, "pointmerge_facedata verts=%hv snapv=%e", BM_ELEM_SELECT, mergevert))
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_ELEM_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};
+
+ if (target) {
+ vco = give_cursor(scene, v3d);
+ copy_v3_v3(co, vco);
+ mul_m4_v3(ob->imat, co);
+ }
+ else {
+ float fac;
+ int i = 0;
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(v, BM_ELEM_SELECT))
+ continue;
+ add_v3_v3(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_ELEM_SELECT))
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_ELEM_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_ELEM_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 *UNUSED(ptr), PropertyRNA *UNUSED(prop), 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)->htype == BM_VERT &&
+ ((BMEditSelection *)em->bm->selected.last)->htype == 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)->htype == BM_VERT) {
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
+ }
+ else if (em->bm->selected.last && ((BMEditSelection *)em->bm->selected.last)->htype == 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_ELEM_SELECT, RNA_float_get(op->ptr, "mergedist"));
+ BMO_op_exec(em->bm, &bmop);
+
+ count = BMO_slot_map_count(em->bm, &bmop, "targetmapout");
+
+ if (!EDBM_CallOpf(em, op, "weldverts targetmap=%s", &bmop, "targetmapout")) {
+ BMO_op_finish(em->bm, &bmop);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s", count, (count==1)?"ex":"ices");
+
+
+ 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;
+
+
+
+static 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->htype != BM_VERT) || (ev->htype != 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_op_exec(em->bm, &bmop);
+
+ /* DO NOT clear the existing selection */
+ /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
+
+ /* select the output */
+ BMO_slot_buffer_hflag_enable(em->bm, &bmop, "vertout", BM_ELEM_SELECT, BM_ALL);
+
+ /* finish the operator */
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ 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;
+}
+
+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->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 *************************/
+
+/* helper to find edge for edge_rip */
+static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *co2, const int mval[2])
+{
+ float vec1[3], vec2[3], mvalf[2];
+
+ ED_view3d_project_float(ar, co1, vec1, mat);
+ ED_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);
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMOperator bmop;
+ BMBVHTree *bvhtree;
+ BMOIter siter;
+ BMIter iter, eiter, liter;
+ BMLoop *l;
+ BMEdge *e, *e2, *closest = NULL;
+ BMVert *v, *ripvert = NULL;
+ int side = 0, i, singlesel = 0;
+ float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
+ float dist = FLT_MAX, d;
+
+ ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ }
+ }
+
+ /* handle case of one vert selected. identify
+ * closest edge around that vert to mouse cursor,
+ * then rip two adjacent edges in the vert fan. */
+ if (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0) {
+ singlesel = 1;
+
+ /* find selected vert */
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT))
+ break;
+ }
+
+ /* this should be impossible, but sanity checks are a good thing */
+ if (!v)
+ return OPERATOR_CANCELLED;
+
+ if (!v->e || !v->e->l) {
+ BKE_report(op->reports, RPT_ERROR, "Selected vertex has no faces");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* find closest edge to mouse cursor */
+ e2 = NULL;
+ BM_ITER(e, &iter, 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_face_count(e2) == 1 || BM_vert_face_count(v) == 2) {
+ l = e2->l;
+ ripvert = BM_vert_rip(bm, l->f, v);
+
+ BLI_assert(ripvert);
+ if (!ripvert) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else if (BM_edge_face_count(e2) == 2) {
+ l = e2->l;
+ e = BM_face_other_loop(e2, l->f, v)->e;
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ BM_elem_select_set(bm, e, TRUE);
+
+ l = e2->l->radial_next;
+ e = BM_face_other_loop(e2, l->f, v)->e;
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ BM_elem_select_set(bm, e, TRUE);
+ }
+
+ dist = FLT_MAX;
+ }
+ else {
+ /* expand edge selection */
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ e2 = NULL;
+ i = 0;
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ e2 = e;
+ i++;
+ }
+ }
+
+ if (i == 1 && e2->l) {
+ l = BM_face_other_loop(e2, e2->l->f, v);
+ l = l->radial_next;
+ l = BM_face_other_loop(l->e, l->f, v);
+
+ if (l) {
+ BM_elem_select_set(bm, l->e, TRUE);
+ }
+ }
+ }
+ }
+
+ if (!EDBM_InitOpf(em, &bmop, op, "edgesplit edges=%he", BM_ELEM_SELECT)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BMO_op_exec(bm, &bmop);
+
+ /* build bvh tree for edge visibility tests */
+ bvhtree = BMBVH_NewBVH(em, 0, NULL, NULL);
+
+ for (i = 0; i < 2; i++) {
+ BMO_ITER(e, &siter, bm, &bmop, i ? "edgeout2":"edgeout1", BM_EDGE) {
+ float cent[3] = {0, 0, 0}, mid[3], vec[3];
+
+ if (!BMBVH_EdgeVisible(bvhtree, e, ar, v3d, 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, bm, BM_LOOPS_OF_FACE, e->l->f) {
+ add_v3_v3(cent, l->v->co);
+ }
+ mul_v3_fl(cent, 1.0f/(float)e->l->f->len);
+
+ mid_v3_v3v3(mid, e->v1->co, e->v2->co);
+ 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 */
+ ED_view3d_project_float(ar, mid, mid, projectMat);
+
+ d = len_squared_v2v2(fmval, mid);
+
+ if (d < dist) {
+ side = i;
+ closest = e;
+ dist = d;
+ }
+ }
+ }
+
+ BMBVH_FreeBVH(bvhtree);
+
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ BMO_slot_buffer_hflag_enable(bm, &bmop, side?"edgeout2":"edgeout1", BM_ELEM_SELECT, BM_EDGE);
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ }
+ }
+
+ /* constrict edge selection again */
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ e2 = NULL;
+ i = 0;
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ e2 = e;
+ i++;
+ }
+ }
+
+ if (i == 1) {
+ if (singlesel)
+ BM_elem_select_set(bm, v, FALSE);
+ else
+ BM_elem_select_set(bm, e2, FALSE);
+ }
+ }
+
+ if (ripvert) {
+ BM_elem_select_set(bm, ripvert, TRUE);
+ }
+
+ EDBM_selectmode_flush(em);
+
+ BLI_assert(singlesel ? (bm->totvertsel > 0) : (bm->totedgesel > 0));
+
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (bm->totvertsel == 0) {
+ 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_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_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
+ continue;
+
+ for (i = 0; i < totshape; i++) {
+ co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i);
+ copy_v3_v3(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_boolean_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_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
+ continue;
+
+ sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
+ copy_v3_v3(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);
+
+ copy_v3_v3(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 *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Mesh *me = (obedit) ? obedit->data : NULL;
+ BMEditMesh *em = (me) ? me->edit_btmesh : NULL;
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+
+ if (obedit && obedit->type == OB_MESH && CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
+ EnumPropertyItem tmp = {0, "", 0, "", ""};
+ int a;
+
+ 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");
+}
+
+/* BMESH_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_enum_get(op->ptr, "axis");
+ int mode = RNA_enum_get(op->ptr, "mode"); /* -1 == aligned, 0 == neg, 1 == pos */
+
+ if (ese == NULL || ese->htype != BM_VERT) {
+ BKE_report(op->reports, RPT_WARNING, "This operator requires an active vertex (last selected)");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ 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_elem_flag_test(ev, BM_ELEM_HIDDEN)) {
+ switch(mode) {
+ case -1: /* aligned */
+ if (fabs(ev->co[axis] - value) < limit)
+ BM_elem_select_set(em->bm, ev, TRUE);
+ break;
+ case 0: /* neg */
+ if (ev->co[axis] > value)
+ BM_elem_select_set(em->bm, ev, TRUE);
+ break;
+ case 1: /* pos */
+ if (ev->co[axis] < value)
+ BM_elem_select_set(em->bm, ev, TRUE);
+ 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}};
+
+ 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");
+}
+
+static int solidify_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Mesh *me = obedit->data;
+ BMEditMesh *em = me->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMOperator bmop;
+
+ float thickness = RNA_float_get(op->ptr, "thickness");
+
+ if (!EDBM_InitOpf(em, &bmop, op, "solidify geom=%hf thickness=%f", BM_ELEM_SELECT, thickness)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* deselect only the faces in the region to be solidified (leave wire
+ edges and loose verts selected, as there will be no corresponding
+ geometry selected below) */
+ BMO_slot_buffer_hflag_disable(bm, &bmop, "geom", BM_ELEM_SELECT, BM_FACE);
+
+ /* run the solidify operator */
+ BMO_op_exec(bm, &bmop);
+
+ /* select the newly generated faces */
+ BMO_slot_buffer_hflag_enable(bm, &bmop, "geomout", BM_ELEM_SELECT, BM_FACE);
+
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ 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_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_edge_seg_isect(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.0f) && (m2 >= -1.0f)) 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.0f;
+ float *scr, co[4];
+ int len = 0, isected;
+ 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 = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); bv; bv = BM_iter_step(&iter)) {
+ scr = MEM_mallocN(sizeof(float)*2, "Vertex Screen Coordinates");
+ copy_v3_v3(co, bv->co);
+ co[3] = 1.0f;
+ mul_m4_v4(obedit->obmat, co);
+ project_float(ar, co, scr);
+ BLI_ghash_insert(gh, bv, scr);
+ }
+
+ if (!EDBM_InitOpf(em, &bmop, op, "esubd")) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* store percentage of edge cut for KNIFE_EXACT here.*/
+ for (be = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); be; be = BM_iter_step(&iter)) {
+ if (BM_elem_flag_test(be, BM_ELEM_SELECT)) {
+ isect = bm_edge_seg_isect(be, curve, len, mode, gh, &isected);
+
+ if (isect != 0.0f) {
+ if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) {
+ BMO_slot_map_float_insert(bm, &bmop,
+ "edgepercents",
+ be, isect);
+
+ }
+ BMO_elem_flag_enable(bm, be, 1);
+ }
+ else {
+ BMO_elem_flag_disable(bm, be, 1);
+ }
+ }
+ else {
+ BMO_elem_flag_disable(bm, be, 1);
+ }
+ }
+
+ BMO_slot_from_flag(bm, &bmop, "edges", 1, BM_EDGE);
+
+ if (mode == KNIFE_MIDPOINT) numcuts = 1;
+ BMO_slot_int_set(&bmop, "numcuts", numcuts);
+
+ BMO_slot_int_set(&bmop, "flag", B_KNIFE);
+ BMO_slot_int_set(&bmop, "quadcornertype", SUBD_STRAIGHT_CUT);
+ BMO_slot_int_set(&bmop, "singleedge", 0);
+ BMO_slot_int_set(&bmop, "gridfill", 0);
+
+ BMO_slot_float_set(&bmop, "radius", 0);
+
+ BMO_op_exec(bm, &bmop);
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_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;
+
+ if (!em)
+ return OPERATOR_CANCELLED;
+
+ bmnew = BM_mesh_create(obedit, bm_mesh_allocsize_default);
+ CustomData_copy(&em->bm->vdata, &bmnew->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&em->bm->edata, &bmnew->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&em->bm->ldata, &bmnew->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&em->bm->pdata, &bmnew->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+ CustomData_bmesh_init_pool(&bmnew->vdata, bm_mesh_allocsize_default[0]);
+ CustomData_bmesh_init_pool(&bmnew->edata, bm_mesh_allocsize_default[1]);
+ CustomData_bmesh_init_pool(&bmnew->ldata, bm_mesh_allocsize_default[2]);
+ CustomData_bmesh_init_pool(&bmnew->pdata, bm_mesh_allocsize_default[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_ELEM_SELECT, bmnew);
+ EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_ELEM_SELECT, DEL_FACES);
+
+ /* clean up any loose edges */
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(e, BM_ELEM_HIDDEN))
+ continue;
+
+ if (BM_edge_face_count(e) != 0) {
+ BM_elem_select_set(em->bm, e, FALSE);
+ }
+ }
+ EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_ELEM_SELECT, DEL_EDGES);
+
+ /* clean up any loose verts */
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(v, BM_ELEM_HIDDEN))
+ continue;
+
+ if (BM_vert_edge_count(v) != 0) {
+ BM_elem_select_set(em->bm, v, FALSE);
+ }
+ }
+
+ EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_ELEM_SELECT, DEL_VERTS);
+
+ BM_mesh_normals_update(bmnew);
+ BMO_op_callf(bmnew, "bmesh_to_mesh mesh=%p object=%p", basenew->object->data, basenew->object);
+
+ BM_mesh_free(bmnew);
+ ((Mesh *)basenew->object->data)->edit_btmesh = NULL;
+
+ return 1;
+}
+
+//BMESH_TODO
+static int mesh_separate_material(Main *UNUSED(bmain), Scene *UNUSED(scene), Base *UNUSED(editbase), wmOperator *UNUSED(wmop))
+{
+ return 0;
+}
+
+static int mesh_separate_loose(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop)
+{
+ int i;
+ BMVert *v;
+ BMEdge *e;
+ BMVert *v_seed;
+ BMWalker walker;
+ BMIter iter;
+ int result = 0;
+ Object *obedit = editbase->object;
+ Mesh *me = obedit->data;
+ BMEditMesh *em = me->edit_btmesh;
+ BMesh *bm = em->bm;
+ int max_iter = bm->totvert;
+
+ /* Clear all selected vertices */
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BM_elem_select_set(bm, v, FALSE);
+ }
+
+ /* Flush the selection to clear edge/face selections to match
+ * selected vertices */
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
+
+ /* A "while (true)" loop should work here as each iteration should
+ * select and remove at least one vertex and when all vertices
+ * are selected the loop will break out. But guard against bad
+ * behavior by limiting iterations to the number of vertices in the
+ * original mesh.*/
+ for (i = 0; i < max_iter; i++) {
+ /* Get a seed vertex to start the walk */
+ v_seed = NULL;
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ v_seed = v;
+ break;
+ }
+
+ /* No vertices available, can't do anything */
+ if (v_seed == NULL) {
+ break;
+ }
+
+ /* Select the seed explicitly, in case it has no edges */
+ BM_elem_select_set(bm, v_seed, TRUE);
+
+ /* Walk from the single vertex, selecting everything connected
+ * to it */
+ BMW_init(&walker, bm, BMW_SHELL,
+ BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_NIL_LAY);
+
+ e = BMW_begin(&walker, v_seed);
+ for (; e; e = BMW_step(&walker)) {
+ BM_elem_select_set(bm, e->v1, TRUE);
+ BM_elem_select_set(bm, e->v2, TRUE);
+ }
+ BMW_end(&walker);
+
+ /* Flush the selection to get edge/face selections matching
+ * the vertex selection */
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
+
+ if (bm->totvert == bm->totvertsel) {
+ /* Every vertex selected, nothing to separate, work is done */
+ break;
+ }
+
+ /* Move selection into a separate object */
+ result |= mesh_separate_selected(bmain, scene, editbase, wmop);
+ }
+
+ return result;
+}
+
+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) {
+ DAG_id_tag_update(base->object->data, OB_RECALC_DATA);
+ 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_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", "");
+}
+
+
+static int fill_mesh_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ BMOperator bmop;
+
+ if (!EDBM_InitOpf(em, &bmop, op, "triangle_fill edges=%he", BM_ELEM_SELECT))
+ return OPERATOR_CANCELLED;
+
+ BMO_op_exec(em->bm, &bmop);
+
+ /* select new geometry */
+ BMO_slot_buffer_hflag_enable(em->bm, &bmop, "geomout", BM_ELEM_SELECT, BM_FACE|BM_EDGE);
+
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ 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_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 beautify_fill_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+
+ if (!EDBM_CallOpf(em, op, "beautify_fill faces=%hf", BM_ELEM_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_beautify_fill(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Beautify Fill";
+ 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;
+}
+
+/********************** 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_ELEM_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_ELEM_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)
+{
+ PropertyRNA *prop;
+
+ /* 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;
+
+ prop = RNA_def_float_rotation(ot->srna, "limit", 0, NULL, 0.0f, DEG2RADF(180.0f),
+ "Max Angle", "Angle Limit in Degrees", 0.0f, DEG2RADF(180.0f));
+ RNA_def_property_float_default(prop, DEG2RADF(40.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 dissolve_limited_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ float angle_limit = RNA_float_get(op->ptr, "angle_limit");
+
+ if (!EDBM_CallOpf(em, op,
+ "dissolvelimit edges=%he verts=%hv angle_limit=%f",
+ BM_ELEM_SELECT, BM_ELEM_SELECT, angle_limit))
+ {
+ 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_dissolve_limited(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Limited Dissolve";
+ ot->idname = "MESH_OT_dissolve_limited";
+ ot->description = "Dissolve selected edges and verts, limited by the angle of surrounding geometry";
+
+ /* api callbacks */
+ ot->exec = dissolve_limited_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f),
+ "Max Angle", "Angle Limit in Degrees", 0.0f, DEG2RADF(180.0f));
+ RNA_def_property_float_default(prop, DEG2RADF(15.0f));
+}
+
+static int edge_flip_exec(bContext *UNUSED(C), wmOperator *UNUSED(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_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, "split geom=%hvef", BM_ELEM_SELECT);
+ BMO_op_exec(em->bm, &bmop);
+ BM_mesh_elem_flag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT);
+ BMO_slot_buffer_hflag_enable(em->bm, &bmop, "geomout", BM_ELEM_SELECT, BM_ALL);
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Geometry has changed, need to recalc normals and looptris */
+ BMEdit_RecalcTesselation(em);
+ EDBM_RecalcNormals(em);
+
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_split(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Split";
+ ot->idname = "MESH_OT_split";
+
+ /* api callbacks */
+ ot->exec = split_mesh_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+
+static int spin_mesh_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMOperator spinop;
+ float cent[3], axis[3], imat[3][3];
+ float d[3] = {0.0f, 0.0f, 0.0f};
+ int steps, dupli;
+ float degr;
+
+ RNA_float_get_array(op->ptr, "center", cent);
+ RNA_float_get_array(op->ptr, "axis", axis);
+ steps = RNA_int_get(op->ptr, "steps");
+ degr = RNA_float_get(op->ptr, "degrees");
+ if (ts->editbutflag & B_CLOCKWISE) degr = -degr;
+ dupli = RNA_boolean_get(op->ptr, "dupli");
+
+ /* undo object transformation */
+ copy_m3_m4(imat, obedit->imat);
+ sub_v3_v3(cent, obedit->obmat[3]);
+ mul_m3_v3(imat, cent);
+ mul_m3_v3(imat, axis);
+
+ if (!EDBM_InitOpf(em, &spinop, op,
+ "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%d ang=%f dupli=%d",
+ BM_ELEM_SELECT, cent, axis, d, steps, degr, dupli)) {
+ return OPERATOR_CANCELLED;
+ }
+ BMO_op_exec(bm, &spinop);
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ BMO_slot_buffer_hflag_enable(bm, &spinop, "lastout", BM_ELEM_SELECT, BM_ALL);
+ if (!EDBM_FinishOp(em, &spinop, op, TRUE)) {
+ 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;
+}
+
+/* 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->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)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMEdge *eed;
+ BMVert *eve, *v1, *v2;
+ BMIter iter, eiter;
+ BMOperator spinop;
+ float dvec[3], nor[3], cent[3], axis[3];
+ float imat[3][3];
+ int steps, turns;
+ int valence;
+
+
+ turns = RNA_int_get(op->ptr, "turns");
+ steps = RNA_int_get(op->ptr, "steps");
+ RNA_float_get_array(op->ptr, "center", cent);
+ RNA_float_get_array(op->ptr, "axis", axis);
+
+ /* undo object transformation */
+ copy_m3_m4(imat, obedit->imat);
+ sub_v3_v3(cent, obedit->obmat[3]);
+ mul_m3_v3(imat, cent);
+ mul_m3_v3(imat, axis);
+
+
+ /* find two vertices with valence count == 1, more or less is wrong */
+ v1 = NULL;
+ v2 = NULL;
+ for (eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ eve; eve = BM_iter_step(&iter)) {
+
+ valence = 0;
+
+ for (eed = BM_iter_new(&eiter, em->bm, BM_EDGES_OF_VERT, eve);
+ eed; eed = BM_iter_step(&eiter)) {
+
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ valence++;
+ }
+
+ }
+
+ if (valence == 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");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* calculate dvec */
+ sub_v3_v3v3(dvec, v1->co, v2->co);
+ mul_v3_fl(dvec, 1.0f / steps);
+
+ if (dot_v3v3(nor, dvec) > 0.000f)
+ negate_v3(dvec);
+
+ if (!EDBM_InitOpf(em, &spinop, op,
+ "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%d ang=%f dupli=0",
+ BM_ELEM_SELECT, cent, axis, dvec, turns * steps, 360.0f * turns))
+ {
+ return OPERATOR_CANCELLED;
+ }
+ BMO_op_exec(bm, &spinop);
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ BMO_slot_buffer_hflag_enable(bm, &spinop, "lastout", BM_ELEM_SELECT, BM_ALL);
+ if (!EDBM_FinishOp(em, &spinop, op, TRUE)) {
+ 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;
+}
+
+/* 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->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 select_by_number_vertices_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMIter iter;
+ int numverts = RNA_int_get(op->ptr, "number");
+ int type = RNA_enum_get(op->ptr, "type");
+
+ for (efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ efa; efa = BM_iter_step(&iter)) {
+
+ int select = 0;
+
+ if (type == 0 && efa->len < numverts) {
+ select = 1;
+ }else if (type == 1 && efa->len == numverts) {
+ select = 1;
+ }else if (type == 2 && efa->len > numverts) {
+ select = 1;
+ }
+
+ if (select) {
+ BM_elem_select_set(em->bm, efa, TRUE);
+ }
+ }
+
+ EDBM_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[] = {
+ {0, "LESS", 0, "Less Than", ""},
+ {1, "EQUAL", 0, "Equal To", ""},
+ {2, "GREATER", 0, "Greater Than", ""},
+ {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;
+
+ /* properties */
+ RNA_def_int(ot->srna, "number", 4, 3, INT_MAX, "Number of Vertices", "", 3, INT_MAX);
+ RNA_def_enum(ot->srna, "type", type_items, 1, "Type", "Type of comparison to make");
+}
+
+static int select_loose_verts_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ BMVert *eve;
+ BMEdge *eed;
+ BMIter iter;
+
+ for (eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ eve; eve = BM_iter_step(&iter)) {
+
+ if (!eve->e) {
+ BM_elem_select_set(em->bm, eve, TRUE);
+ }
+ }
+
+ for (eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ eed; eed = BM_iter_step(&iter)) {
+
+ if (!eed->l) {
+ BM_elem_select_set(em->bm, eed, TRUE);
+ }
+ }
+
+ EDBM_selectmode_flush(em);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_loose_verts(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Loose Vertices/Edges";
+ ot->description = "Select vertices with edges or faces and edges with no faces";
+ ot->idname = "MESH_OT_select_loose_verts";
+
+ /* api callbacks */
+ ot->exec = select_loose_verts_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int select_mirror_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ int extend = RNA_boolean_get(op->ptr, "extend");
+
+ EDBM_select_mirrored(obedit, em, extend);
+ EDBM_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");
+}
+
+#if 0 /* UNUSED */
+/********* 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;
+}
+#endif
+
+// XXX is this needed?
+/* called from buttons */
+#if 0 /* UNUSED */
+static void xsortvert_flag__doSetX(void *userData, EditVert *UNUSED(eve), int x, int UNUSED(y), int index)
+{
+ xvertsort *sortblock = userData;
+
+ sortblock[index].x = x;
+}
+#endif
+
+/* all verts with (flag & 'flag') are sorted */
+static void xsortvert_flag(bContext *UNUSED(C), int UNUSED(flag))
+{
+ /* BMESH_TODO */
+#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_elem_flag_test(eve, BM_ELEM_SELECT))
+ sortblock[i].v1 = eve;
+ }
+
+ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
+ mesh_foreachScreenVert(&vc, xsortvert_flag__doSetX, sortblock, V3D_CLIP_TEST_OFF);
+
+ 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;
+}
+
+/* ********************** 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, j, *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->totpoly == 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->totpoly, "sort faces");
+ for (i = 0; i < me->totpoly; i++) {
+ index[i] = i;
+ }
+
+ face_sort_floats = (float *) MEM_mallocN(sizeof(float) * me->totpoly, "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->totpoly; i++) {
+ face_sort_floats[i] = BLI_frand();
+ }
+ qsort(index, me->totpoly, sizeof(int), float_sort);
+ }
+ else {
+ MPoly *mp;
+ MLoop *ml;
+ MVert *mv;
+ float vec[3];
+ float mat[4][4];
+ float cur[3];
+
+ if (event == 1)
+ mult_m4_m4m4(mat, rv3d->viewmat, OBACT->obmat); /* apply the view matrix to the object matrix */
+ else if (event == 2) { /* sort from cursor */
+ if (v3d && v3d->localvd) {
+ copy_v3_v3(cur, v3d->cursor);
+ }
+ else {
+ copy_v3_v3(cur, scene->cursor);
+ }
+ invert_m4_m4(mat, OBACT->obmat);
+ mul_m4_v3(mat, cur);
+ }
+
+ mp = me->mpoly;
+
+ for (i = 0; i < me->totpoly; i++, mp++) {
+ if (event == 3) {
+ face_sort_floats[i] = ((float)mp->mat_nr)*reverse;
+ }
+ else if (event == 4) {
+ /* selected first */
+ if (mp->flag & ME_FACE_SEL)
+ face_sort_floats[i] = 0.0;
+ else
+ face_sort_floats[i] = reverse;
+ }
+ else {
+ /* find the face's center */
+ ml = me->mloop + mp->loopstart;
+ zero_v3(vec);
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ mv = me->mvert + ml->v;
+ add_v3_v3(vec, mv->co);
+ }
+ mul_v3_fl(vec, 1.0f / (float)mp->totloop);
+
+ 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->totpoly, sizeof(int), float_sort);
+ }
+
+ MEM_freeN(face_sort_floats);
+ for (i = 0; i < me->pdata.totlayer; i++) {
+ layer = &me->pdata.layers[i];
+ permutate(layer->data, me->totpoly, 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, "SELECTED", 0, "Selected", "" },
+ { 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", "");
+}
+
+#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;
+#if 1 /* BMESH TODO */
+ (void)em;
+#else
+ hashvert_flag(em, SELECT);
+#endif
+ 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_elem_flag_test(eve, BM_ELEM_SELECT) && !BM_elem_flag_test(eve, BM_ELEM_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_elem_flag_test(eve, BM_ELEM_SELECT) && !BM_elem_flag_test(eve, BM_ELEM_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);
+}
+
+/* bevel! yay!!*/
+static int mesh_bevel_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = (((Mesh *)obedit->data))->edit_btmesh;
+ BMIter iter;
+ BMEdge *eed;
+ BMOperator bmop;
+ float factor = RNA_float_get(op->ptr, "percent"), fac = factor /*, dfac */ /* UNUSED */, df, s;
+ int i, recursion = RNA_int_get(op->ptr, "recursion");
+ const int use_even = RNA_boolean_get(op->ptr, "use_even");
+ const int use_dist = RNA_boolean_get(op->ptr, "use_dist");
+ float *w = NULL, ftot;
+ int li;
+
+ BM_data_layer_add(em->bm, &em->bm->edata, CD_PROP_FLT);
+ li = CustomData_number_of_layers(&em->bm->edata, CD_PROP_FLT)-1;
+
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ float d = len_v3v3(eed->v1->co, eed->v2->co);
+ float *dv = CustomData_bmesh_get_n(&em->bm->edata, eed->head.data, CD_PROP_FLT, li);
+
+ *dv = d;
+ }
+
+ if (em == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ w = MEM_mallocN(sizeof(float) * recursion, "bevel weights");
+
+ /* ugh, stupid math depends somewhat on angles!*/
+ /* dfac = 1.0/(float)(recursion + 1); */ /* UNUSED */
+ df = 1.0;
+ for (i = 0, ftot = 0.0f; i < recursion; i++) {
+ s = powf(df, 1.25f);
+
+ w[i] = s;
+ ftot += s;
+
+ df *= 2.0;
+ }
+
+ mul_vn_fl(w, recursion, 1.0f / (float)ftot);
+
+ fac = factor;
+ for (i = 0; i < recursion; i++) {
+ fac = w[recursion - i - 1] * factor;
+
+ if (!EDBM_InitOpf(em, &bmop, op,
+ "bevel geom=%hev percent=%f lengthlayer=%i use_lengths=%i use_even=%i use_dist=%i",
+ BM_ELEM_SELECT, fac, li, 1, use_even, use_dist))
+ {
+ return OPERATOR_CANCELLED;
+ }
+
+ BMO_op_exec(em->bm, &bmop);
+ if (!EDBM_FinishOp(em, &bmop, op, TRUE))
+ return OPERATOR_CANCELLED;
+ }
+
+ BM_data_layer_free_n(em->bm, &em->bm->edata, CD_MASK_PROP_FLT, li);
+
+ MEM_freeN(w);
+
+ 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_bevel(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bevel";
+ ot->description = "Edge/Vertex Bevel";
+ ot->idname = "MESH_OT_bevel";
+
+ /* api callbacks */
+ ot->exec = mesh_bevel_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_float(ot->srna, "percent", 0.5f, -FLT_MAX, FLT_MAX, "Percentage", "", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "recursion", 1, 1, 50, "Recursion Level", "Recursion Level", 1, 8);
+
+ RNA_def_boolean(ot->srna, "use_even", FALSE, "Even", "Calculate evenly spaced bevel");
+ RNA_def_boolean(ot->srna, "use_dist", FALSE, "Distance", "Interpret the percent in blender units");
+
+}
+
+static int bridge_edge_loops(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+
+ if (!EDBM_CallOpf(em, op, "bridge_loops edges=%he", BM_ELEM_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_bridge_edge_loops(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Bridge edge loops";
+ ot->description = "Make faces between two edge loops";
+ ot->idname = "MESH_OT_bridge_edge_loops";
+
+ /* api callbacks */
+ ot->exec = bridge_edge_loops;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
+}
+
+static int mark_freestyle_edge(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Mesh *me = ((Mesh *)obedit->data);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ BMEdge *eed;
+ BMIter iter;
+ int clear = RNA_boolean_get(op->ptr, "clear");
+
+ if (em == NULL) return OPERATOR_FINISHED;
+
+ /* auto-enable seams drawing */
+ if (clear == 0) {
+ me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
+ }
+
+ if (clear) {
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
+ BM_elem_flag_disable(eed, BM_ELEM_FREESTYLE);
+ }
+ }
+ else {
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
+ BM_elem_flag_enable(eed, BM_ELEM_FREESTYLE);
+ }
+ }
+
+ 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_freestyle_edge(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Mark Freestyle Edge";
+ ot->description= "(un)mark selected edges as Freestyle feature edges";
+ ot->idname= "MESH_OT_mark_freestyle_edge";
+
+ /* api callbacks */
+ ot->exec= mark_freestyle_edge;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
+}
+
+static int mark_freestyle_face_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Mesh *me = ((Mesh *)obedit->data);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMIter iter;
+ int clear = RNA_boolean_get(op->ptr, "clear");
+
+ if (em == NULL) return OPERATOR_FINISHED;
+
+ /* auto-enable Freestyle face mark drawing */
+ if(!clear) {
+ me->drawflag |= ME_DRAW_FREESTYLE_FACE;
+ }
+
+ if(clear) {
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
+ BM_elem_flag_disable(efa, BM_ELEM_FREESTYLE);
+ }
+ } else {
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
+ BM_elem_flag_enable(efa, BM_ELEM_FREESTYLE);
+ }
+ }
+ printf("%s\n", clear ? "clear" : "set");
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ printf("face %s\n", (BM_elem_flag_test(efa, BM_ELEM_FREESTYLE)) ? "enabled" : "disabled");
+ }
+ printf("\n");
+
+ 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_freestyle_face(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Mark Freestyle Face";
+ ot->description= "(un)mark selected faces for exclusion from Freestyle feature edge detection";
+ ot->idname= "MESH_OT_mark_freestyle_face";
+
+ /* api callbacks */
+ ot->exec= mark_freestyle_face_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
+}
diff --git a/source/blender/editors/mesh/bmesh_utils.c b/source/blender/editors/mesh/bmesh_utils.c
new file mode 100644
index 00000000000..f124823b106
--- /dev/null
+++ b/source/blender/editors/mesh/bmesh_utils.c
@@ -0,0 +1,1139 @@
+/*
+ * ***** 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): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_library.h"
+#include "BKE_key.h"
+#include "BKE_mesh.h"
+#include "BKE_bmesh.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+#include "ED_util.h"
+
+void EDBM_RecalcNormals(BMEditMesh *em)
+{
+ BM_mesh_normals_update(em->bm);
+}
+
+void EDBM_ClearMesh(BMEditMesh *em)
+{
+ /* clear bmesh */
+ BM_mesh_clear(em->bm);
+
+ /* free derived meshes */
+ if (em->derivedCage) {
+ em->derivedCage->needsFree = 1;
+ em->derivedCage->release(em->derivedCage);
+ }
+ if (em->derivedFinal && em->derivedFinal != em->derivedCage) {
+ em->derivedFinal->needsFree = 1;
+ em->derivedFinal->release(em->derivedFinal);
+ }
+
+ em->derivedCage = em->derivedFinal = NULL;
+
+ /* free tesselation data */
+ em->tottri = 0;
+ if (em->looptris)
+ MEM_freeN(em->looptris);
+}
+
+void EDBM_stats_update(BMEditMesh *em)
+{
+ const char iter_types[3] = {BM_VERTS_OF_MESH,
+ BM_EDGES_OF_MESH,
+ BM_FACES_OF_MESH};
+
+ BMIter iter;
+ BMHeader *ele;
+ 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 = BM_iter_new(&iter, em->bm, iter_types[i], NULL);
+ for ( ; ele; ele = BM_iter_step(&iter)) {
+ if (BM_elem_flag_test(ele, BM_ELEM_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_op_vinitf(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, const int report)
+{
+ const char *errmsg;
+
+ BMO_op_finish(em->bm, bmop);
+
+ if (BMO_error_get(em->bm, &errmsg, NULL)) {
+ BMEditMesh *emcopy = em->emcopy;
+
+ if (report) BKE_report(op->reports, RPT_ERROR, errmsg);
+
+ BMEdit_Free(em);
+ *em = *emcopy;
+ BMEdit_RecalcTesselation(em);
+
+ 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_op_vinitf(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_op_exec(bm, &bmop);
+
+ va_end(list);
+ return EDBM_FinishOp(em, &bmop, op, TRUE);
+}
+
+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_op_vinitf(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_op_exec(bm, &bmop);
+
+ BM_mesh_elem_flag_disable_all(em->bm, BM_VERT|BM_EDGE|BM_FACE, BM_ELEM_SELECT);
+
+ BMO_slot_buffer_hflag_enable(em->bm, &bmop, selectslot, BM_ELEM_SELECT, BM_ALL);
+
+ va_end(list);
+ return EDBM_FinishOp(em, &bmop, op, TRUE);
+}
+
+int EDBM_CallOpfSilent(BMEditMesh *em, const char *fmt, ...)
+{
+ BMesh *bm = em->bm;
+ BMOperator bmop;
+ va_list list;
+
+ va_start(list, fmt);
+
+ if (!BMO_op_vinitf(bm, &bmop, fmt, list)) {
+ va_end(list);
+ return 0;
+ }
+
+ if (!em->emcopy)
+ em->emcopy = BMEdit_Copy(em);
+ em->emcopyusers++;
+
+ BMO_op_exec(bm, &bmop);
+
+ va_end(list);
+ return EDBM_FinishOp(em, &bmop, NULL, FALSE);
+}
+
+void EDBM_selectmode_to_scene(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+
+ if (!em)
+ return;
+
+ scene->toolsettings->selectmode = em->selectmode;
+
+ /* Request redraw of header buttons (to show new select mode) */
+ WM_event_add_notifier(C, NC_SCENE|ND_TOOLSETTINGS, scene);
+}
+
+void EDBM_MakeEditBMesh(ToolSettings *ts, Scene *UNUSED(scene), Object *ob)
+{
+ Mesh *me = ob->data;
+ BMesh *bm;
+
+ if (!me->mpoly && me->totface) {
+ fprintf(stderr, "%s: bmesh conversion issue! may lose lots of geometry! (bmesh internal error)\n", __func__);
+
+ /* BMESH_TODO need to write smarter code here */
+ bm = BKE_mesh_to_bmesh(me, ob);
+ }
+ else {
+ bm = BKE_mesh_to_bmesh(me, ob);
+ }
+
+ if (me->edit_btmesh) {
+ /* this happens when switching shape keys */
+ BMEdit_Free(me->edit_btmesh);
+ MEM_freeN(me->edit_btmesh);
+ }
+
+ /* currently executing operators re-tesselates, so we can avoid doing here
+ * but at some point it may need to be added back. */
+#if 0
+ me->edit_btmesh = BMEdit_Create(bm, TRUE);
+#else
+ me->edit_btmesh = BMEdit_Create(bm, FALSE);
+#endif
+
+ me->edit_btmesh->selectmode = me->edit_btmesh->bm->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_op_callf(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 = BM_iter_new(&iter, tm->bm, BM_VERTS_OF_MESH, NULL);
+ for ( ; ele; ele = BM_iter_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 = BM_iter_new(&iter, tm->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; ele; ele = BM_iter_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 = BM_iter_new(&iter, tm->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; ele; ele = BM_iter_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 && index < tm->bm->totvert ?tm->vert_index[index]:NULL;
+}
+
+BMEdge *EDBM_get_edge_for_index(BMEditMesh *tm, int index)
+{
+ return tm->edge_index && index < tm->bm->totedge ?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;
+}
+
+void EDBM_selectmode_flush_ex(BMEditMesh *em, int selectmode)
+{
+ em->bm->selectmode = selectmode;
+ BM_mesh_select_mode_flush(em->bm);
+ em->bm->selectmode = em->selectmode;
+}
+
+void EDBM_selectmode_flush(BMEditMesh *em)
+{
+ EDBM_selectmode_flush_ex(em, em->selectmode);
+}
+
+void EDBM_deselect_flush(BMEditMesh *em)
+{
+ /* function below doesnt use. just do this to keep the values in sync */
+ em->bm->selectmode = em->selectmode;
+ BM_mesh_deselect_flush(em->bm);
+}
+
+
+void EDBM_select_flush(BMEditMesh *em)
+{
+ /* function below doesnt use. just do this to keep the values in sync */
+ em->bm->selectmode = em->selectmode;
+ BM_mesh_select_flush(em->bm);
+}
+
+void EDBM_select_more(BMEditMesh *em)
+{
+ BMOperator bmop;
+ int usefaces = em->selectmode > SCE_SELECT_EDGE;
+
+ BMO_op_initf(em->bm, &bmop,
+ "regionextend geom=%hvef constrict=%d usefaces=%d",
+ BM_ELEM_SELECT, 0, usefaces);
+ BMO_op_exec(em->bm, &bmop);
+ BMO_slot_buffer_hflag_enable(em->bm, &bmop, "geomout", BM_ELEM_SELECT, BM_ALL);
+ BMO_op_finish(em->bm, &bmop);
+
+ EDBM_selectmode_flush(em);
+}
+
+void EDBM_select_less(BMEditMesh *em)
+{
+ BMOperator bmop;
+ int usefaces = em->selectmode > SCE_SELECT_EDGE;
+
+ BMO_op_initf(em->bm, &bmop,
+ "regionextend geom=%hvef constrict=%d usefaces=%d",
+ BM_ELEM_SELECT, 0, usefaces);
+ BMO_op_exec(em->bm, &bmop);
+ BMO_slot_buffer_hflag_enable(em->bm, &bmop, "geomout", BM_ELEM_SELECT, BM_ALL);
+ BMO_op_finish(em->bm, &bmop);
+
+ EDBM_selectmode_flush(em);
+}
+
+int EDBM_get_actSelection(BMEditMesh *em, BMEditSelection *ese)
+{
+ BMEditSelection *ese_last = em->bm->selected.last;
+ BMFace *efa = BM_active_face_get(em->bm, FALSE);
+
+ ese->next = ese->prev = NULL;
+
+ if (ese_last) {
+ if (ese_last->htype == 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->htype = BM_FACE;
+ }
+ else {
+ ese->data = ese_last->data;
+ ese->htype = ese_last->htype;
+ }
+ }
+ else if (efa) { /* no */
+ ese->data = (void *)efa;
+ ese->htype = BM_FACE;
+ }
+ else {
+ ese->data = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+void EDBM_flag_disable_all(BMEditMesh *em, const char hflag)
+{
+ BM_mesh_elem_flag_disable_all(em->bm, BM_VERT|BM_EDGE|BM_FACE, hflag);
+}
+
+void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
+{
+ BM_mesh_elem_flag_enable_all(em->bm, BM_VERT|BM_EDGE|BM_FACE, hflag);
+}
+
+/**************-------------- 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;
+ char obname[MAX_ID_NAME - 2];
+} undomesh;
+
+/* undo simply makes copies of a bmesh */
+static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
+{
+ BMEditMesh *em = emv;
+ Mesh *obme = obdata;
+
+ undomesh *um = MEM_callocN(sizeof(undomesh), "undo Mesh");
+ BLI_strncpy(um->obname, em->bm->ob->id.name + 2, sizeof(um->obname));
+
+ /* make sure shape keys work */
+ um->me.key = obme->key ? copy_key_nolib(obme->key) : NULL;
+
+#ifdef BMESH_EM_UNDO_RECALC_TESSFACE_WORKAROUND
+
+ /* we recalc the tesselation here, to avoid seeding calls to
+ * BMEdit_RecalcTesselation throughout the code. */
+ BMEdit_RecalcTesselation(em);
+
+#endif
+
+ BMO_op_callf(em->bm, "bmesh_to_mesh mesh=%p notesselation=%i", &um->me, 1);
+ um->selectmode = em->selectmode;
+
+ return um;
+}
+
+static void undoMesh_to_editbtMesh(void *umv, void *emv, void *UNUSED(obdata))
+{
+ BMEditMesh *em = emv, *em2;
+ Object *ob;
+ undomesh *um = umv;
+ BMesh *bm;
+
+ ob = (Object *)find_id("OB", um->obname);
+ ob->shapenr = em->bm->shapenr;
+
+ BMEdit_Free(em);
+
+ bm = BM_mesh_create(ob, bm_mesh_allocsize_default);
+ BMO_op_callf(bm, "mesh_to_bmesh mesh=%p object=%p set_shapekey=%i", &um->me, ob, 0);
+
+ em2 = BMEdit_Create(bm, TRUE);
+ *em = *em2;
+
+ em->selectmode = um->selectmode;
+
+ MEM_freeN(em2);
+}
+
+
+static void free_undo(void *umv)
+{
+ if (((Mesh *)umv)->key) {
+ free_key(((Mesh *)umv)->key);
+ MEM_freeN(((Mesh *)umv)->key);
+ }
+
+ 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; */ /* UNUSED */
+ MLoopUV *luv;
+ unsigned int a;
+ int totverts, i, totuv;
+
+ if (do_face_idx_array)
+ EDBM_init_index_arrays(em, 0, 0, 1);
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ totverts = em->bm->totvert;
+ totuv = 0;
+
+ /* generate UvMapVert array */
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!selected || ((!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) && BM_elem_flag_test(efa, BM_ELEM_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_pt");
+ 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_elem_flag_test(efa, BM_ELEM_HIDDEN)) && BM_elem_flag_test(efa, BM_ELEM_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[BM_elem_index_get(l->v)];
+ vmap->vert[BM_elem_index_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); */ /* UNUSED */
+
+ l = BM_iter_at_index(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); */ /* UNUSED */
+
+ l = BM_iter_at_index(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(uvdiff[0]) < limit[0] && fabs(uvdiff[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];
+}
+
+/* from editmesh_lib.c in trunk */
+
+
+/* A specialized vert map used by stitch operator */
+UvElementMap *EDBM_make_uv_element_map(BMEditMesh *em, int selected, int do_islands)
+{
+ BMVert *ev;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ /* vars from original func */
+ UvElementMap *element_map;
+ UvElement *buf;
+ UvElement *islandbuf;
+ /* island number for faces */
+ int *island_number;
+
+ MLoopUV *luv;
+ int totverts, i, totuv, j, nislands = 0, islandbufsize = 0;
+
+ unsigned int *map;
+ BMFace **stack;
+ int stacksize = 0;
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
+
+ totverts = em->bm->totvert;
+ totuv = 0;
+
+ island_number = MEM_mallocN(sizeof(*stack)*em->bm->totface, "uv_island_number_face");
+ if (!island_number) {
+ return NULL;
+ }
+
+ /* generate UvElement array */
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!selected || ((!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) && BM_elem_flag_test(efa, BM_ELEM_SELECT)))
+ totuv += efa->len;
+ }
+
+ if (totuv == 0) {
+ MEM_freeN(island_number);
+ return NULL;
+ }
+ element_map = (UvElementMap *)MEM_callocN(sizeof(*element_map), "UvElementMap");
+ if (!element_map) {
+ MEM_freeN(island_number);
+ return NULL;
+ }
+ element_map->totalUVs = totuv;
+ element_map->vert = (UvElement **)MEM_callocN(sizeof(*element_map->vert) * totverts, "UvElementVerts");
+ buf = element_map->buf = (UvElement *)MEM_callocN(sizeof(*element_map->buf) * totuv, "UvElement");
+
+ if (!element_map->vert || !element_map->buf) {
+ EDBM_free_uv_element_map(element_map);
+ MEM_freeN(island_number);
+ return NULL;
+ }
+
+ j = 0;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ island_number[j++] = INVALID_ISLAND;
+ if (!selected || ((!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) && BM_elem_flag_test(efa, BM_ELEM_SELECT))) {
+ i = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ buf->tfindex = i;
+ buf->face = efa;
+ buf->separate = 0;
+ buf->island = INVALID_ISLAND;
+
+ buf->next = element_map->vert[BM_elem_index_get(l->v)];
+ element_map->vert[BM_elem_index_get(l->v)] = buf;
+
+ buf++;
+ i++;
+ }
+ }
+ }
+
+ /* sort individual uvs for each vert */
+ i = 0;
+ BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ UvElement *newvlist = NULL, *vlist = element_map->vert[i];
+ UvElement *iterv, *v, *lastv, *next;
+ float *uv, *uv2, uvdiff[2];
+
+ while (vlist) {
+ v = vlist;
+ vlist = vlist->next;
+ v->next = newvlist;
+ newvlist = v;
+
+ efa = v->face;
+ /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
+
+ l = BM_iter_at_index(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 = iterv->face;
+ /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
+
+ l = BM_iter_at_index(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 (fabsf(uvdiff[0]) < STD_UV_CONNECT_LIMIT && fabsf(uvdiff[1]) < STD_UV_CONNECT_LIMIT) {
+ if (lastv) lastv->next = next;
+ else vlist = next;
+ iterv->next = newvlist;
+ newvlist = iterv;
+ }
+ else {
+ lastv = iterv;
+ }
+
+ iterv = next;
+ }
+
+ newvlist->separate = 1;
+ }
+
+ element_map->vert[i] = newvlist;
+ i++;
+ }
+
+ if (do_islands) {
+ /* map holds the map from current vmap->buf to the new, sorted map */
+ map = MEM_mallocN(sizeof(*map)*totuv, "uvelement_remap");
+ stack = MEM_mallocN(sizeof(*stack)*em->bm->totface, "uv_island_face_stack");
+ islandbuf = MEM_callocN(sizeof(*islandbuf)*totuv, "uvelement_island_buffer");
+
+ /* at this point, every UvElement in vert points to a UvElement sharing the same vertex. Now we should sort uv's in islands. */
+ for (i = 0; i < totuv; i++) {
+ if (element_map->buf[i].island == INVALID_ISLAND) {
+ element_map->buf[i].island = nislands;
+ stack[0] = element_map->buf[i].face;
+ island_number[BM_elem_index_get(stack[0])] = nislands;
+ stacksize = 1;
+
+ while (stacksize > 0) {
+ efa = stack[--stacksize];
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ UvElement *element, *initelement = element_map->vert[BM_elem_index_get(l->v)];
+
+ for (element = initelement; element; element = element->next) {
+ if (element->separate)
+ initelement = element;
+
+ if (element->face == efa) {
+ /* found the uv corresponding to our face and vertex. Now fill it to the buffer */
+ element->island = nislands;
+ map[element - element_map->buf] = islandbufsize;
+ islandbuf[islandbufsize].tfindex = element->tfindex;
+ islandbuf[islandbufsize].face = element->face;
+ islandbuf[islandbufsize].separate = element->separate;
+ islandbuf[islandbufsize].island = nislands;
+ islandbufsize++;
+
+ for (element = initelement; element; element = element->next) {
+ if (element->separate && element != initelement)
+ break;
+
+ if (island_number[BM_elem_index_get(element->face)] == INVALID_ISLAND) {
+ stack[stacksize++] = element->face;
+ island_number[BM_elem_index_get(element->face)] = nislands;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ nislands++;
+ }
+ }
+
+ /* remap */
+ for (i = 0; i < em->bm->totvert; i++) {
+ /* important since we may do selection only. Some of these may be NULL */
+ if (element_map->vert[i])
+ element_map->vert[i] = &islandbuf[map[element_map->vert[i] - element_map->buf]];
+ }
+
+ element_map->islandIndices = MEM_callocN(sizeof(*element_map->islandIndices)*nislands,"UvElementMap_island_indices");
+ if (!element_map->islandIndices) {
+ MEM_freeN(islandbuf);
+ MEM_freeN(stack);
+ MEM_freeN(map);
+ EDBM_free_uv_element_map(element_map);
+ MEM_freeN(island_number);
+ }
+
+ j = 0;
+ for (i = 0; i < totuv; i++) {
+ UvElement *element = element_map->buf[i].next;
+ if (element == NULL)
+ islandbuf[map[i]].next = NULL;
+ else
+ islandbuf[map[i]].next = &islandbuf[map[element - element_map->buf]];
+
+ if (islandbuf[i].island != j) {
+ j++;
+ element_map->islandIndices[j] = i;
+ }
+ }
+
+ MEM_freeN(element_map->buf);
+
+ element_map->buf = islandbuf;
+ element_map->totalIslands = nislands;
+ MEM_freeN(stack);
+ MEM_freeN(map);
+ }
+ MEM_freeN(island_number);
+
+ return element_map;
+}
+
+
+UvMapVert *EM_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);
+ }
+}
+
+void EDBM_free_uv_element_map(UvElementMap *element_map)
+{
+ if (element_map) {
+ if (element_map->vert) MEM_freeN(element_map->vert);
+ if (element_map->buf) MEM_freeN(element_map->buf);
+ if (element_map->islandIndices) MEM_freeN(element_map->islandIndices);
+ MEM_freeN(element_map);
+ }
+}
+
+/* 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 = BM_active_face_get(em->bm, 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);
+}
+
+static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index)
+{
+ intptr_t eve_i = index_lookup[index];
+ return (eve_i == -1) ? NULL : (BMVert *)eve_i;
+}
+
+/* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a
+ * preference */
+#define BM_SEARCH_MAXDIST_MIRR 0.00002f
+#define BM_CD_LAYER_ID "__mirror_index"
+void EDBM_CacheMirrorVerts(BMEditMesh *em, const short use_select)
+{
+ Mesh *me = em->me;
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMVert *v;
+ int li, topo = 0;
+
+ /* one or the other is used depending if topo is enabled */
+ BMBVHTree *tree = NULL;
+ MirrTopoStore_t mesh_topo_store = {NULL, -1, -1, -1};
+
+ if (me && (me->editflag & ME_EDIT_MIRROR_TOPO)) {
+ topo = 1;
+ }
+
+ if (!em->vert_index) {
+ EDBM_init_index_arrays(em, 1, 0, 0);
+ em->mirr_free_arrays = 1;
+ }
+
+ if (!CustomData_get_layer_named(&bm->vdata, CD_PROP_INT, BM_CD_LAYER_ID)) {
+ BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_INT, BM_CD_LAYER_ID);
+ }
+
+ li = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, BM_CD_LAYER_ID);
+
+ bm->vdata.layers[li].flag |= CD_FLAG_TEMPORARY;
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ if (topo) {
+ ED_mesh_mirrtopo_init(me, -1, &mesh_topo_store, TRUE);
+ }
+ else {
+ tree = BMBVH_NewBVH(em, 0, NULL, NULL);
+ }
+
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+
+ /* temporary for testing, check for selection */
+ if (use_select && !BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ /* do nothing */
+ }
+ else {
+ BMVert *mirr;
+ int *idx = CustomData_bmesh_get_layer_n(&bm->vdata, v->head.data, li);
+
+ if (topo) {
+ mirr = cache_mirr_intptr_as_bmvert(mesh_topo_store.index_lookup, BM_elem_index_get(v));
+ }
+ else {
+ float co[3] = {-v->co[0], v->co[1], v->co[2]};
+ mirr = BMBVH_FindClosestVert(tree, co, BM_SEARCH_MAXDIST_MIRR);
+ }
+
+ if (mirr && mirr != v) {
+ *idx = BM_elem_index_get(mirr);
+ idx = CustomData_bmesh_get_layer_n(&bm->vdata, mirr->head.data, li);
+ *idx = BM_elem_index_get(v);
+ }
+ else {
+ *idx = -1;
+ }
+ }
+
+ }
+
+
+ if (topo) {
+ ED_mesh_mirrtopo_free(&mesh_topo_store);
+ }
+ else {
+ BMBVH_FreeBVH(tree);
+ }
+
+ em->mirror_cdlayer = li;
+}
+
+BMVert *EDBM_GetMirrorVert(BMEditMesh *em, BMVert *v)
+{
+ int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer);
+
+ BLI_assert(em->mirror_cdlayer != -1); /* invalid use */
+
+ 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_ClearMirrorVert(BMEditMesh *em, BMVert *v)
+{
+ int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer);
+
+ BLI_assert(em->mirror_cdlayer != -1); /* invalid use */
+
+ if (mirr) {
+ *mirr = -1;
+ }
+}
+
+void EDBM_EndMirrorCache(BMEditMesh *em)
+{
+ if (em->mirr_free_arrays) {
+ MEM_freeN(em->vert_index);
+ em->vert_index = NULL;
+ }
+
+ em->mirror_cdlayer = -1;
+}
+
+void EDBM_ApplyMirrorCache(BMEditMesh *em, const int sel_from, const int sel_to)
+{
+ BMIter iter;
+ BMVert *v;
+
+ BLI_assert(em->vert_index != NULL);
+
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) == sel_from) {
+ BMVert *mirr = EDBM_GetMirrorVert(em, v);
+ if (mirr) {
+ if (BM_elem_flag_test(mirr, BM_ELEM_SELECT) == sel_to) {
+ copy_v3_v3(mirr->co, v->co);
+ mirr->co[0] *= -1.0f;
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 9107b30d928..bec1403a8dd 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -34,12 +34,11 @@
#include "MEM_guardedalloc.h"
+#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BLI_heap.h"
#include "BLI_edgehash.h"
#include "BLI_editVert.h"
-#include "BLI_utildefines.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -52,6 +51,7 @@
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_context.h"
+#include "BKE_tessmesh.h"
#include "BIF_gl.h"
@@ -69,42 +69,75 @@
* use in object mode when selecting faces (while painting) */
void paintface_flush_flags(Object *ob)
{
- Mesh *me= get_mesh(ob);
- DerivedMesh *dm= ob->derivedFinal;
- MFace *faces, *mf, *mf_orig;
+ Mesh *me = get_mesh(ob);
+ DerivedMesh *dm = ob->derivedFinal;
+ MPoly *polys, *mp_orig;
+ MFace *faces;
int *index_array = NULL;
- int totface;
+ int totface, totpoly;
int i;
if(me==NULL || dm==NULL)
return;
- index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ /*
+ * Try to push updated mesh poly flags to three other data sets:
+ * - Mesh polys => Mesh tess faces
+ * - Mesh polys => Final derived polys
+ * - Final derived polys => Final derived tessfaces
+ */
- if(!index_array)
- return;
-
- faces = dm->getFaceArray(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;
+ if ((index_array = CustomData_get_layer(&me->fdata, CD_POLYINDEX))) {
+ faces = me->mface;
+ totface = me->totface;
+
+ /* loop over tessfaces */
+ for (i= 0; i<totface; i++) {
+ /* Copy flags onto the original tessface from its original poly */
+ mp_orig = me->mpoly + index_array[i];
+ faces[i].flag = mp_orig->flag;
+ }
+ }
+
+ if ((index_array = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX))) {
+ polys = dm->getPolyArray(dm);
+ totpoly = dm->getNumPolys(dm);
+
+ /* loop over final derived polys */
+ for (i= 0; i<totpoly; i++) {
+ /* Copy flags onto the final derived poly from the original mesh poly */
+ mp_orig = me->mpoly + index_array[i];
+ polys[i].flag = mp_orig->flag;
+ }
+ }
+
+ if ((index_array = CustomData_get_layer(&dm->faceData, CD_POLYINDEX))) {
+ polys = dm->getPolyArray(dm);
+ faces = dm->getTessFaceArray(dm);;
+ totface = dm->getNumTessFaces(dm);
+
+ /* loop over tessfaces */
+ for (i= 0; i<totface; i++) {
+ /* Copy flags onto the final tessface from its final poly */
+ mp_orig = polys + index_array[i];
+ faces[i].flag = mp_orig->flag;
+ }
}
}
/* returns 0 if not found, otherwise 1 */
-static int facesel_face_pick(struct bContext *C, Mesh *me, const int mval[2], unsigned int *index, short rect)
+static int facesel_face_pick(struct bContext *C, Mesh *me, Object *ob, const int mval[2], 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) {
+ makeDerivedMesh(scene, ob, NULL, CD_MASK_BAREMESH, 0);
+
+ // XXX if (v3d->flag & V3D_INVALID_BACKBUF) {
// XXX drawview.c! check_backbuf();
// XXX persp(PERSP_VIEW);
// XXX }
@@ -114,14 +147,14 @@ static int facesel_face_pick(struct bContext *C, Mesh *me, const int mval[2], un
on an edge in the backbuf, we can still select a face */
int dist;
- *index = view3d_sample_backbuf_rect(&vc, mval, 3, 1, me->totface+1, &dist,0,NULL, NULL);
+ *index = view3d_sample_backbuf_rect(&vc, mval, 3, 1, me->totpoly+1, &dist,0,NULL, NULL);
}
else {
/* sample only on the exact position */
*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)--;
@@ -129,43 +162,17 @@ static int facesel_face_pick(struct bContext *C, Mesh *me, const int mval[2], un
return 1;
}
-/* 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)
-{
- EditFace *efa = NULL;
-
- if(!EM_texFaceCheck(em))
- return NULL;
-
- efa = EM_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);
- }
- 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==NULL || me->totface==0) return;
+ if(me==NULL || 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) {
@@ -187,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==NULL || me->totface==0) return;
+ if(me==NULL || 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;
@@ -208,30 +215,29 @@ 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 *mp, 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);
+ MLoop *ml;
+ int i;
+
+ for (i=0, ml=mloop; i<mp->totloop; i++, ml++) {
+ BLI_edgehash_insert(ehash, ml->v, ME_POLY_LOOP_NEXT(mloop, mp, i)->v, NULL);
}
- else
- BLI_edgehash_insert(ehash, mf->v3, mf->v1, 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)
@@ -239,17 +245,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;
}
}
@@ -259,35 +265,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;
}
}
@@ -299,24 +296,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;
}
@@ -331,7 +328,7 @@ void paintface_select_linked(bContext *UNUSED(C), Object *ob, int UNUSED(mval[2]
unsigned int index=0;
me = get_mesh(ob);
- if(me==NULL || me->totface==0) return;
+ if(me==NULL || me->totpoly==0) return;
if (mode==0 || mode==1) {
// XXX - Causes glitches, not sure why
@@ -349,15 +346,15 @@ void paintface_select_linked(bContext *UNUSED(C), Object *ob, int UNUSED(mval[2]
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==NULL) 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;
@@ -369,8 +366,8 @@ void paintface_deselect_all_visible(Object *ob, int action, short flush_flags)
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;
@@ -380,8 +377,8 @@ void paintface_deselect_all_visible(Object *ob, int action, short flush_flags)
}
}
- mface= me->mface;
- a= me->totface;
+ mface= me->mpoly;
+ a= me->totpoly;
while(a--) {
if((mface->flag & ME_HIDE) == 0) {
switch (action) {
@@ -407,270 +404,65 @@ void paintface_deselect_all_visible(Object *ob, int action, short flush_flags)
int paintface_minmax(Object *ob, float *min, float *max)
{
- Mesh *me= get_mesh(ob);
- MFace *mf;
- MVert *mv;
- int a, ok=0;
- float vec[3];
-
- if(me==NULL)
- return ok;
-
- 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;
- }
- }
- return ok;
-}
-
-/* ******************** edge loop shortest path ********************* */
-
-#define ME_SEAM_DONE 2 /* reuse this flag */
-
-static float edgetag_cut_cost(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 );
- float cost, d1[3], d2[3];
-
- cost = len_v3v3(v1->co, v->co);
- cost += len_v3v3(v->co, v2->co);
-
- sub_v3_v3v3(d1, v->co, v1->co);
- sub_v3_v3v3(d2, v2->co, v->co);
-
- cost = cost + 0.5f*cost*(2.0f - fabsf(d1[0]*d2[0] + d1[1]*d2[1] + d1[2]*d2[2]));
-
- return cost;
-}
-
-static void edgetag_add_adjacent(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);
- float newcost;
-
- if (eedadj->f2 & ME_SEAM_DONE)
- continue;
-
- newcost = cost[mednum] + edgetag_cut_cost(mednum, adjnum, vertnum);
-
- if (cost[adjnum] > newcost) {
- cost[adjnum] = newcost;
- prevedge[adjnum] = mednum;
- BLI_heap_insert(heap, newcost, SET_INT_IN_POINTER(adjnum));
- }
- }
-}
-
-void edgetag_context_set(Scene *scene, EditEdge *eed, int val)
-{
-
- switch (scene->toolsettings->edge_mode) {
- case EDGE_MODE_SELECT:
- EM_select_edge(eed, val);
- break;
- case EDGE_MODE_TAG_SEAM:
- if (val) {eed->seam = 255;}
- else {eed->seam = 0;}
- break;
- case EDGE_MODE_TAG_SHARP:
- if (val) {eed->sharp = 1;}
- else {eed->sharp = 0;}
- break;
- case EDGE_MODE_TAG_CREASE:
- if (val) {eed->crease = 1.0f;}
- else {eed->crease = 0.0f;}
- break;
- case EDGE_MODE_TAG_BEVEL:
- if (val) {eed->bweight = 1.0f;}
- else {eed->bweight = 0.0f;}
- break;
- case EDGE_MODE_TAG_FREESTYLE:
- if (val) {eed->freestyle = 1;}
- else {eed->freestyle = 0;}
- break;
- }
-}
-
-int edgetag_context_check(Scene *scene, EditEdge *eed)
-{
- switch (scene->toolsettings->edge_mode) {
- case EDGE_MODE_SELECT:
- return (eed->f & SELECT) ? 1 : 0;
- case EDGE_MODE_TAG_SEAM:
- return eed->seam ? 1 : 0;
- case EDGE_MODE_TAG_SHARP:
- return eed->sharp ? 1 : 0;
- case EDGE_MODE_TAG_CREASE:
- return eed->crease ? 1 : 0;
- case EDGE_MODE_TAG_BEVEL:
- return eed->bweight ? 1 : 0;
- case EDGE_MODE_TAG_FREESTYLE:
- return eed->freestyle ? 1 : 0;
- }
- return 0;
-}
-
+ Mesh *me;
+ MPoly *mf;
+ MTexPoly *tf;
+ MLoop *ml;
+ MVert *mvert;
+ int a, b, ok=0;
+ float vec[3], bmat[3][3];
-int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge *target)
-{
- EditEdge *eed;
- EditVert *ev;
+ me= get_mesh(ob);
+ if(!me || !me->mtpoly) return ok;
- Heap *heap;
- float *cost;
- int a, totvert=0, totedge=0, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0;
-
+ copy_m3_m4(bmat, ob->obmat);
- /* we need the vert */
- for (ev= em->verts.first, totvert=0; ev; ev= ev->next) {
- ev->tmp.l = totvert;
- totvert++;
- }
-
- for (eed= em->edges.first; eed; eed = eed->next) {
- eed->f2 = 0;
- if (eed->h) {
- eed->f2 |= ME_SEAM_DONE;
- }
- eed->tmp.l = totedge;
- totedge++;
- }
-
- /* alloc */
- nedges = MEM_callocN(sizeof(*nedges)*totvert+1, "SeamPathNEdges");
- edges = MEM_mallocN(sizeof(*edges)*totedge*2, "SeamPathEdges");
- prevedge = MEM_mallocN(sizeof(*prevedge)*totedge, "SeamPathPrevious");
- 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]++;
- }
-
- for (a=1; a<totvert; a++) {
- int newswap = nedges[a+1];
- nedges[a+1] = nedgeswap + nedges[a];
- nedgeswap = newswap;
- }
- 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;
-
- cost[a] = 1e20f;
- prevedge[a] = -1;
- }
-
- /* 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);
-
-
- while (!BLI_heap_empty(heap)) {
- mednum = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
- eed = EM_get_edge_for_index( mednum );
-
- if (mednum == target->tmp.l)
- break;
-
- if (eed->f2 & ME_SEAM_DONE)
+ mvert= me->mvert;
+ 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;
- eed->f2 |= 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);
- }
-
-
- 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;
- }
-
- if (mednum != target->tmp.l) {
- MEM_freeN(prevedge);
- EM_free_index_arrays();
- return 0;
- }
-
- /* follow path back to source and mark as seam */
- if (mednum == target->tmp.l) {
- short allseams = 1;
+ ml = me->mloop + mf->totloop;
+ for (b=0; b<mf->totloop; b++, ml++) {
+ copy_v3_v3(vec, (mvert[ml->v].co));
+ mul_m3_v3(bmat, vec);
+ add_v3_v3v3(vec, vec, ob->obmat[3]);
+ DO_MINMAX(vec, min, max);
+ }
- mednum = target->tmp.l;
- do {
- eed = EM_get_edge_for_index( mednum );
- if (!edgetag_context_check(scene, eed)) {
- allseams = 0;
- break;
- }
- mednum = prevedge[mednum];
- } while (mednum != source->tmp.l);
-
- mednum = target->tmp.l;
- do {
- eed = EM_get_edge_for_index( mednum );
- if (allseams)
- edgetag_context_set(scene, eed, 0);
- else
- edgetag_context_set(scene, eed, 1);
- mednum = prevedge[mednum];
- } while (mednum != -1);
+ ok= 1;
}
- MEM_freeN(prevedge);
- EM_free_index_arrays();
- return 1;
+ return ok;
}
/* *************************************** */
#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);
+ 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);
}
- else
- BLI_edgehash_insert(ehash, mf->v3, mf->v1, 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");
@@ -681,9 +473,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))
@@ -696,11 +488,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++)
@@ -722,21 +514,24 @@ void seam_mark_clear_tface(Scene *scene, short mode)
int paintface_mouse_select(struct bContext *C, Object *ob, const int 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;
@@ -764,25 +559,34 @@ int paintface_mouse_select(struct bContext *C, Object *ob, const int mval[2], in
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(ob);
- me= get_mesh(vc->obact);
-
- if(me==NULL || me->totface==0 || sx*sy <= 0)
+ if(me==NULL || me->totpoly==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);
@@ -794,13 +598,13 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend)
while(a--) {
if(*rt) {
index= WM_framebuffer_to_index(*rt);
- if(index<=me->totface) selar[index]= 1;
+ if(index<=me->totpoly) selar[index]= 1;
}
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 {
@@ -823,6 +627,104 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend)
}
+/* (similar to void paintface_flush_flags(Object *ob))
+ * copy the vertex flags, most importantly selection from the mesh to the final derived mesh,
+ * use in object mode when selecting vertices (while painting) */
+void paintvert_flush_flags(Object *ob)
+{
+ Mesh *me= get_mesh(ob);
+ DerivedMesh *dm= ob->derivedFinal;
+ MVert *dm_mvert, *dm_mv;
+ int *index_array = NULL;
+ int totvert;
+ int i;
+
+ if(me==NULL || dm==NULL)
+ return;
+
+ index_array = dm->getVertDataArray(dm, CD_ORIGINDEX);
+
+ dm_mvert = dm->getVertArray(dm);
+ totvert = dm->getNumVerts(dm);
+
+ dm_mv= dm_mvert;
+
+ if(index_array) {
+ int orig_index;
+ for (i= 0; i<totvert; i++, dm_mv++) {
+ orig_index= index_array[i];
+ if(orig_index != ORIGINDEX_NONE) {
+ dm_mv->flag= me->mvert[index_array[i]].flag;
+ }
+ }
+ }
+ else {
+ for (i= 0; i<totvert; i++, dm_mv++) {
+ dm_mv->flag= me->mvert[i].flag;
+ }
+ }
+}
+/* note: if the caller passes FALSE to flush_flags, then they will need to run paintvert_flush_flags(ob) themselves */
+void paintvert_deselect_all_visible(Object *ob, int action, short flush_flags)
+{
+ Mesh *me;
+ MVert *mvert;
+ int a;
+
+ me= get_mesh(ob);
+ if(me==NULL) return;
+
+ if(action == SEL_INVERT) {
+ mvert= me->mvert;
+ a= me->totvert;
+ while(a--) {
+ if((mvert->flag & ME_HIDE) == 0) {
+ mvert->flag ^= SELECT;
+ }
+ mvert++;
+ }
+ }
+ else {
+ if (action == SEL_TOGGLE) {
+ action = SEL_SELECT;
+
+ mvert= me->mvert;
+ a= me->totvert;
+ while(a--) {
+ if((mvert->flag & ME_HIDE) == 0 && mvert->flag & SELECT) {
+ action = SEL_DESELECT;
+ break;
+ }
+ mvert++;
+ }
+ }
+
+ mvert= me->mvert;
+ a= me->totvert;
+ while(a--) {
+ if((mvert->flag & ME_HIDE) == 0) {
+ switch (action) {
+ case SEL_SELECT:
+ mvert->flag |= SELECT;
+ break;
+ case SEL_DESELECT:
+ mvert->flag &= ~SELECT;
+ break;
+ case SEL_INVERT:
+ mvert->flag ^= SELECT;
+ break;
+ }
+ }
+ mvert++;
+ }
+ }
+
+ if(flush_flags) {
+ paintvert_flush_flags(ob);
+ }
+}
+
+
/* ********************* MESH VERTEX MIRR TOPO LOOKUP *************** */
/* note, this is not the best place for the function to be but moved
* here to for the purpose of syncing with bmesh */
@@ -853,9 +755,9 @@ int ED_mesh_mirrtopo_recalc_check(Mesh *me, const int ob_mode, MirrTopoStore_t *
int totvert;
int totedge;
- if (me->edit_mesh) {
- totvert = me->edit_mesh->totvert;
- totedge = me->edit_mesh->totedge;
+ if (me->edit_btmesh) {
+ totvert = me->edit_btmesh->bm->totvert;
+ totedge = me->edit_btmesh->bm->totedge;
}
else {
totvert = me->totvert;
@@ -879,11 +781,11 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to
const short skip_em_vert_array_init)
{
MEdge *medge;
- EditMesh *em = me->edit_mesh;
- void **eve_tmp_back = NULL; /* some of the callers are using eve->tmp so restore after */
+ BMEditMesh *em = me->edit_btmesh;
/* editmode*/
- EditEdge *eed;
+ BMEdge *eed;
+ BMIter iter;
int a, last;
int totvert, totedge;
@@ -901,13 +803,9 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to
mesh_topo_store->prev_ob_mode = ob_mode;
if(em) {
- EditVert *eve;
- totvert = 0;
- eve_tmp_back = MEM_mallocN(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_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ totvert = em->bm->totvert;
}
else {
totvert = me->totvert;
@@ -917,11 +815,11 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to
/* Initialize the vert-edge-user counts used to detect unique topology */
if(em) {
- totedge = 0;
+ totedge = me->edit_btmesh->bm->totedge;
- for(eed=em->edges.first; eed; eed = eed->next, totedge++) {
- topo_hash[eed->v1->tmp.l]++;
- topo_hash[eed->v2->tmp.l]++;
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ topo_hash[BM_elem_index_get(eed->v1)]++;
+ topo_hash[BM_elem_index_get(eed->v2)]++;
}
}
else {
@@ -940,9 +838,9 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to
/* use the number of edges per vert to give verts unique topology IDs */
if(em) {
- for(eed=em->edges.first; eed; eed = eed->next) {
- topo_hash[eed->v1->tmp.l] += topo_hash_prev[eed->v2->tmp.l];
- topo_hash[eed->v2->tmp.l] += topo_hash_prev[eed->v1->tmp.l];
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ topo_hash[BM_elem_index_get(eed->v1)] += topo_hash_prev[BM_elem_index_get(eed->v2)];
+ topo_hash[BM_elem_index_get(eed->v2)] += topo_hash_prev[BM_elem_index_get(eed->v1)];
}
}
else {
@@ -976,19 +874,6 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to
memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * 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 */
topo_pairs = MEM_callocN( sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs");
@@ -997,7 +882,7 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to
if(em) {
if (skip_em_vert_array_init == FALSE) {
- EM_init_index_arrays(em, 1, 0, 0);
+ EDBM_init_index_arrays(em,1, 0, 0);
}
}
@@ -1018,12 +903,12 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to
/* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2,
* but you cant ever access the last 'a' index of MirrTopoPairs */
for(a=2; a <= totvert; a++) {
- /* printf("I %d %ld %d\n", (a-last), MirrTopoPairs[a ].hash, MirrTopoPairs[a ].vIndex ); */
+ /* printf("I %d %ld %d\n", (a-last), MirrTopoPairs[a ].hash, MirrTopoPairs[a ].v_index ); */
if ((a==totvert) || (topo_pairs[a-1].hash != topo_pairs[a].hash)) {
if (a-last==2) {
if(em) {
- index_lookup[topo_pairs[a-1].v_index] = (intptr_t)EM_get_vert_for_index(topo_pairs[a-2].v_index);
- index_lookup[topo_pairs[a-2].v_index] = (intptr_t)EM_get_vert_for_index(topo_pairs[a-1].v_index);
+ index_lookup[topo_pairs[a-1].v_index] = (intptr_t)EDBM_get_vert_for_index(em, topo_pairs[a-2].v_index);
+ index_lookup[topo_pairs[a-2].v_index] = (intptr_t)EDBM_get_vert_for_index(em, topo_pairs[a-1].v_index);
}
else {
index_lookup[topo_pairs[a-1].v_index] = topo_pairs[a-2].v_index;
@@ -1035,7 +920,7 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to
}
if(em) {
if (skip_em_vert_array_init == FALSE) {
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
}
}
diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c
deleted file mode 100644
index 26645b66c7f..00000000000
--- a/source/blender/editors/mesh/editmesh.c
+++ /dev/null
@@ -1,2074 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): Blender Foundation, full recode 2002-2008
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/mesh/editmesh.c
- * \ingroup edmesh
- */
-
-
-
-#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->freestyle = example->freestyle;
- 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;
-
- 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.999f && inp >-0.999f) 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.001f) 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_face_sel= paint_facesel_test(ob);
- const short is_paint_vert_sel= is_paint_face_sel ? FALSE : paint_vertsel_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_face_sel)
- eve->f |= (mvert->flag & SELECT);
-
- if (mvert->flag & ME_HIDE) eve->h= 1;
- normal_short_to_float_v3(eve->no, mvert->no);
-
- 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) {
- int is_sel;
- if (is_paint_vert_sel) {
- /* when from vertex select, flush flags to edges,
- * allow selection, code below handles editmode selection conversion */
- is_sel= (eed->v1->f & SELECT) && (eed->v2->f & SELECT);
- }
- else {
- is_sel= (medge->flag & SELECT);
- }
-
- 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 & ME_FREESTYLE_EDGE) eed->freestyle = 1;
- if(medge->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines!
- if(medge->flag & ME_HIDE) eed->h |= 1;
- if(is_sel) eed->f |= SELECT;
- 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 {
- int is_sel;
-
- if (!is_paint_vert_sel) {
- is_sel= (mface->flag & ME_FACE_SEL);
- }
- else {
- /* when from vertex select, flush flags to edges,
- * allow selection, code below handles editmode selection conversion */
- is_sel= ( (efa->v1->f & SELECT) &&
- (efa->v2->f & SELECT) &&
- (efa->v3->f & SELECT) &&
- (efa->v4 == NULL || efa->v4->f & SELECT)
- );
- }
-
- if (a==me->act_face) {
- EM_set_actFace(em, efa);
- }
-
- /* dont allow hidden and selected */
- if(is_sel) {
- efa->f |= SELECT;
-
- if(is_paint_face_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;
- 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 */
- normal_float_to_short_v3(mvert->no, eve->no);
-
- /* 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.0f*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->freestyle) medge->flag |= ME_FREESTYLE_EDGE;
- if(eed->h & EM_FGON) medge->flag |= ME_FGON; // different defines yes
- if(eed->h & 1) medge->flag |= ME_HIDE;
-
- medge->crease= (char)(255.0f*eed->crease);
- medge->bweight= (char)(255.0f*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==obedit && 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 */
- float (*fp)[3]= actkey->data;
- 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) {
- sub_v3_v3v3(ofs[i], mvert->co, fp[eve->keyindex]);
- }
-
- 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;
-
- /* copy settings */
- menew->texflag= me->texflag;
- menew->drawflag= me->drawflag;
- menew->flag= me->flag;
- menew->editflag= me->editflag;
- menew->smoothresh= me->smoothresh;
-
- /* 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(em->totfacesel > 0) {
- mesh_separate_selected(op, bmain, scene, editbase);
- }
- }
-
- 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_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, freestyle;
- 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;
- 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);
- 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++) {
- copy_v3_v3(evec->co, eve->co);
- copy_v3_v3(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.0f);
-
- 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->freestyle= eed->freestyle;
- eedc->crease= (short)(eed->crease*255.0f);
- eedc->bweight= (short)(eed->bweight*255.0f);
- 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;
- }
-
- 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;
-
- copy_v3_v3(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->freestyle= eedc->freestyle;
- 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);
-}
-
-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;
- }
-}
-
-
-/* (similar to void paintface_flush_flags(Object *ob))
- * copy the vertex flags, most importantly selection from the mesh to the final derived mesh,
- * use in object mode when selecting vertices (while painting) */
-void paintvert_flush_flags(Object *ob)
-{
- Mesh *me= get_mesh(ob);
- DerivedMesh *dm= ob->derivedFinal;
- MVert *dm_mvert, *dm_mv;
- int *index_array = NULL;
- int totvert;
- int i;
-
- if(me==NULL || dm==NULL)
- return;
-
- index_array = dm->getVertDataArray(dm, CD_ORIGINDEX);
-
- dm_mvert = dm->getVertArray(dm);
- totvert = dm->getNumVerts(dm);
-
- dm_mv= dm_mvert;
-
- if(index_array) {
- int orig_index;
- for (i= 0; i<totvert; i++, dm_mv++) {
- orig_index= index_array[i];
- if(orig_index != ORIGINDEX_NONE) {
- dm_mv->flag= me->mvert[index_array[i]].flag;
- }
- }
- }
- else {
- for (i= 0; i<totvert; i++, dm_mv++) {
- dm_mv->flag= me->mvert[i].flag;
- }
- }
-}
-/* note: if the caller passes FALSE to flush_flags, then they will need to run paintvert_flush_flags(ob) themselves */
-void paintvert_deselect_all_visible(Object *ob, int action, short flush_flags)
-{
- Mesh *me;
- MVert *mvert;
- int a;
-
- me= get_mesh(ob);
- if(me==NULL) return;
-
- if(action == SEL_INVERT) {
- mvert= me->mvert;
- a= me->totvert;
- while(a--) {
- if((mvert->flag & ME_HIDE) == 0) {
- mvert->flag ^= SELECT;
- }
- mvert++;
- }
- }
- else {
- if (action == SEL_TOGGLE) {
- action = SEL_SELECT;
-
- mvert= me->mvert;
- a= me->totvert;
- while(a--) {
- if((mvert->flag & ME_HIDE) == 0 && mvert->flag & SELECT) {
- action = SEL_DESELECT;
- break;
- }
- mvert++;
- }
- }
-
- mvert= me->mvert;
- a= me->totvert;
- while(a--) {
- if((mvert->flag & ME_HIDE) == 0) {
- switch (action) {
- case SEL_SELECT:
- mvert->flag |= SELECT;
- break;
- case SEL_DESELECT:
- mvert->flag &= ~SELECT;
- break;
- case SEL_INVERT:
- mvert->flag ^= SELECT;
- break;
- }
- }
- mvert++;
- }
- }
-
- if(flush_flags) {
- paintvert_flush_flags(ob);
- }
-}
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index 043e02ab1d0..ea9dc73ee94 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -20,7 +20,7 @@
*
* The Original Code is: all of this file.
*
- * Contributor(s): none yet.
+ * Contributor(s): Joseph Eagar
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -29,1370 +29,99 @@
* \ingroup edmesh
*/
-
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#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 "RNA_define.h"
#include "RNA_access.h"
-#include "RNA_enum_types.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 "BKE_tessmesh.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] = {
- {2,0,1},
- {1,0,5},
- {3,0,2},
- {4,0,3},
- {5,0,4},
- {1,5,10},
- {2,1,6},
- {3,2,7},
- {4,3,8},
- {5,4,9},
- {6,1,10},
- {7,2,6},
- {8,3,7},
- {9,4,8},
- {10,5,9},
- {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) {
- const 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, TRUE);
- 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= dot_v3v3(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 imat[4][4];
- const float *curs= give_cursor(vc.scene, vc.v3d);
-
- copy_v3_v3(min, curs);
- view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE);
-
- eve= addvertlist(vc.em, 0, NULL);
-
- invert_m4_m4(imat, vc.obedit->obmat);
- mul_v3_m4v3(eve->co, imat, min);
-
- 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)
+/* 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);
- 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;
+ View3D *v3d =CTX_wm_view3d(C);
+ float mat[3][3], rmat[3][3], cmat[3][3], imat[3][3];
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
-}
+ unit_m4(primmat);
-
-
-/* ************************ 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;
- float len, len2, vec2[3];
-
- 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;
- }
- recalc_editnormals(em);
- 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*sinf(phi);
- vec[1]= 0.0;
- vec[2]= dia*cosf(phi);
- eve= addvertlist(em, vec, NULL);
- eve->f= 1+2+4;
- if(a==0) v1= eve;
- else addedgelist(em, eve, eve->prev, 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);
- }
-
- /* length of one segment on meridian */
- len= 2*dia*sinf(phid / 2.0f);
-
- /* length of one segment in shortest parallen */
- vec[0]= dia*sinf(phid);
- vec[1]= 0.0;
- vec[2]= dia*cosf(phid);
-
- mul_v3_m3v3(vec2, cmat, vec);
- len2= len_v3v3(vec, vec2);
-
- /* use shortest segment length divided by 3 as merge threshold */
- removedoublesflag(em, 4, 0, MIN2(len, len2) / 3.0f);
-
- /* and now do imat */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & SELECT) {
- mul_m4_v3(mat,eve->co);
- }
- eve= eve->next;
- }
- recalc_editnormals(em);
- 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*sinf(phi);
- vec[1]= dia*cosf(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);
- }
- }
+ eul_to_mat3(rmat, rot);
+ invert_m3(rmat);
- 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 */
+ /* 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);
- if(!ELEM5(type, PRIM_GRID, PRIM_PLANE, PRIM_ICOSPHERE, PRIM_UVSPHERE, PRIM_MONKEY))
- EM_recalc_normal_direction(em, FALSE, TRUE); /* otherwise monkey has eyes in wrong direction */
+ /* center */
+ copy_v3_v3(primmat[3], loc);
+ sub_v3_v3(primmat[3], obedit->obmat[3]);
+ invert_m3_m3(imat, mat);
+ mul_m3_v3(imat, primmat[3]);
- BKE_mesh_end_editmesh(obedit->data, em);
+ return v3d ? v3d->grid : 1.0f;
}
/* ********* 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)
+static void make_prim_init(bContext *C, const char *idname,
+ float *dia, float mat[][4],
+ int *state, float *loc, float *rot, unsigned int layer)
{
Object *obedit= CTX_data_edit_object(C);
- int newob = 0;
- float mat[4][4];
- float scale;
+ *state = 0;
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));
-
+ rename_id((ID *)obedit, idname);
+ rename_id((ID *)obedit->data, idname);
+
/* create editmode */
ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER); /* rare cases the active layer is messed up */
- newob = 1;
+ *state = 1;
}
else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
- scale= ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
+ *dia *= new_primitive_matrix(C, loc, rot, mat);
+}
+
+static void make_prim_finish(bContext *C, int *state, int enter_editmode)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
- dia *= scale;
- depth *= scale * 0.5f;
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
- make_prim(obedit, type, mat, tot, seg, subdiv, dia, depth, ext, fill);
+ /* Primitive has all verts selected, use vert select flush
+ * to push this up to edges & faces. */
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
- DAG_id_tag_update(obedit->data, 0);
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
/* userdef */
- if (newob && !enter_editmode) {
+ 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);
@@ -1400,16 +129,27 @@ static void make_prim_ext(bContext *C, float *loc, float *rot, int enter_editmod
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 = 1.0f;
int enter_editmode;
+ int state;
unsigned int layer;
- float loc[3], rot[3];
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, "Plane", &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, dia, mat))
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);
+ make_prim_finish(C, &state, enter_editmode);
+
return OPERATOR_FINISHED;
}
@@ -1433,16 +173,27 @@ void MESH_OT_primitive_plane_add(wmOperatorType *ot)
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;
unsigned int layer;
- float loc[3], rot[3];
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, "Cube", &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: M_SQRT2 - plane (diameter of 1.41 makes it unit size) */
+ make_prim_finish(C, &state, enter_editmode);
- /* 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;
}
@@ -1464,21 +215,41 @@ void MESH_OT_primitive_cube_add(wmOperatorType *ot)
ED_object_add_generic_props(ot, TRUE);
}
+static const EnumPropertyItem fill_type_items[]= {
+ {0, "NOTHING", 0, "Nothing", "Don't fill at all"},
+ {1, "NGON", 0, "Ngon", "Use ngons"},
+ {2, "TRIFAN", 0, "Triangle Fan", "Use triangle fans"},
+ {0, NULL, 0, NULL, NULL}};
+
static int add_primitive_circle_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, cap_end, cap_tri;
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;
+ cap_end = RNA_enum_get(op->ptr, "fill_type");
+ cap_tri = cap_end==2;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, "Circle", &dia, mat, &state, loc, rot, layer);
- 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"));
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
- return OPERATOR_FINISHED;
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_circle segments=%i diameter=%f cap_ends=%i cap_tris=%i mat=%m4",
+ RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"),
+ cap_end, cap_tri, mat))
+ return OPERATOR_CANCELLED;
+
+ make_prim_finish(C, &state, enter_editmode);
+
+ return OPERATOR_FINISHED;
}
void MESH_OT_primitive_circle_add(wmOperatorType *ot)
@@ -1502,26 +273,39 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot)
RNA_def_int(ot->srna, "vertices", 32, 3, INT_MAX, "Vertices", "", 3, 500);
prop = RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
- RNA_def_boolean(ot->srna, "fill", 0, "Fill", "");
+ RNA_def_enum(ot->srna, "fill_type", fill_type_items, 0, "Fill Type", "");
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, cap_end, cap_tri;
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;
+ cap_end = RNA_enum_get(op->ptr, "end_fill_type");
+ cap_tri = cap_end==2;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, "Cylinder", &dia, mat, &state, loc, rot, layer);
- 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"));
+ 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 cap_tris=%i depth=%f mat=%m4",
+ RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"),
+ RNA_float_get(op->ptr, "radius"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat))
+ return OPERATOR_CANCELLED;
+
+ make_prim_finish(C, &state, enter_editmode);
+
return OPERATOR_FINISHED;
}
@@ -1548,26 +332,40 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot)
RNA_def_property_subtype(prop, PROP_DISTANCE);
prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
- RNA_def_boolean(ot->srna, "cap_ends", 1, "Cap Ends", "");
+ RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Cap Fill Type", "");
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, cap_end, cap_tri;
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;
+ cap_end = RNA_enum_get(op->ptr, "end_fill_type");
+ cap_tri = cap_end==2;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, "Cone", &dia, mat, &state, loc, rot, layer);
- 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"));
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
- return OPERATOR_FINISHED;
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%i cap_tris=%i depth=%f mat=%m4",
+ RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius1"),
+ RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, 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)
@@ -1589,29 +387,44 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot)
/* props */
RNA_def_int(ot->srna, "vertices", 32, 2, INT_MAX, "Vertices", "", 2, 500);
- prop = RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
+ prop = RNA_def_float(ot->srna, "radius1", 1.0f, 0.0, FLT_MAX, "Radius 1", "", 0.001, 100.00);
+ RNA_def_property_subtype(prop, PROP_DISTANCE);
+ prop = RNA_def_float(ot->srna, "radius2", 0.0f, 0.0, FLT_MAX, "Radius 2", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
- RNA_def_boolean(ot->srna, "cap_end", 1, "Cap End", "");
+ RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Base Fill Type", "");
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 = 1.0f;
int enter_editmode;
+ int state;
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;
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, "Grid", &dia, mat, &state, loc, rot, layer);
- 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);
+ 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") * dia, mat))
+ {
+ return OPERATOR_CANCELLED;
+ }
+
+ make_prim_finish(C, &state, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -1643,16 +456,29 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot)
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, view_aligned;
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;
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, &view_aligned);
+ if (!view_aligned)
+ rot[0] += M_PI/2.0f;
+
+ make_prim_init(C, "Monkey", &dia, mat, &state, loc, rot, layer);
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_MONKEY, 0, 0, 2, 0.0f, 0.0f, 0, 0);
+ 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;
}
@@ -1676,17 +502,28 @@ void MESH_OT_primitive_monkey_add(wmOperatorType *ot)
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;
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;
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, "Sphere", &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
- 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);
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_uvsphere segments=%i revolutions=%i diameter=%f mat=%m4",
+ RNA_int_get(op->ptr, "ring_count"), 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;
}
@@ -1719,16 +556,29 @@ void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot)
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;
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;
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, "Icosphere", &dia, mat, &state, loc, rot, layer);
- 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);
+ 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;
}
@@ -1757,47 +607,3 @@ void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot)
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 Mesh";
- 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_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
-}
-
diff --git a/source/blender/editors/mesh/editmesh_bvh.c b/source/blender/editors/mesh/editmesh_bvh.c
new file mode 100644
index 00000000000..cc1f89e2c8b
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_bvh.c
@@ -0,0 +1,418 @@
+/*
+ * ***** 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) 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 "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+
+#include "BLI_math.h"
+#include "BLI_smallhash.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_tessmesh.h"
+
+#include "ED_mesh.h"
+#include "ED_view3d.h"
+
+
+typedef struct BMBVHTree {
+ BMEditMesh *em;
+ BMesh *bm;
+ BVHTree *tree;
+ float epsilon;
+ float maxdist; //for nearest point search
+ float uv[2];
+
+ /*stuff for topological vert search*/
+ BMVert *v, *curv;
+ GHash *gh;
+ float curw, curd;
+ float co[3], (*cagecos)[3], (*cos)[3];
+ int curtag, flag;
+
+ Object *ob;
+ Scene *scene;
+} BMBVHTree;
+
+static void cage_mapped_verts_callback(void *userData, int index, float *co,
+ float *UNUSED(no_f), short *UNUSED(no_s))
+{
+ void **data = userData;
+ BMEditMesh *em = data[0];
+ float (*cagecos)[3] = data[1];
+ SmallHash *hash = data[2];
+
+ if (index >= 0 && index < em->bm->totvert && !BLI_smallhash_haskey(hash, index)) {
+ BLI_smallhash_insert(hash, index, NULL);
+ copy_v3_v3(cagecos[index], co);
+ }
+}
+
+BMBVHTree *BMBVH_NewBVH(BMEditMesh *em, int flag, Scene *scene, Object *obedit)
+{
+ BMBVHTree *tree = MEM_callocN(sizeof(*tree), "BMBVHTree");
+ DerivedMesh *cage, *final;
+ SmallHash shash;
+ float cos[3][3], (*cagecos)[3] = NULL;
+ int i;
+
+ /*when initializing cage verts, we only want the first cage coordinate for each vertex,
+ so that e.g. mirror or array use original vertex coordiantes and not mirrored or duplicate*/
+ BLI_smallhash_init(&shash);
+
+ BMEdit_RecalcTesselation(em);
+
+ tree->ob = obedit;
+ tree->scene = scene;
+ tree->em = em;
+ tree->bm = em->bm;
+ tree->epsilon = FLT_EPSILON*2.0f;
+ tree->flag = flag;
+
+ tree->tree = BLI_bvhtree_new(em->tottri, tree->epsilon, 8, 8);
+
+ if (flag & BMBVH_USE_CAGE) {
+ BMIter iter;
+ BMVert *v;
+ void *data[3];
+
+ tree->cos = MEM_callocN(sizeof(float)*3*em->bm->totvert, "bmbvh cos");
+ BM_ITER_INDEX(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL, i) {
+ BM_elem_index_set(v, i); /* set_inline */
+ copy_v3_v3(tree->cos[i], v->co);
+ }
+ em->bm->elem_index_dirty &= ~BM_VERT;
+
+
+ cage = editbmesh_get_derived_cage_and_final(scene, obedit, em, &final, CD_MASK_DERIVEDMESH);
+ cagecos = MEM_callocN(sizeof(float)*3*em->bm->totvert, "bmbvh cagecos");
+
+ data[0] = em;
+ data[1] = cagecos;
+ data[2] = &shash;
+
+ cage->foreachMappedVert(cage, cage_mapped_verts_callback, data);
+ }
+
+ tree->cagecos = cagecos;
+
+ for (i=0; i<em->tottri; i++) {
+ if (flag & BMBVH_USE_CAGE) {
+ copy_v3_v3(cos[0], cagecos[BM_elem_index_get(em->looptris[i][0]->v)]);
+ copy_v3_v3(cos[1], cagecos[BM_elem_index_get(em->looptris[i][1]->v)]);
+ copy_v3_v3(cos[2], cagecos[BM_elem_index_get(em->looptris[i][2]->v)]);
+ } else {
+ copy_v3_v3(cos[0], em->looptris[i][0]->v->co);
+ copy_v3_v3(cos[1], em->looptris[i][1]->v->co);
+ copy_v3_v3(cos[2], em->looptris[i][2]->v->co);
+ }
+
+ BLI_bvhtree_insert(tree->tree, i, (float*)cos, 3);
+ }
+
+ BLI_bvhtree_balance(tree->tree);
+ BLI_smallhash_release(&shash);
+
+ return tree;
+}
+
+void BMBVH_FreeBVH(BMBVHTree *tree)
+{
+ BLI_bvhtree_free(tree->tree);
+
+ if (tree->cagecos)
+ MEM_freeN(tree->cagecos);
+ if (tree->cos)
+ MEM_freeN(tree->cos);
+
+ 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(isect_ray_tri_v3((float*)ray->origin, (float*)ray->direction, v0, v1, v2, &dist, uv))
+ return dist;
+
+ 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;
+
+ copy_v3_v3(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);
+
+ copy_v2_v2(tree->uv, uv);
+ }
+}
+
+BMFace *BMBVH_RayCast(BMBVHTree *tree, float *co, float *dir, float *hitout, float *cagehit)
+{
+ BVHTreeRayHit hit;
+
+ hit.dist = FLT_MAX;
+ hit.index = -1;
+
+ tree->uv[0] = tree->uv[1] = 0.0f;
+
+ BLI_bvhtree_ray_cast(tree->tree, co, dir, 0.0f, &hit, raycallback, tree);
+ if (hit.dist != FLT_MAX && hit.index != -1) {
+ if (hitout) {
+ if (tree->flag & BMBVH_RETURN_ORIG) {
+ BMVert *v1, *v2, *v3;
+ float co[3];
+ int i;
+
+ v1 = tree->em->looptris[hit.index][0]->v;
+ v2 = tree->em->looptris[hit.index][1]->v;
+ v3 = tree->em->looptris[hit.index][2]->v;
+
+ for (i=0; i<3; i++) {
+ co[i] = v1->co[i] + (v2->co[i] - v1->co[i])*tree->uv[0] + (v3->co[i]-v1->co[i])*tree->uv[1];
+ }
+ copy_v3_v3(hitout, co);
+ } else {
+ copy_v3_v3(hitout, hit.co);
+ }
+
+ if (cagehit)
+ copy_v3_v3(cagehit, 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) {
+ copy_v3_v3(hit->co, ls[i]->v->co);
+ copy_v3_v3(hit->no, ls[i]->v->no);
+ hit->dist = dist;
+ hit->index = index;
+ }
+ }
+}
+
+BMVert *BMBVH_FindClosestVert(BMBVHTree *tree, float *co, float maxdist)
+{
+ BVHTreeNearest hit;
+
+ copy_v3_v3(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[cur]->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;
+
+/* UNUSED */
+#if 0
+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;
+}
+#endif
+
+#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, NULL);
+
+ if (f && BM_edge_in_face(f, e))
+ return NULL;
+
+ return f;
+}
+
+static 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, ARegion *ar, View3D *v3d, 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;
+ float mval_f[2], end[3];
+
+ if (!ar) {
+ printf("error in BMBVH_EdgeVisible!\n");
+ return 0;
+ }
+
+ mval_f[0] = ar->winx/2.0;
+ mval_f[1] = ar->winy/2.0;
+ ED_view3d_win_to_segment_clip(ar, v3d, mval_f, origin, end);
+
+ invert_m4_m4(invmat, obedit->obmat);
+ mul_m4_v3(invmat, origin);
+
+ copy_v3_v3(co1, e->v1->co);
+ add_v3_v3v3(co2, e->v1->co, e->v2->co);
+ mul_v3_fl(co2, 0.5f);
+ copy_v3_v3(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/editmesh_bvh.h b/source/blender/editors/mesh/editmesh_bvh.h
new file mode 100644
index 00000000000..c8baa804205
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_bvh.h
@@ -0,0 +1,67 @@
+/*
+ * ***** 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 *****
+ */
+
+/** \file blender/editors/mesh/editmesh_bvh.h
+ * \ingroup edmesh
+ */
+
+#ifndef __EDITBMESH_BVH_H__
+#define __EDITBMESH_BVH_H__
+
+struct BMEditMesh;
+struct BMFace;
+struct BMEdge;
+struct BMVert;
+struct RegionView3D;
+struct BMBVHTree;
+struct BVHTree;
+struct Scene;
+struct Object;
+
+#ifndef IN_EDITMESHBVH
+typedef struct BMBVHTree BMBVHTree;
+#endif
+
+struct BMBVHTree *BMBVH_NewBVH(struct BMEditMesh *em, int flag, struct Scene *scene, struct Object *obedit);
+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, float *cagehit);
+
+int BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e,
+ struct ARegion *ar, struct View3D *v3d, 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);
+
+/*BMBVH_NewBVH flag parameter*/
+#define BMBVH_USE_CAGE 1 /*project geometry onto modifier cage */
+#define BMBVH_RETURN_ORIG 2 /*use with BMBVH_USE_CAGE, returns hits in relation to original geometry*/
+
+#endif /* __EDITBMESH_BVH_H__ */
diff --git a/source/blender/editors/mesh/editmesh_lib.c b/source/blender/editors/mesh/editmesh_lib.c
deleted file mode 100644
index 2895f5c34e6..00000000000
--- a/source/blender/editors/mesh/editmesh_lib.c
+++ /dev/null
@@ -1,3070 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2004 by Blender Foundation
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/mesh/editmesh_lib.c
- * \ingroup edmesh
- */
-
-
-/*
-
-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 along 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 useful 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.5f) vec[0]=1;
- else if (eve->no[1]<0.5f) 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 along 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(dot_v3v3(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;
- copy_v3_v3(v1->no, efa->n);
- copy_v3_v3(v2->no, efa->n);
- copy_v3_v3(v3->no, efa->n);
- if(efa->v4) {
- v4= addvertlist(em, efa->v4->co, efa->v4);
- v4->f1= 1;
- copy_v3_v3(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);
-
- /* step 5; update normals after extrude */
- recalc_editnormals(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;
- }
-
- /* update normals after extrude */
- recalc_editnormals(em);
-
- if(is_zero_v3(nor)) 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) && (md->mode & eModifierMode_Realtime)) {
- MirrorModifierData *mmd = (MirrorModifierData*) md;
-
- if(mmd->flag & MOD_MIR_CLIPPING) {
- float mtx[4][4];
- if (mmd->mirror_ob) {
- float imtx[4][4];
- invert_m4_m4(imtx, mmd->mirror_ob->obmat);
- mult_m4_m4m4(mtx, imtx, obedit->obmat);
- }
-
- 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 ( (fabsf(co1[0]) < mmd->tolerance) &&
- (fabsf(co2[0]) < mmd->tolerance) )
- ++eed->f2;
-
- if (mmd->flag & MOD_MIR_AXIS_Y)
- if ( (fabsf(co1[1]) < mmd->tolerance) &&
- (fabsf(co2[1]) < mmd->tolerance) )
- ++eed->f2;
-
- if (mmd->flag & MOD_MIR_AXIS_Z)
- if ( (fabsf(co1[2]) < mmd->tolerance) &&
- (fabsf(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);
-
- /* step 8; update normals after extrude */
- recalc_editnormals(em);
-
- if(is_zero_v3(nor)) 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) && (md->mode & eModifierMode_Realtime)) {
- MirrorModifierData *mmd = (MirrorModifierData*) md;
-
- if(mmd->flag & MOD_MIR_CLIPPING) {
- float mtx[4][4];
- if (mmd->mirror_ob) {
- float imtx[4][4];
- invert_m4_m4(imtx, mmd->mirror_ob->obmat);
- mult_m4_m4m4(mtx, imtx, obedit->obmat);
- }
-
- 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 ( (fabsf(co1[0]) < mmd->tolerance) &&
- (fabsf(co2[0]) < mmd->tolerance) )
- ++eed->f2;
-
- if (mmd->flag & MOD_MIR_AXIS_Y)
- if ( (fabsf(co1[1]) < mmd->tolerance) &&
- (fabsf(co2[1]) < mmd->tolerance) )
- ++eed->f2;
- if (mmd->flag & MOD_MIR_AXIS_Z)
- if ( (fabsf(co1[2]) < mmd->tolerance) &&
- (fabsf(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);
-
- copy_v3_v3(v1->co, eve->co);
- copy_v3_v3(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(is_zero_v3(nor)) 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)
- zero_v3(eve->no);
-
- for(efa= em->faces.first; efa; efa=efa->next) {
- float *n4= (efa->v4)? efa->v4->no: NULL;
- float *c4= (efa->v4)? efa->v4->co: NULL;
-
- 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);
- }
-
- accumulate_vertex_normals(efa->v1->no, efa->v2->no, efa->v3->no, n4,
- efa->n, efa->v1->co, efa->v2->co, efa->v3->co, c4);
- }
-
- /* 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.0f) {
- copy_v3_v3(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;
-
- 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];
-
- if(fabsf(uv[0]-uv2[0]) < limit[0] && fabsf(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;
-}
-
-/* A specialized vert map used by stitch operator */
-UvElementMap *EM_make_uv_element_map(EditMesh *em, int selected, int do_islands)
-{
- EditVert *ev;
- EditFace *efa;
-
- /* vars from original func */
- UvElementMap *vmap;
- UvElement *buf;
- UvElement *islandbuf;
- MTFace *tf;
- unsigned int a;
- int i,j, totuv, nverts, nislands = 0, islandbufsize = 0;
- unsigned int *map;
- /* for uv island creation */
- EditFace **stack;
- int stacksize = 0;
-
- /* we need the vert */
- for(ev = em->verts.first, i = 0; ev; ev = ev->next, i++)
- ev->tmp.l = i;
-
- totuv = 0;
-
- for(efa = em->faces.first; efa; efa = efa->next)
- if(!selected || ((!efa->h) && (efa->f & SELECT)))
- totuv += (efa->v4)? 4: 3;
-
- if(totuv == 0)
- return NULL;
-
- vmap = (UvElementMap *)MEM_callocN(sizeof(*vmap), "UvVertElementMap");
- if(!vmap)
- return NULL;
-
- vmap->vert = (UvElement**)MEM_callocN(sizeof(*vmap->vert)*em->totvert, "UvElementVerts");
- buf = vmap->buf = (UvElement*)MEM_callocN(sizeof(*vmap->buf)*totuv, "UvElement");
-
- if(!vmap->vert || !vmap->buf) {
- EM_free_uv_element_map(vmap);
- return NULL;
- }
-
- vmap->totalUVs = totuv;
-
- for(efa = em->faces.first; efa; 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->face = efa;
- buf->separate = 0;
- buf->island = INVALID_ISLAND;
-
- buf->next = vmap->vert[(*(&efa->v1 + i))->tmp.l];
- vmap->vert[(*(&efa->v1 + i))->tmp.l] = buf;
-
- buf++;
- }
- }
-
- efa->tmp.l = INVALID_ISLAND;
- }
-
- /* sort individual uvs for each vert */
- for(a = 0, ev = em->verts.first; ev; a++, ev = ev->next) {
- UvElement *newvlist = NULL, *vlist = vmap->vert[a];
- UvElement *iterv, *v, *lastv, *next;
- float *uv, *uv2;
-
- while(vlist) {
- v= vlist;
- vlist= vlist->next;
- v->next= newvlist;
- newvlist= v;
-
- efa = v->face;
- 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 = iterv->face;
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- uv2 = tf->uv[iterv->tfindex];
-
- if(fabsf(uv[0]-uv2[0]) < STD_UV_CONNECT_LIMIT && fabsf(uv[1]-uv2[1]) < STD_UV_CONNECT_LIMIT) {
- 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_islands) {
- /* at this point, every UvElement in vert points to a UvElement sharing the same vertex. Now we should sort uv's in islands. */
-
- /* map holds the map from current vmap->buf to the new, sorted map*/
- map = MEM_mallocN(sizeof(*map)*totuv, "uvelement_remap");
- stack = MEM_mallocN(sizeof(*stack)*em->totface, "uv_island_face_stack");
- islandbuf = MEM_callocN(sizeof(*islandbuf)*totuv, "uvelement_island_buffer");
-
- for(i = 0; i < totuv; i++) {
- if(vmap->buf[i].island == INVALID_ISLAND) {
- vmap->buf[i].island = nislands;
- stack[0] = vmap->buf[i].face;
- stack[0]->tmp.l = nislands;
- stacksize=1;
-
- while(stacksize > 0) {
- efa = stack[--stacksize];
- nverts = efa->v4? 4 : 3;
-
- for(j = 0; j < nverts; j++) {
- UvElement *element, *initelement = vmap->vert[(*(&efa->v1 + j))->tmp.l];
-
- for(element = initelement; element; element = element->next) {
- if(element->separate)
- initelement = element;
-
- if(element->face == efa) {
- /* found the uv corresponding to our face and vertex. Now fill it to the buffer */
- element->island = nislands;
- map[element - vmap->buf] = islandbufsize;
- islandbuf[islandbufsize].tfindex = element->tfindex;
- islandbuf[islandbufsize].face = element->face;
- islandbuf[islandbufsize].separate = element->separate;
- islandbuf[islandbufsize].island = nislands;
- islandbufsize++;
-
- for(element = initelement; element; element = element->next) {
- if(element->separate && element != initelement)
- break;
-
- if(element->face->tmp.l == INVALID_ISLAND) {
- stack[stacksize++] = element->face;
- element->face->tmp.l = nislands;
- }
- }
- break;
- }
- }
- }
- }
-
- nislands++;
- }
- }
-
- /* remap */
- for(i = 0; i < em->totvert; i++) {
- /* important since we may do selection only. Some of these may be NULL */
- if(vmap->vert[i])
- vmap->vert[i] = &islandbuf[map[vmap->vert[i] - vmap->buf]];
- }
-
- vmap->islandIndices = MEM_callocN(sizeof(*vmap->islandIndices)*nislands,"UvVertMap2_island_indices");
- if(!vmap->islandIndices) {
- MEM_freeN(islandbuf);
- MEM_freeN(stack);
- MEM_freeN(map);
- EM_free_uv_element_map(vmap);
- }
-
- j = 0;
- for(i = 0; i < totuv; i++) {
- UvElement *element = vmap->buf[i].next;
- if(element == NULL)
- islandbuf[map[i]].next = NULL;
- else
- islandbuf[map[i]].next = &islandbuf[map[element - vmap->buf]];
-
- if(islandbuf[i].island != j) {
- j++;
- vmap->islandIndices[j] = i;
- }
- }
-
- MEM_freeN(vmap->buf);
-
- vmap->buf = islandbuf;
- vmap->totalIslands = nislands;
- MEM_freeN(stack);
- MEM_freeN(map);
- }
-
- 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);
- }
-}
-
-void EM_free_uv_element_map(UvElementMap *vmap)
-{
- if (vmap) {
- if (vmap->vert) MEM_freeN(vmap->vert);
- if (vmap->buf) MEM_freeN(vmap->buf);
- if (vmap->islandIndices) MEM_freeN(vmap->islandIndices);
- 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;
- unsigned 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); \
- { \
- const unsigned int mf_v1 = EDV1; \
- const unsigned int mf_v2 = EDV2; \
- edge_ref = (EdgeFaceRef *)BLI_edgehash_lookup(edge_hash, mf_v1, mf_v2); \
- 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, mf_v1, mf_v2, 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, &ed_v1, &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 */
- copy_v3_v3(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);
- copy_v3_v3(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 01695331542..00000000000
--- a/source/blender/editors/mesh/editmesh_loop.c
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2004 by Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/mesh/editmesh_loop.c
- * \ingroup edmesh
- */
-
-
-/*
-
-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 "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 ******** */
-
-/* ***************** 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.001f; /* prevent missed edges */
- x2min=MIN2(x21,x22)-0.001f; /* due to round off error */
- y2max=MAX2(y21,y22)+0.001f;
- y2min=MIN2(y21,y22)-0.001f;
-
- /* 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.0f;
-
- y1max=MAX2(y11, y12);
- y1min=MIN2(y11, y12);
- yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0f;
- }
- 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.0f) && (m2 >= -1.0f)) 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);
-}
-
-/* for multicut */
-#define MAX_CUTS 256
-
-/* for amount of edges */
-#define MAX_CUT_EDGES 1024
-
-static int knife_cut_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
- ED_view3d_operator_properties_viewmat_set(C, op);
-
- return WM_gesture_lines_invoke(C, op, event);
-}
-
-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));
- EditEdge *eed;
- EditVert *eve;
- CutCurve curve[MAX_CUT_EDGES];
- 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_enum_get(op->ptr, "type");
- int winx, winy;
- float persmat[4][4];
-// 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 (obedit == NULL)
- 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_CUT_EDGES) break;
- }
- RNA_END;
-
- if(len<2) {
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- ED_view3d_operator_properties_viewmat_get(op, &winx, &winy, persmat);
-
- /*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);
- apply_project_float(persmat, winx, winy, 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= knife_cut_invoke;
- ot->modal= WM_gesture_lines_modal;
- ot->exec= knife_cut_exec;
- ot->cancel= WM_gesture_lines_cancel;
-
- 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 */
- prop = RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN);
-
- ED_view3d_operator_properties_viewmat(ot);
-}
-
-/* ******************************************************* */
-
diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c
deleted file mode 100644
index d7ec83e64e3..00000000000
--- a/source/blender/editors/mesh/editmesh_mods.c
+++ /dev/null
@@ -1,4527 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2004 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/mesh/editmesh_mods.c
- * \ingroup edmesh
- */
-
-
-/*
-
-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 "ED_uvedit.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; */ /* UNUSED */
-
- if ((scene->toolsettings->automerge) &&
- (obedit && obedit->type==OB_MESH && (obedit->mode & OB_MODE_EDIT))
- ) {
- EditMesh *em= me->edit_mesh;
- int totvert= em->totvert, totedge= em->totedge, totface= em->totface;
-
- /* len = */ /* UNUSED */ removedoublesflag(em, 1, 1, scene->toolsettings->doublimit);
- if (totvert != em->totvert || totedge != em->totedge || totface != em->totface) {
- 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(int 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, int 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 if(paint_vertsel_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++) glVertex2iv(mcords[a]);
- 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 if (paint_vertsel_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 { int mval[2]; short 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 { int mval[2]; short 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, V3D_CLIP_TEST_RV3D_CLIPPING);
-
- if (data.dist>3) {
- data.pass = 1;
- mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_CLIP_TEST_RV3D_CLIPPING);
- }
-
- *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(ED_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, V3D_CLIP_TEST_REGION);
-
- *dist = data.dist;
- return data.closest;
- }
-}
-
-static void findnearestface__getDistance(void *userData, EditFace *efa, int x, int y, int UNUSED(index))
-{
- struct { int 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 { int mval[2]; short 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 { int 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 { int mval[2]; short 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
-#define SIMEDGE_FREESTYLE 109
-
-/* 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", ""},
- {SIMEDGE_FREESTYLE, "FREESTYLE", 0, "Freestyle Edge Mark", ""},
- {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.5f) <= 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= RAD2DEGF(angle_v3v3(base_efa->n, efa->n));
- if (angle/180.0f<=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= RAD2DEGF(angle_v3v3(base_efa->n, efa->n));
- if (angle/180.0f<=thresh) {
- dot=dot_v3v3(efa->cent, base_efa->n);
- if (fabsf(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_enum_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;
-}
-
-/* ***************************************************** */
-
-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= RAD2DEGF(angle_v3v3(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= RAD2DEGF(angle_v3v3(base_dir, dir));
-
- if (angle>90.0f) /* use the smallest angle between the edges */
- angle= fabsf(angle-180.0f);
-
- if (angle / 90.0f<=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 &&
- (fabsf(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 &&
- (fabsf(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;
- }
- }
- } else if (mode==SIMEDGE_FREESTYLE) { /* Freestyle edge mark */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (
- !(eed->f & SELECT) &&
- !eed->h &&
- (eed->freestyle == base_eed->freestyle)
- ) {
- 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_enum_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;
-}
-
-/* ********************************* */
-
-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 OPERATOR_CANCELLED;
- }
-
- 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= RAD2DEGF(angle_v3v3(base_eve->no, eve->no));
- if (angle/180.0f<=thresh) {
- eve->f |= SELECT;
- selcount++;
- deselcount--;
- if (!deselcount) {/*have we selected all posible faces?, if so return*/
- BKE_mesh_end_editmesh(me, em);
- return OPERATOR_FINISHED;
- }
- }
- }
- }
- }
- 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 OPERATOR_FINISHED;
- }
- }
- }
- }
- 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 OPERATOR_FINISHED;
- }
-
- 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 OPERATOR_FINISHED;
- }
- 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;
-}
-
-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), PropertyRNA *UNUSED(prop), 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;
- } else {
- tf->tpage = NULL;
- }
- 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;
- } else {
- tf->tpage = NULL;
- }
- 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 UNUSED_FUNCTION(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;
-}
-
-static void ensure_ed_vert_sel(EditMesh *em)
-{
- EditEdge *eed;
-
- /* EM_selectmode_flush() doesnt take into account that deselected edges
- * may be still connected to selected edges [#26885] */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- eed->v1->f |= SELECT;
- eed->v2->f |= SELECT;
- }
- }
-}
-
-/* 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);
- }
-
- if(select == FALSE && !(em->selectmode & SCE_SELECT_VERTEX)) { /* only when not in vert sel [#26931] */
- ensure_ed_vert_sel(em);
- }
-}
-
-/*
- 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);
- }
-
- if(select == FALSE && !(em->selectmode & SCE_SELECT_VERTEX)) { /* only when not in vert sel [#26931] */
- ensure_ed_vert_sel(em);
- }
-}
-
-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, const int 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, const int 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;
- case EDGE_MODE_TAG_FREESTYLE:
- me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
- break;
- }
-
- /* live unwrap while tagging */
- if( (vc.scene->toolsettings->edge_mode_live_unwrap) &&
- (vc.scene->toolsettings->edge_mode == EDGE_MODE_TAG_SEAM) &&
- (CustomData_has_layer(&em->fdata, CD_MTFACE))
- ) {
- ED_unwrap_lscm(vc.scene, vc.obedit, FALSE); /* unwrap all not just sel */
- }
-
- 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, const int 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;
- WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, NULL);
- }
-
- 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 boundaries */
- 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_struct_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);
- else
- RNA_boolean_set(op->ptr, "limit", FALSE);
- }
-}
-
-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 boundaries (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 boundaries (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.0f - sharpness) * (float)M_PI) / 180.0f;
-
- /* 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 (fabsf(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.0f - sharpness) * (float)M_PI) / 180.0f;
-
- 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 (fabsf(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())
-
-}
-
-/* ******************** (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 editmesh_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= editmesh_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)
-{
- Scene *scene= CTX_data_scene(C);
- 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;
- }
- }
-
- /* live unwrap while tagging */
- if( (scene->toolsettings->edge_mode_live_unwrap) &&
- (CustomData_has_layer(&em->fdata, CD_MTFACE))
- ) {
- ED_unwrap_lscm(scene, obedit, FALSE); /* unwrap all not just sel */
- }
-
- 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", "");
-}
-
-static int editmesh_mark_freestyle_edge(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 Freestyle edge mark drawing */
- if(!clear) {
- me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
- }
-
- if(!clear) {
- eed= em->edges.first;
- while(eed) {
- if(!eed->h && (eed->f & SELECT)) eed->freestyle = 1;
- eed = eed->next;
- }
- } else {
- eed= em->edges.first;
- while(eed) {
- if(!eed->h && (eed->f & SELECT)) eed->freestyle = 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_freestyle_edge(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Mark Freestyle Edge";
- ot->description= "(un)mark selected edges as Freestyle feature edges";
- ot->idname= "MESH_OT_mark_freestyle_edge";
-
- /* api callbacks */
- ot->exec= editmesh_mark_freestyle_edge;
- 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.0f) flipface(em, startvl);
- }
- else {
- if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0f) 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) && (md->mode & eModifierMode_Realtime)) {
- MirrorModifierData *mmd = (MirrorModifierData*) md;
-
- if(mmd->flag & MOD_MIR_CLIPPING) {
- for (eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
-
- if (mmd->flag & MOD_MIR_AXIS_X && fabsf(eve->co[0]) < mmd->tolerance) eve->f2 |= 1;
- if (mmd->flag & MOD_MIR_AXIS_Y && fabsf(eve->co[1]) < mmd->tolerance) eve->f2 |= 2;
- if (mmd->flag & MOD_MIR_AXIS_Z && fabsf(eve->co[2]) < mmd->tolerance) eve->f2 |= 4;
-
- }
- }
- }
- }
- }
-
- eed= em->edges.first;
- while(eed) {
- if( (eed->v1->f & SELECT) || (eed->v2->f & SELECT) ) {
- mid_v3_v3v3(fvec, eed->v1->co, eed->v2->co);
-
- 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.5f/(float)eve->f1;
-
- if(xaxis)
- eve->co[0]= 0.5f*eve->co[0]+fac*adr[0];
- if(yaxis)
- eve->co[1]= 0.5f*eve->co[1]+fac*adr[1];
- if(zaxis)
- eve->co[2]= 0.5f*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.0f;
- 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/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
deleted file mode 100644
index 48b96eaf927..00000000000
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ /dev/null
@@ -1,6832 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2004 by Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Johnny Matthews, Geoffrey Bantle.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/mesh/editmesh_tools.c
- * \ingroup edmesh
- */
-
-
-/*
-
-editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise in mods.c
-
-*/
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
-#include "BLO_sys_types.h" // for intptr_t support
-
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_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_global.h"
-#include "BKE_key.h"
-#include "BKE_mesh.h"
-#include "BKE_bmesh.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"
-
-/* XXX */
-static void waitcursor(int UNUSED(val)) {}
-#define add_numbut(a, b, c, d, e, f, g) {}
-
-/* XXX */
-
-/* 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}};
-
-
-/* local prototypes ---------------*/
-static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa);
-int EdgeLoopDelete(EditMesh *em, wmOperator *op);
-
-/********* qsort routines *********/
-
-
-typedef struct xvertsort {
- float x;
- EditVert *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;
-}
-
-
-/* *********************************** */
-
-static void convert_to_triface(EditMesh *em, int direction)
-{
- EditFace *efa, *efan, *next;
- float fac;
-
- efa= em->faces.last;
- while(efa) {
- next= efa->prev;
- if(efa->v4) {
- if(efa->f & SELECT) {
- /* choose shortest diagonal for split */
- 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);
- if(efa->f & SELECT) EM_select_face(efan, 1);
- efan= EM_face_from_faces(em, 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);
- if(efa->f & SELECT) EM_select_face(efan, 1);
- efan= EM_face_from_faces(em, efa, NULL, 1, 2, 3, -1);
- if(efa->f & SELECT) EM_select_face(efan, 1);
- }
-
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- }
- efa= next;
- }
-
- EM_fgon_flags(em); // redo flags and indices for fgons
-
-
-}
-
-int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /* return amount */
-{
- /*
- flag - Test with vert->flags
- automerge - Alternative operation, merge unselected into selected.
- Used for "Auto Weld" mode. warning.
- limit - Quick manhattan distance between verts.
- */
-
- /* all verts with (flag & 'flag') are being evaluated */
- EditVert *eve, *v1, *nextve;
- EditEdge *eed, *e1, *nexted;
- EditFace *efa, *nextvl;
- xvertsort *sortblock, *sb, *sb1;
- struct facesort *vlsortblock, *vsb, *vsb1;
- int a, b, test, amount;
-
-
- /* flag 128 is cleared, count */
-
- /* Normal non weld operation */
- eve= em->verts.first;
- amount= 0;
- while(eve) {
- eve->f &= ~128;
- if(eve->h==0 && (automerge || (eve->f & flag))) amount++;
- eve= eve->next;
- }
- if(amount==0) return 0;
-
- /* allocate memory and qsort */
- sb= sortblock= MEM_mallocN(sizeof(xvertsort)*amount,"sortremovedoub");
- eve= em->verts.first;
- while(eve) {
- if(eve->h==0 && (automerge || (eve->f & flag))) {
- sb->x= eve->co[0]+eve->co[1]+eve->co[2];
- sb->v1= eve;
- sb++;
- }
- eve= eve->next;
- }
- qsort(sortblock, amount, sizeof(xvertsort), vergxco);
-
-
- /* test for doubles */
- sb= sortblock;
- if (automerge) {
- for(a=0; a<amount; a++, sb++) {
- eve= sb->v1;
- if( (eve->f & 128)==0 ) {
- 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 &&
- (float)fabs(v1->co[1]-eve->co[1])<=limit &&
- (float)fabs(v1->co[2]-eve->co[2])<=limit)
- { /* unique bit */
- eve->f|= 128;
- eve->tmp.v = v1;
- }
- } else if( (eve->f & flag)==1 && (v1->f & flag)==0 ) {
- 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 */
- v1->f|= 128;
- v1->tmp.v = eve;
- }
- }
- }
- }
- }
- }
- } else {
- for(a=0; a<amount; a++, sb++) {
- eve= sb->v1;
- if( (eve->f & 128)==0 ) {
- sb1= sb+1;
- for(b=a+1; b<amount; b++, sb1++) {
- /* 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 &&
- (float)fabs(v1->co[1]-eve->co[1])<=limit &&
- (float)fabs(v1->co[2]-eve->co[2])<=limit)
- {
- v1->f|= 128;
- v1->tmp.v = eve;
- }
- }
- }
- }
- }
- }
- 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);
-
- /* test edges and insert again */
- eed= em->edges.first;
- while(eed) {
- eed->f2= 0;
- eed= eed->next;
- }
- eed= em->edges.last;
- while(eed) {
- nexted= eed->prev;
-
- if(eed->f2==0) {
- if( (eed->v1->f & 128) || (eed->v2->f & 128) ) {
- remedge(em, 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);
-
- if(e1) {
- e1->f2= 1;
- if(eed->f & SELECT)
- e1->f |= SELECT;
- }
- if(e1!=eed) free_editedge(em, eed);
- }
- }
- eed= nexted;
- }
-
- /* first count amount of test faces */
- efa= (struct EditFace *)em->faces.first;
- amount= 0;
- while(efa) {
- efa->f1= 0;
- if(efa->v1->f & 128) efa->f1= 1;
- 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;
- }
-
- /* test faces for double vertices, and if needed remove them */
- efa= (struct EditFace *)em->faces.first;
- 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;
- if(efa->v3==efa->v1) test+=4;
- 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) {
- efa->v2= efa->v3;
- efa->v3= efa->v4;
- efa->v4= 0;
-
- EM_data_interp_from_faces(em, efa, NULL, efa, 0, 2, 3, 3);
-
- test= 0;
- }
- else if(test==8 || test==16) {
- efa->v4= 0;
- test= 0;
- }
- else {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- amount--;
- }
- }
- else {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- amount--;
- }
- }
-
- if(test==0) {
- /* set edge pointers */
- efa->e1= findedgelist(em, efa->v1, efa->v2);
- efa->e2= findedgelist(em, efa->v2, efa->v3);
- if(efa->v4==0) {
- efa->e3= findedgelist(em, 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= nextvl;
- }
-
- /* double faces: sort block */
- /* count again, now all selected faces */
- amount= 0;
- efa= em->faces.first;
- while(efa) {
- efa->f1= 0;
- if(faceselectedOR(efa, 1)) {
- efa->f1= 1;
- amount++;
- }
- efa= efa->next;
- }
-
- if(amount) {
- /* double faces: sort block */
- vsb= vlsortblock= MEM_mallocN(sizeof(struct facesort)*amount, "sortremovedoub");
- efa= em->faces.first;
- while(efa) {
- if(efa->f1 & 1) {
- if(efa->v4) vsb->x= (uintptr_t) MIN4( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3, (uintptr_t)efa->v4);
- else vsb->x= (uintptr_t) MIN3( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3);
-
- vsb->efa= efa;
- vsb++;
- }
- efa= efa->next;
- }
-
- qsort(vlsortblock, amount, sizeof(struct facesort), vergface);
-
- vsb= vlsortblock;
- for(a=0; a<amount; a++) {
- efa= vsb->efa;
- if( (efa->f1 & 128)==0 ) {
- 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);
- }
- efa= nextvl;
- }
- }
-
- /* remove double vertices */
- a= 0;
- eve= (struct EditVert *)em->verts.first;
- while(eve) {
- nextve= eve->next;
- if(automerge || eve->f & flag) {
- if(eve->f & 128) {
- a++;
- BLI_remlink(&em->verts, eve);
- free_editvert(em, 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 totvert= em->totvert, totedge= em->totedge, totface= em->totface;
-
- int count = removedoublesflag(em,1,0,RNA_float_get(op->ptr, "limit"));
-
- if (totvert != em->totvert || totedge != em->totedge || totface != em->totface) {
- recalc_editnormals(em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
- }
-
- 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);
-}
-
-// 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)
-{
- ViewContext vc;
- EditVert *eve;
- xvertsort *sortblock;
- ListBase tbase;
- int i, amount;
-
- em_setup_viewcontext(C, &vc);
-
- amount = BLI_countlist(&vc.em->verts);
- sortblock = MEM_callocN(sizeof(xvertsort)*amount,"xsort");
- for (i=0,eve= vc.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, V3D_CLIP_TEST_OFF);
-
- 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);
-
-}
-
-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;
-}
-
-
-/* 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);
-
-}
-
-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)
-{
- float nor[3]= {0.0, 0.0, 0.0};
- short transmode= 0;
-
- if(type<1) return;
-
- 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);
-
- if(transmode==0) {
- BKE_report(op->reports, RPT_WARNING, "Not a valid selection for extrude");
- }
- else {
- EM_fgon_flags(em);
-
- /* 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);
-
- /* individual faces? */
-// BIF_TransformSetUndo("Extrude");
- if(type==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_v3(nor, obedit->obmat[3]);
-// BIF_setSingleAxisConstraint(nor, "along normal");
- }
-// Transform();
- }
- }
-
-}
-
-// XXX should be a menu item
-static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- extrude_mesh(obedit, em, op, RNA_enum_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_enum_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;
-}
-
-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}};
-
-
-static EnumPropertyItem *mesh_extrude_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
-{
- EnumPropertyItem *item= NULL;
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em;
-
- int totitem= 0;
-
- if(obedit==NULL || obedit->type != OB_MESH)
- 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, mesh_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);
-
- /* 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, 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_split(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Split";
- ot->description= "Split selected geometry into separate disconnected mesh";
- 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 extrude_repeat_mesh_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- 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 */
- RNA_float_get_array(op->ptr, "direction", dvec);
- 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++) {
- extrudeflag(obedit, em, SELECT, nor, 0);
- translateflag(em, SELECT, dvec);
- }
-
- 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;
-}
-
-/* get center and axis, in global coords */
-static int extrude_repeat_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
-{
- RegionView3D *rv3d= ED_view3d_context_rv3d(C);
-
- if(rv3d)
- RNA_float_set_array(op->ptr, "direction", rv3d->persinv[2]);
-
- return extrude_repeat_mesh_exec(C, op);
-}
-
-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->invoke= extrude_repeat_mesh_invoke;
- ot->exec= extrude_repeat_mesh_exec;
- 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, 100.0f);
- RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, 180);
- RNA_def_float_vector(ot->srna, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "Direction", "Direction of extrude", -FLT_MAX, FLT_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);
- 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*(float)M_PI/360.0f;
- 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, 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);
-
- 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 int screw_mesh_exec(bContext *C, wmOperator *op)
-{
- 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_WARNING, "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.0f) {
- negate_v3(dvec);
- }
-
- 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);
-
- 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;
- }
-}
-
-/* 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)
-{
- 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);
- }
- ed= nexted;
- }
-}
-
-static void erase_faces(EditMesh *em, ListBase *l)
-{
- EditFace *f, *nextf;
-
- f = (EditFace *) l->first;
-
- while(f) {
- nextf= f->next;
- if( faceselectedOR(f, SELECT) ) {
- BLI_remlink(l, f);
- free_editface(em, f);
- }
- f = nextf;
- }
-}
-
-static void erase_vertices(EditMesh *em, ListBase *l)
-{
- EditVert *v, *nextv;
-
- v = (EditVert *) l->first;
- while(v) {
- nextv= v->next;
- if(v->f & 1) {
- BLI_remlink(l, v);
- free_editvert(em, v);
- }
- v = nextv;
- }
-}
-
-static void delete_mesh(EditMesh *em, wmOperator *op, int event)
-{
- EditFace *efa, *nextvl;
- EditVert *eve,*nextve;
- EditEdge *eed,*nexted;
- int count;
- /* const char *str="Erase"; */
-
-
- 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);
- }
- else if(event==6) {
- if(!EdgeLoopDelete(em, op))
- return;
-
- /* str= "Erase Edge Loop"; */
- }
- else if(event==4) {
- /* str= "Erase Edges & Faces"; */
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- /* delete only faces with 1 or more edges selected */
- count= 0;
- if(efa->e1->f & SELECT) count++;
- if(efa->e2->f & SELECT) count++;
- if(efa->e3->f & SELECT) count++;
- if(efa->e4 && (efa->e4->f & SELECT)) count++;
- if(count) {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- efa= nextvl;
- }
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
- if(eed->f & SELECT) {
- remedge(em, eed);
- free_editedge(em, eed);
- }
- eed= nexted;
- }
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- event=0;
- if( efa->v1->f & SELECT) 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);
- }
- efa= nextvl;
- }
- }
- else if(event==1) {
- /* str= "Erase Edges"; */
- // faces first
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- event=0;
- if( efa->e1->f & SELECT) 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);
- }
- efa= nextvl;
- }
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
- if(eed->f & SELECT) {
- remedge(em, eed);
- free_editedge(em, eed);
- }
- eed= nexted;
- }
- /* to remove loose vertices: */
- eed= em->edges.first;
- while(eed) {
- if( eed->v1->f & SELECT) eed->v1->f-=SELECT;
- if( eed->v2->f & SELECT) eed->v2->f-=SELECT;
- eed= eed->next;
- }
- 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 if(event==2) {
- /* str="Erase Faces"; */
- delfaceflag(em, 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);
- if(em->selected.first) BLI_freelistN(&(em->selected));
- }
- else if(event==5) {
- /* 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);
- }
- efa= nextvl;
- }
- }
-
- recalc_editnormals(em);
-
- EM_fgon_flags(em); // redo flags and indices for fgons
-}
-
-/* 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)
-{
- 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);
-
- delete_mesh(em, op, 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;
-}
-
-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");
-}
-
-
-/*GB*/
-/*-------------------------------------------------------------------------------*/
-/*--------------------------- Edge Based Subdivide ------------------------------*/
-
-#define EDGENEW 2
-#define FACENEW 2
-#define EDGEINNER 4
-#define EDGEOLD 8
-
-/*used by faceloop cut to select only edges valid for edge slide*/
-#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)
-{
- float tvec[3], fac;
-
- if(beauty & B_SMOOTH) {
- /* we calculate an offset vector tvec[], to be added to *co */
- float len, nor[3], nor1[3], nor2[3];
-
- sub_v3_v3v3(nor, edge->v1->co, edge->v2->co);
- len= 0.5f*normalize_v3(nor);
-
- copy_v3_v3(nor1, edge->v1->no);
- copy_v3_v3(nor2, edge->v2->no);
-
- /* cosine angle */
- fac= dot_v3v3(nor, nor1);
- mul_v3_v3fl(tvec, nor1, fac);
-
- /* cosine angle */
- fac= -dot_v3v3(nor, nor2);
- madd_v3_v3fl(tvec, nor2, fac);
-
- /* falloff for multi subdivide */
- smooth *= sqrtf(fabs(1.0f - 2.0f*fabsf(0.5f-perc)));
-
- mul_v3_fl(tvec, smooth * len);
-
- add_v3_v3(co, tvec);
- }
- else if(beauty & B_SPHERE) { /* subdivide sphere */
- normalize_v3(co);
- mul_v3_fl(co, smooth);
- }
-
- if(beauty & B_FRACTAL) {
- fac= fractal*len_v3v3(edge->v1->co, edge->v2->co);
- tvec[0]= fac*(float)(0.5-BLI_drand());
- tvec[1]= fac*(float)(0.5-BLI_drand());
- tvec[2]= fac*(float)(0.5-BLI_drand());
- add_v3_v3(co, tvec);
- }
-}
-
-/* assumes in the edge is the correct interpolated vertices already */
-/* percent defines the interpolation, smooth, fractal 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)
-{
- EditVert *ev;
- float co[3];
-
- interp_v3_v3v3(co, edge->v1->co, edge->v2->co, percent);
-
- /* offset for smooth or sphere or fractal */
- alter_co(co, edge, smooth, fractal, beauty, percent);
-
- /* 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;
- }
- }
-
- ev = addvertlist(em, co, NULL);
-
- /* vert data (vgroups, ..) */
- EM_data_interp_from_verts(em, edge->v1, edge->v2, ev, percent);
-
- /* normal */
- interp_v3_v3v3(ev->no, edge->v1->no, edge->v2->no, percent);
- normalize_v3(ev->no);
-
- return ev;
-}
-
-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;
- }
-}
-
-static void facecopy(EditMesh *em, EditFace *source, EditFace *target)
-{
- 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];
-
- CustomData_em_copy_data(&em->fdata, &em->fdata, source->data, &target->data);
-
- target->mat_nr = source->mat_nr;
- 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)
-{
- EditEdge *cedge=NULL;
- EditVert *v[4], **verts;
- EditFace *hold;
- short start=0, /* end, */ /* UNUSED */ left, right, vertsize,i;
-
- v[0] = efa->v1;
- v[1] = efa->v2;
- v[2] = efa->v3;
- 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;}
-
- // Point verts to the array of new verts for cedge
- verts = BLI_ghash_lookup(gh, cedge);
- //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] != v[start]) {flipvertarray(verts,numcuts+2);}
- /* end = (start+1)%4; */ /* UNUSED */
- left = (start+2)%4;
- right = (start+3)%4;
-
- /*
- We should have something like this now
-
- 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->e2->f2 |= EDGEINNER;
- hold->e4->f2 |= EDGEINNER;
- }else{
- hold = addfacelist(em, verts[(vertsize-1)/2],v[left],v[right],NULL, NULL,NULL);
- hold->e1->f2 |= EDGEINNER;
- hold->e3->f2 |= EDGEINNER;
- }
- facecopy(em, 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);
- if(i+1 != (vertsize-1)/2) {
- 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);
- if(i+1 != (vertsize-1)/2) {
- 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)
-{
- EditEdge *cedge=NULL;
- EditVert *v[3], **verts;
- EditFace *hold;
- short start=0, /* end, */ /* UNUSED */ op, vertsize,i;
-
- v[0] = efa->v1;
- v[1] = efa->v2;
- 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;}
-
- // Point verts to the array of new verts for cedge
- verts = BLI_ghash_lookup(gh, cedge);
- //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] != v[start]) {flipvertarray(verts,numcuts+2);}
- /* end = (start+1)%3; */ /* UNUSED */
- op = (start+2)%3;
-
- /*
- We should have something like this now
-
- 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
- |---*---*---|
- \ \ \ |
- \ \ \ |
- \ \ \ |
- \ \ \|
- \ \\|
- \ |
- |op
- */
-
- // Make side faces
- for(i=0;i<(vertsize-1);i++) {
- hold = addfacelist(em, verts[i],verts[i+1],v[op],NULL,NULL,NULL);
- if(i+1 != vertsize-1) {
- if(seltype == SUBDIV_SELECT_INNER) {
- hold->e2->f2 |= EDGEINNER;
- }
- }
- facecopy(em, efa,hold);
- }
-}
-
-static void fill_quad_double_op(EditMesh *em, 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;
-
- v[0] = efa->v1;
- v[1] = efa->v2;
- v[2] = efa->v3;
- 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;}
-
- // 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]);
- //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);}
- /* end = (start+1)%4; */ /* UNUSED */
- left = (start+2)%4;
- /* right = (start+3)%4; */ /* UNUSED */
- if(verts[1][0] != v[left]) {flipvertarray(verts[1],numcuts+2);}
- /*
- We should have something like this now
-
- 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);
- if(i < vertsize-2) {
- hold->e2->f2 |= EDGEINNER;
- hold->e2->f2 |= DOUBLEOPFILL;
- }
- facecopy(em, efa,hold);
- }
-}
-
-static void fill_quad_double_adj_path(EditMesh *em, 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;
-
- 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;}
- if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3;}
- if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0;}
-
- // 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]);
- //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);}
- /*
- We should have something like this now
-
- end start
- 3 2 1 0
- start2 0|---*---*---|
- | |
- 1* |
- | |
- 2* |
- | |
- 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);
- /* when ctrl is depressed, only want verts on the cutline selected */
- if (ctrl)
- 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);
- /* 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) {
- // 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->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- }
- //EM_fgon_flags(em);
-
-}
-
-static void fill_quad_double_adj_fan(EditMesh *em, 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, */ /* UNUSED */ i;
-
- v[0] = efa->v1;
- v[1] = efa->v2;
- v[2] = efa->v3;
- 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]);
- //This is the index size of the verts array
- /* vertsize = numcuts+2; */ /* UNUSED */
-
- // 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);}
- /*
- We should have something like this now
-
- end start
- 3 2 1 0
- start2 0|---*---*---|
- | |
- 1* |
- | |
- 2* |
- | |
- 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->e1->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
-
- hold = addfacelist(em, op,verts[0][i],verts[0][i+1],NULL,NULL,NULL);
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- }
-}
-
-static void fill_quad_double_adj_inner(EditMesh *em, 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, */ /* UNUSED */ i;
- float co[3];
-
- v[0] = efa->v1;
- v[1] = efa->v2;
- v[2] = efa->v3;
- 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]);
- //This is the index size of the verts array
- /* vertsize = numcuts+2; */ /* UNUSED */
-
- // 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);}
- /*
- We should have something like this now
-
- end start
- 3 2 1 0
- start2 0|---*---*---|
- | |
- 1* |
- | |
- 2* |
- | |
- end2 3|-----------|op
-
- We will fill this case like this or this (warning horrible ascii art follows)
- |---*-----*---|
- | * / |
- * \ / |
- | * |
- | / \ |
- * \ |
- | \ |
- |-------------|
- */
-
- // 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]->f2 |= EDGEINNER;
-
- EM_data_interp_from_verts(em, 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->e2->f2 |= EDGEINNER;
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- // Add Bottom Quads
- hold = addfacelist(em, verts[0][0],verts[0][1],inner[numcuts-1],op,NULL,NULL);
- hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
-
- hold = addfacelist(em, 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) {
- // 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->e1->f2 |= EDGEINNER;
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
-
- hold = addfacelist(em, 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) {
- // hold->e1->h |= EM_FGON;
- //}
- }
-
- //EM_fgon_flags(em);
-
- MEM_freeN(inner);
-}
-
-static void fill_tri_double(EditMesh *em, 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;
-
- 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;}
- if(efa->e3->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e1; start = 2; start2 = 0;}
-
- // 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]);
- //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);}
- /*
- We should have something like this now
-
- end start
- 3 2 1 0
- start2 0|---*---*---|
- | /
- 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->e3->f2 |= EDGEINNER;
- facecopy(em, 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->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- }
-}
-
-static void fill_quad_triple(EditMesh *em, 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;
-
- if(!(efa->e1->f & SELECT)) {
- cedge[0] = efa->e2;
- cedge[1] = efa->e3;
- cedge[2] = efa->e4;
- start = 1;start2 = 2;start3 = 3;
- }
- if(!(efa->e2->f & SELECT)) {
- cedge[0] = efa->e3;
- cedge[1] = efa->e4;
- cedge[2] = efa->e1;
- start = 2;start2 = 3;start3 = 0;
- }
- if(!(efa->e3->f & SELECT)) {
- cedge[0] = efa->e4;
- cedge[1] = efa->e1;
- cedge[2] = efa->e2;
- start = 3;start2 = 0;start3 = 1;
- }
- if(!(efa->e4->f & SELECT)) {
- cedge[0] = efa->e1;
- cedge[1] = efa->e2;
- cedge[2] = efa->e3;
- 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);}
- /*
- We should have something like this now
-
- start2
- 3 2 1 0
- start3 0|---*---*---|3
- | |
- 1* *2
- | |
- 2* *1
- | |
- 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 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|
- | / / \ \ |
- |/ 3 / \ 3 \|
- * / \ *
- | / \ |
- | / 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->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- hold = addfacelist(em, verts[1][vertsize-2],verts[1][vertsize-1],verts[2][1],NULL,NULL,NULL);
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, 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->e2->f2 |= EDGEINNER;
- facecopy(em, 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->e2->f2 |= EDGEINNER;
- facecopy(em, 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->e3->f2 |= EDGEINNER;
- //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
- // hold->e3->h |= EM_FGON;
- //}
- facecopy(em, 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);
- hold->e2->f2 |= EDGEINNER;
- //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
- // hold->e2->h |= EM_FGON;
- //}
- facecopy(em, 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->e4->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- }
- // 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);
- } 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->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- }
- //EM_fgon_flags(em);
-}
-
-static void fill_quad_quadruple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, float smooth, float fractal, int beauty)
-{
- EditVert **verts[4], ***innerverts;
- EditFace *hold;
- EditEdge temp;
- short /* vertsize, */ /* UNUSED */ 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);
- verts[2] = BLI_ghash_lookup(gh, efa->e3);
- verts[3] = BLI_ghash_lookup(gh, efa->e4);
-
- //This is the index size of the verts array
- /* vertsize = numcuts+2; */ /* UNUSED */
-
- // 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] != 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[3][0] == efa->v4) {flipvertarray(verts[3],numcuts+2);}
- /*
- We should have something like this now
- 1
-
- 3 2 1 0
- 0|---*---*---|0
- | |
- 1* *1
- 2 | | 4
- 2* *2
- | |
- 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
- | | | |
- 1 0---1---2---3
- | | | |
- 2 0---1---2---3
- | | | |
- 3 0---1---2---3
-
- */
- 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++) {
- float percent= (float)j/(float)(numcuts+1);
-
- innerverts[i][(numcuts+1)-j]= subdivide_edge_addvert(em, &temp, smooth, fractal, 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;
-
- 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);
- }
- }
- // Clean up our dynamic multi-dim array
- for(i=0;i<numcuts+2;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)
-{
- EditVert **verts[3], ***innerverts;
- short /* vertsize, */ /* UNUSED */ i, j;
- EditFace *hold;
- EditEdge temp;
-
- // 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);
- verts[2] = BLI_ghash_lookup(gh, efa->e3);
-
- //This is the index size of the verts array
- /* vertsize = numcuts+2; */ /* UNUSED */
-
- // 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] != 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);}
- /*
- We should have something like this now
- 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
-
- 3
-
- 0 0---1---2---3---4
- | / | / |/ | /
- 1 0---1----2---3
- 1 | / | / | /
- 2 0----1---2 2
- | / | /
- |/ |/
- 3 0---1
- | /
- |/
- 4 0
-
- */
-
- 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);
- }
- }
-
- // Now fill the verts with happy little tris :)
- for(i=0;i<=numcuts+1;i++) {
- 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;
- 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
- 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;
- }
- }
- }
-
- // Clean up our dynamic multi-dim array
- for(i=0;i<numcuts+2;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)
-{
- EditFace *hold;
- /*
- Depending on which two vertices have been knifed through (v1 and v2), we
- triangulate like the patterns below.
- X-------| |-------X
- | \ | | / |
- | \ | | / |
- | \ | | / |
- --------X X--------
- */
-
- if(v1 == 1 && v2 == 3){
- hold= addfacelist(em, 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);
- hold->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
- hold->e1->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
- }
- else{
- hold= addfacelist(em, 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);
- hold->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
- }
-}
-
-static void fill_quad_singlevert(EditMesh *em, EditFace *efa, struct GHash *gh)
-{
- EditEdge *cedge=NULL;
- EditVert *v[4], **verts;
- EditFace *hold;
- short start=0, end, left, right /* , vertsize */ /* UNUSED */;
-
- v[0] = efa->v1;
- v[1] = efa->v2;
- v[2] = efa->v3;
- 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;}
-
- // Point verts to the array of new verts for cedge
- verts = BLI_ghash_lookup(gh, cedge);
- //This is the index size of the verts array
- /* vertsize = 3; */ /* UNUSED */
-
- // 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] != v[start]) {flipvertarray(verts,3);}
- end = (start+1)%4;
- left = (start+2)%4;
- right = (start+3)%4;
-
-/*
- We should have something like this now
-
- 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...
-
- |---*---| |---*---|
- | / | | \ |
- | / | | \ |
- |/ | | \|
- X-------- --------X
-*/
-
- 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->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, 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->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
- hold->e4->f2 |= EDGENEW;
- hold->e1->f2 |= EDGEINNER;
- facecopy(em, 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->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
- hold->e1->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
- //quad is composed of cutvert, end, left, right
- hold = addfacelist(em, 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);
- }
-
-}
-
-// 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)
-{
- 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->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)
-{
- 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
-
- //Set faces f1 to 0 cause we need it later
- for(ef=em->faces.first;ef;ef = ef->next) ef->f1 = 0;
- for(eve=em->verts.first; eve; eve=eve->next) {
- if(!(beauty & B_KNIFE)) /* knife sets this flag for vertex cuts */
- eve->f1 = 0;
- eve->f2 = 0;
- }
-
- for (; md; md=md->next) {
- if ((md->type==eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
- MirrorModifierData *mmd = (MirrorModifierData*) md;
-
- if(mmd->flag & MOD_MIR_CLIPPING) {
- for (eve= em->verts.first; eve; eve= eve->next) {
- eve->f2= 0;
-
- if (mmd->flag & MOD_MIR_AXIS_X && fabsf(eve->co[0]) < mmd->tolerance) eve->f2 |= 1;
- if (mmd->flag & MOD_MIR_AXIS_Y && fabsf(eve->co[1]) < mmd->tolerance) eve->f2 |= 2;
- if (mmd->flag & MOD_MIR_AXIS_Z && fabsf(eve->co[2]) < mmd->tolerance) eve->f2 |= 4;
-
- }
- }
- }
- }
-
- //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->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) {
- for(ef = em->faces.first;ef;ef = ef->next) {
- if(!ef->v4) {
- continue;
- }
- if(ef->f & SELECT) {
- 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);
-
- length[0] = len_v3v3(v1mat, v2mat);
- length[1] = len_v3v3(v2mat, v3mat);
- length[2] = len_v3v3(v3mat, v4mat);
- length[3] = len_v3v3(v4mat, v1mat);
- sort[0] = ef->e1;
- 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;
- } else {
- if(length[hold] < length[i]) {
- hold = i;
- }
- }
- }
- if (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;
- } else {
- if(length[hold] > length[i]) {
- hold = i;
- }
- }
- }
- if (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");
-
- // 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( 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
- for(eed=em->edges.first;eed;eed = eed->next) {
- if(eed->f & flag) {
- templist = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"vertlist");
- templist[0] = eed->v1;
- 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);
- //while we are here, we can copy edge info from the original edge
- cedge = addedgelist(em, 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->f2 = EDGENEW;
- // 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);
- // 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) {
- edgecount = 0;
- facetype = 3;
- if(ef->e1->f & flag) {edgecount++;}
- if(ef->e2->f & flag) {edgecount++;}
- if(ef->e3->f & flag) {edgecount++;}
- if(ef->v4) {
- facetype = 4;
- if(ef->e4->f & flag) {edgecount++;}
- }
- if(facetype == 4) {
- switch(edgecount) {
- case 0:
- if(beauty & B_KNIFE && numcuts == 1){
- /*Test for when knifing through two opposite verts but no edges*/
- touchcount = 0;
- if(ef->v1->f1) touchcount++;
- if(ef->v2->f1) touchcount++;
- if(ef->v3->f1) touchcount++;
- if(ef->v4->f1) touchcount++;
- if(touchcount == 2){
- if(ef->v1->f1 && ef->v3->f1){
- ef->f1 = SELECT;
- fill_quad_doublevert(em, ef, 1, 3);
- }
- else if(ef->v2->f1 && ef->v4->f1){
- ef->f1 = SELECT;
- fill_quad_doublevert(em, ef, 2, 4);
- }
- }
- }
- break;
-
- case 1:
- if(beauty & B_KNIFE && numcuts == 1){
- /*Test for when knifing through an edge and one vert*/
- touchcount = 0;
- if(ef->v1->f1) touchcount++;
- 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);
- }
- else{
- ef->f1 = SELECT;
- fill_quad_single(em, ef, gh, numcuts, seltype);
- }
- }
- else{
- ef->f1 = SELECT;
- fill_quad_single(em, ef, gh, numcuts, seltype);
- }
- }
- else{
- ef->f1 = SELECT;
- fill_quad_single(em, ef, gh, numcuts, seltype);
- }
- 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) ||
- (ef->e2->f & flag && ef->e4->f & flag)) {
- fill_quad_double_op(em, 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;
- }
-
- }
- break;
- case 3: ef->f1 = SELECT;
- fill_quad_triple(em, ef, gh, numcuts);
- break;
- case 4: ef->f1 = SELECT;
- fill_quad_quadruple(em, ef, gh, numcuts, smooth, fractal, beauty);
- break;
- }
- } else {
- switch(edgecount) {
- case 0: break;
- case 1: ef->f1 = SELECT;
- fill_tri_single(em, ef, gh, numcuts, seltype);
- break;
- case 2: ef->f1 = SELECT;
- fill_tri_double(em, ef, gh, numcuts);
- break;
- case 3: ef->f1 = SELECT;
- fill_tri_triple(em, ef, gh, numcuts, smooth, fractal, 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;
- } else {
- eed->f1 = 0;
- }
- }
- free_tagged_edges_faces(em, em->edges.first, em->faces.first);
-
- if(seltype == SUBDIV_SELECT_ORIG && !ctrl) {
- /* 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);
- }
- }
- for(eed = em->edges.first;eed;eed = eed->next) {
- if(eed->f2 & EDGENEW || eed->f2 & EDGEOLD) {
- eed->f |= flag;
- EM_select_edge(eed,1);
- }
- }
- } else if ((seltype == SUBDIV_SELECT_INNER || seltype == SUBDIV_SELECT_INNER_SEL)|| ctrl) {
- for(eed = em->edges.first;eed;eed = eed->next) {
- if(eed->f2 & EDGEINNER) {
- eed->f |= flag;
- 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);
- }
- }
- } else if(seltype == SUBDIV_SELECT_LOOPCUT){
- for(eed = em->edges.first;eed;eed = eed->next) {
- if(eed->f2 & DOUBLEOPFILL){
- eed->f |= flag;
- EM_select_edge(eed,1);
- }else{
- eed->f &= !flag;
- EM_select_edge(eed,0);
- }
- }
- }
- if(em->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){
- ef->e1->h |= 1;
- ef->e2->h |= 1;
- ef->e3->h |= 1;
- if(ef->e4) ef->e4->h |= 1;
- }
- }
- //second pass: unhide edges of visible faces adjacent to hidden faces
- for(ef=em->faces.first; ef; ef=ef->next){
- if(ef->h == 0){
- ef->e1->h &= ~1;
- ef->e2->h &= ~1;
- ef->e3->h &= ~1;
- 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
- // that memory
- BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
-
- EM_selectmode_flush(em);
- 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;
- }
- } else {
- if( (ef->e1->f & SELECT && ef->e2->f & SELECT) && ef->e3->f & SELECT) {
- ef->f |= SELECT;
- }
- }
- }
-
- recalc_editnormals(em);
-}
-
-static int count_selected_edges(EditEdge *ed)
-{
- int totedge = 0;
- while(ed) {
- ed->tmp.p = 0;
- if( ed->f & SELECT ) totedge++;
- ed= ed->next;
- }
- return totedge;
-}
-
-/* hurms, as if this makes code readable! It's pointerpointer hiding... (ton) */
-typedef EditFace *EVPtr;
-typedef EVPtr EVPTuple[2];
-
-/** builds EVPTuple array efaa of face tuples (in fact pointers to EditFaces)
- sharing one edge.
- arguments: selected edge list, face list.
- Edges will also be tagged accordingly (see eed->f2) */
-
-static int collect_quadedges(EVPTuple *efaa, EditEdge *eed, EditFace *efa)
-{
- EditEdge *e1, *e2, *e3;
- EVPtr *evp;
- int i = 0;
-
- /* run through edges, if selected, set pointer edge-> facearray */
- while(eed) {
- eed->f2= 0;
- eed->f1= 0;
- if( eed->f & SELECT ) {
- eed->tmp.p = (EditVert *) (&efaa[i]);
- 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
- */
-
- while(efa) {
- efa->f1= 0;
- if(efa->v4==0 && (efa->f & SELECT)) { /* if selected triangle */
- e1= efa->e1;
- e2= efa->e2;
- e3= efa->e3;
- if(e1->f2<3 && e1->tmp.p) {
- if(e1->f2<2) {
- evp= (EVPtr *) e1->tmp.p;
- evp[(int)e1->f2] = efa;
- }
- e1->f2+= 1;
- }
- if(e2->f2<3 && e2->tmp.p) {
- if(e2->f2<2) {
- evp= (EVPtr *) e2->tmp.p;
- evp[(int)e2->f2]= efa;
- }
- e2->f2+= 1;
- }
- if(e3->f2<3 && e3->tmp.p) {
- if(e3->f2<2) {
- evp= (EVPtr *) e3->tmp.p;
- evp[(int)e3->f2]= efa;
- }
- e3->f2+= 1;
- }
- }
- else {
- /* set to 3 to make sure these are not flipped or joined */
- efa->e1->f2= 3;
- efa->e2->f2= 3;
- efa->e3->f2= 3;
- if (efa->e4) efa->e4->f2= 3;
- }
-
- efa= efa->next;
- }
- return i;
-}
-
-
-/* returns vertices of two adjacent triangles forming a quad
- - can be righthand or lefthand
-
- 4-----3
- |\ |
- | \ 2 | <- efa1
- | \ |
- efa-> | 1 \ |
- | \|
- 1-----2
-
-*/
-#define VTEST(face, num, other) \
- (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)
-{
- if VTEST(efa, 1, efa1) {
- *v1= efa->v1;
- *v2= efa->v2;
- vindex[0]= 0;
- vindex[1]= 1;
- }
- else if VTEST(efa, 2, efa1) {
- *v1= efa->v2;
- *v2= efa->v3;
- vindex[0]= 1;
- vindex[1]= 2;
- }
- else if VTEST(efa, 3, efa1) {
- *v1= efa->v3;
- *v2= efa->v1;
- vindex[0]= 2;
- vindex[1]= 0;
- }
-
- if VTEST(efa1, 1, efa) {
- *v3= efa1->v1;
- *v4= (efa1->v2 == *v2)? efa1->v3: efa1->v2;
- vindex[2]= 0;
- vindex[3]= (efa1->v2 == *v2)? 2: 1;
- }
- else if VTEST(efa1, 2, efa) {
- *v3= efa1->v2;
- *v4= (efa1->v3 == *v2)? efa1->v1: efa1->v3;
- vindex[2]= 1;
- vindex[3]= (efa1->v3 == *v2)? 0: 2;
- }
- else if VTEST(efa1, 3, efa) {
- *v3= efa1->v3;
- *v4= (efa1->v1 == *v2)? efa1->v2: efa1->v1;
- vindex[2]= 2;
- vindex[3]= (efa1->v1 == *v2)? 1: 0;
- }
- else
- *v3= *v4= NULL;
-}
-
-/* Helper functions for edge/quad edit features*/
-static void untag_edges(EditFace *f)
-{
- f->e1->f1 = 0;
- f->e2->f1 = 0;
- f->e3->f1 = 0;
- if (f->e4) f->e4->f1 = 0;
-}
-
-/** remove and free list of tagged edges and faces */
-static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa)
-{
- EditEdge *nexted;
- EditFace *nextvl;
-
- while(efa) {
- nextvl= efa->next;
- if(efa->f1) {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- else
- /* avoid deleting edges that are still in use */
- untag_edges(efa);
- efa= nextvl;
- }
-
- while(eed) {
- nexted= eed->next;
- if(eed->f1) {
- remedge(em, eed);
- free_editedge(em, eed);
- }
- eed= nexted;
- }
-}
-
-
-/* ******************** BEGIN TRIANGLE TO QUAD ************************************* */
-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 = RAD2DEGF(angle_v3v3(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 = RAD2DEGF(angle_v3v3(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 = (
- fabsf(RAD2DEGF(angle_v3v3(edgeVec1, edgeVec2)) - 90) +
- fabsf(RAD2DEGF(angle_v3v3(edgeVec2, edgeVec3)) - 90) +
- fabsf(RAD2DEGF(angle_v3v3(edgeVec3, edgeVec4)) - 90) +
- fabsf(RAD2DEGF(angle_v3v3(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));
-
- return measure;
-}
-
-#define T2QUV_LIMIT 0.005f
-#define T2QCOL_LIMIT 3
-static int compareFaceAttribs(EditMesh *em, EditFace *f1, EditFace *f2, EditEdge *eed)
-{
- /*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);
-
- /*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{
- for(i = 0; i < 2; i++){
- if(tf1->uv[fe1[i]][0] + T2QUV_LIMIT > tf2->uv[fe2[i]][0] && tf1->uv[fe1[i]][0] - T2QUV_LIMIT < tf2->uv[fe2[i]][0] &&
- tf1->uv[fe1[i]][1] + T2QUV_LIMIT > tf2->uv[fe2[i]][1] && tf1->uv[fe1[i]][1] - T2QUV_LIMIT < tf2->uv[fe2[i]][1]) attrok |= B_JOINTRIA_UV;
- }
- }
- }
-
- /*do VCOLs*/
- if(flag & B_JOINTRIA_VCOL){
- if(!col1 || !col2) attrok |= B_JOINTRIA_VCOL;
- else{
- char *f1vcol, *f2vcol;
- 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] &&
- f1vcol[3] + T2QCOL_LIMIT > f2vcol[3] && f1vcol[3] - T2QCOL_LIMIT < f2vcol[3]) attrok |= B_JOINTRIA_VCOL;
- }
- }
- }
-
- 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;
-}
-
-/*Bitflags for edges.*/
-#define T2QDELETE 1
-#define T2QCOMPLEX 2
-#define T2QJOIN 4
-void join_triangles(EditMesh *em)
-{
- EditVert *v1, *v2, *v3, *v4, *eve;
- EditEdge *eed, **edsortblock = NULL, **edb = NULL;
- EditFace *efa;
- EVPTuple *efaar = NULL;
- EVPtr *efaa = NULL;
- float *creases = NULL;
- float measure; /*Used to set tolerance*/
- float limit = 0.8f; // XXX scene->toolsettings->jointrilimit;
- int i, ok, totedge=0, totseledge=0, complexedges, vindex[4];
-
- /*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");
- for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++){
- 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;
- for(efa=em->faces.first; efa; efa=efa->next) efa->f1 = efa->tmp.l = 0;
-
- /*For every selected 2 manifold edge, create pointers to its two faces.*/
- 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.*/
- 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 */
- if(eed->f2 == 2){
- efaa= (EVPtr *) eed->tmp.p;
- efaa[0]->tmp.l++;
- efaa[1]->tmp.l++;
- }
- }
-
- for(eed=em->edges.first; eed; eed=eed->next){
- if(eed->f2 == 2){
- 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){
- /*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
- }
- 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{
- 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");
- for(eed = em->edges.first; eed; eed=eed->next){
- if(eed->f1 & T2QCOMPLEX){
- *edb = eed;
- edb++;
- }
- }
- 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++){
- efaa = (EVPtr *)((*edb)->tmp.p); /*suspect!*/
- if( !efaa[0]->f1 && !efaa[1]->f1){
- efaa[0]->f1 = 1; //mark for join
- efaa[1]->f1 = 1; //mark for join
- (*edb)->f1 |= T2QJOIN;
- }
- }
- }
-
- /*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.*/
- /*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]);
- EM_select_face(efa,1);
- }
- else{
- efaa[0]->f1 = 0;
- efaa[1]->f1 = 0;
- }
- }
- }
- }
-
- /*free data and cleanup*/
- if(creases){
- 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);
- if(efaar) MEM_freeN(efaar);
- if(edsortblock) MEM_freeN(edsortblock);
-
- EM_selectmode_flush(em);
-
-}
-/* ******************** 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)
-{
- EditVert *v1, *v2, *v3, *v4;
- EditEdge *eed, *nexted;
- EditFace *efa, *w;
- //void **efaar, **efaa;
- 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
- * - test edge: flip?
- - 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
-
- totedge = count_selected_edges(em->edges.first);
- if(totedge==0) return;
-
- /* temporary array for : edge -> face[1], face[2] */
- 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;
- efa= efaa[0];
- 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);
-
-/*
- 4-----3 4-----3
- |\ | | /|
- | \ 1 | | 1 / |
- | \ | -> | / |
- | 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],
- 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],
- 4+vindex[2], 4+vindex[3], -1);
-
- EM_select_face(w, 1);
- }
- /* tag as to-be-removed */
- FACE_MARKCLEAR(efaa[1]);
- FACE_MARKCLEAR(efaa[0]);
- eed->f1 = 1;
-
- } /* endif test convex */
- }
- }
- }
- eed= nexted;
- }
-
- /* clear tagged edges and faces: */
- free_tagged_edges_faces(em, em->edges.first, em->faces.first);
-
- MEM_freeN(efaar);
-}
-
-#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)
-{
- EditVert **verts[2];
- EditFace *face[2], *efa /* , *newFace[2] */ /* UNUSED */;
- 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) {
- if((efa->e1 == eed || efa->e2 == eed) || (efa->e3 == eed || efa->e4 == eed)) {
- if(facecount >= 2) {
- /* more than two faces with this edge */
- return;
- }
- else {
- face[facecount] = efa;
- facecount++;
- }
- }
- }
-
- if(facecount < 2)
- return;
-
- /* how many edges does each face have */
- 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;
- verts[1]= &face[1]->v1;
- edges[1]= &face[1]->e1;
-
- /* we don't want to rotate edges between faces that share more than one edge */
- numshared= 0;
- for(i=0; i<fac1; i++)
- for(j=0; j<fac2; j++)
- if (edges[0][i] == edges[1][j])
- numshared++;
-
- if(numshared > 1)
- 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
- - then we make sure they are ordered according to the face vertex order
- - and then we construct the array */
- p1= p2= p3= p4= 0;
-
- for(i=0; i<4; i++) {
- if(eed->v1 == verts[0][i]) p1 = i;
- if(eed->v2 == verts[0][i]) p2 = i;
- 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;
- }
-
- /* create an Array of the Edges who have h set prior to rotate */
- numhidden = 0;
- for(srchedge = em->edges.first;srchedge;srchedge = srchedge->next)
- if(srchedge->h && ((srchedge->v1->f & SELECT) || (srchedge->v2->f & SELECT)))
- numhidden++;
-
- hiddenedges = MEM_mallocN(sizeof(EditVert*)*numhidden+1, "RotateEdgeHiddenVerts");
- if(!hiddenedges) {
- BKE_report(op->reports, RPT_ERROR, "Memory allocation failed");
- return;
- }
-
- 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;
-
- /* create the 2 new faces */
- if(fac1 == 3 && fac2 == 3) {
- /* no need of reverse setup */
-
- /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1);
- /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, 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]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]);
- /* newFace[1]= */ /* UNUSED */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]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][2], 4+p[1][1], p[0][0], p[0][1]);
- /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, 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;
- }
- }
- else if(fac1 == 3 && fac2 == 4) {
- if(dir == DIRECTION_CCW) {
- /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1);
- /* newFace[1]= */ /* UNUSED */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]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][0], p[0][1], 4+p[1][2], -1);
- /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, 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;
- }
-
- }
- else if(fac1 == 4 && fac2 == 4) {
- if(dir == DIRECTION_CCW) {
- /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]);
- /* newFace[1]= */ /* UNUSED */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]= */ /* UNUSED */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]= */ /* UNUSED */EM_face_from_faces(em, 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;
- }
- }
- else
- return; /* This should never happen */
-
- if(dir == DIRECTION_CCW || (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)) {
- srchedge->f = eed->f;
- srchedge->h = eed->h;
- srchedge->dir = eed->dir;
- srchedge->seam = eed->seam;
- srchedge->freestyle = eed->freestyle;
- srchedge->crease = eed->crease;
- 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;
-
- /* cleanup */
- MEM_freeN(hiddenedges);
-
- /* get rid of the old edge and faces*/
- remedge(em, eed);
- free_editedge(em, eed);
- BLI_remlink(&em->faces, face[0]);
- free_editface(em, face[0]);
- BLI_remlink(&em->faces, face[1]);
- free_editface(em, face[1]);
-}
-
-/* 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);
- 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) {
- eed->f1= 0;
- eed->f2 &= ~2;
- if(eed->f & SELECT) edgeCount++;
- }
-
- if(edgeCount>1) {
- /* more selected edges, check faces */
- 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++;
- }
- }
- edgeCount= 0;
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f1==2) edgeCount++;
- }
- if(edgeCount==1) {
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f1==2) {
- edge_rotate(em, op, 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 if(edgeCount==1) {
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- EM_select_edge(eed, 0);
- edge_rotate(em, op, 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;
- }
-
- /* flush selected vertices (again) to edges/faces */
- EM_select_flush(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_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 the edge around");
-}
-
-
-/******************* BEVEL CODE STARTS HERE ********************/
-
- /* XXX old bevel not ported yet */
-
-static void UNUSED_FUNCTION(bevel_menu)(EditMesh *em)
-{
- BME_Mesh *bm;
- BME_TransData_Head *td;
-// TransInfo *t;
- int options, res, gbm_free = 0;
-
-// t = BIF_GetTransInfo();
- if (!G.editBMesh) {
- G.editBMesh = MEM_callocN(sizeof(*(G.editBMesh)),"bevel_menu() G.editBMesh");
- gbm_free = 1;
- }
-
- G.editBMesh->options = BME_BEVEL_RUNNING | BME_BEVEL_SELECT;
- G.editBMesh->res = 1;
-
- 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);
- BME_bevel(bm,0.1f,res,options,0,0,&td);
- BME_bmesh_to_editmesh(bm, td, em);
- EM_selectmode_flush(em);
- G.editBMesh->bm = bm;
- G.editBMesh->td = td;
-// initTransform(TFM_BEVEL,CTX_BMESH);
-// Transform();
- BME_free_transdata(td);
- BME_free_mesh(bm);
-// if (t->state != TRANS_CONFIRM) {
-// BIF_undo();
-// }
- if (options == G.editBMesh->options) {
- G.editBMesh->options &= ~BME_BEVEL_RUNNING;
- }
- }
-
- if (gbm_free) {
- MEM_freeN(G.editBMesh);
- G.editBMesh = NULL;
- }
-}
-
-
-/* *********** 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)
-{
- EditFace *search=NULL;
-
- search = em->faces.first;
- if (e1 == e2){
- return 0 ;
- }
- 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;
- }
- return 0;
-}
-
-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;
- }
-
- /* 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;
-}
-
-
-/* -------------------- More tools ------------------ */
-#if 0
-void mesh_set_face_flags(EditMesh *em, short mode)
-{
- EditFace *efa;
- MTFace *tface;
- short m_tex=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;
-// }
-
- add_numbut(0, TOG|SHO, "Texture", 0, 0, &m_tex, 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);
- add_numbut(5, TOG|SHO, "Shared", 0, 0, &m_shared, NULL);
- add_numbut(6, TOG|SHO, "Twoside", 0, 0, &m_twoside, NULL);
- add_numbut(7, TOG|SHO, "ObColor", 0, 0, &m_obcolor, NULL);
- add_numbut(8, TOG|SHO, "Halo", 0, 0, &m_halo, NULL);
- add_numbut(9, TOG|SHO, "Billboard", 0, 0, &m_billboard, NULL);
- 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;
-
- /* 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_shared) flag |= TF_SHAREDCOL;
- if (m_light) flag |= TF_LIGHT;
- if (m_invis) flag |= TF_INVISIBLE;
- if (m_collision) flag |= TF_DYNAMIC;
- if (m_twoside) flag |= TF_TWOSIDE;
- if (m_obcolor) flag |= TF_OBCOL;
- if (m_halo) flag |= TF_BILLBOARD;
- if (m_billboard) flag |= TF_BILLBOARD2;
- 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) {
- tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if (mode) tface->mode |= flag;
- else tface->mode &= ~flag;
- change = 1;
- }
- efa= efa->next;
- }
-
-}
-#endif
-
-/********************** Rip Operator *************************/
-
-/* helper to find edge for edge_rip */
-static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *co2, const int mval[2])
-{
- float vec1[2], vec2[2], mvalf[2];
-
- ED_view3d_project_float(ar, co1, vec1, mat);
- ED_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);
-}
-
-/* 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);
-
-}
-
-/* based on mouse cursor position, it defines how is being ripped */
-static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
- 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;
- int *mval= event->mval;
-
- /* select flush... vertices are important */
- EM_selectmode_set(em);
-
- ED_view3d_ob_project_mat_get(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;
- ED_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_WARNING, "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_WARNING, "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_WARNING, "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, 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", FALSE);
-// 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;
-
- /* to give to transform */
- /* XXX Transform this in a macro */
- Transform_Properties(ot, P_CONSTRAINT|P_MIRROR);
-}
-
-
-/************************ Shape Operators *************************/
-
-static void shape_propagate(Object *obedit, EditMesh *em, wmOperator *op)
-{
- EditVert *ev = NULL;
- Mesh* me = (Mesh*)obedit->data;
- Key* ky = NULL;
- KeyBlock* kb = NULL;
-
-
- if(me->key){
- ky = me->key;
- } else {
- BKE_report(op->reports, RPT_WARNING, "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);
- }
- }
- }
- } else {
- BKE_report(op->reports, RPT_WARNING, "Object Has No Blendshapes");
- return;
- }
-
-#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, 0);
- return;
-}
-
-
-static int shape_propagate_to_all_exec(bContext *C, wmOperator *op)
-{
- 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;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-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, *refkb= NULL;
- float *data, *refdata= NULL, co[3];
- float blend= RNA_float_get(op->ptr, "blend");
- int shape= RNA_enum_get(op->ptr, "shape");
- int add= RNA_boolean_get(op->ptr, "add");
- int blended= 0;
-
- if(key && (kb= BLI_findlink(&key->block, shape))) {
- data= kb->data;
-
- if(add) {
- refkb= BLI_findlink(&key->block, kb->relative);
- if(refkb)
- refdata = refkb->data;
- }
-
- for(eve=em->verts.first; eve; eve=eve->next){
- if(eve->f & SELECT) {
- if(eve->keyindex >= 0 && eve->keyindex < kb->totelem) {
- copy_v3_v3(co, data + eve->keyindex*3);
-
- if(add) {
- /* in add mode, we add relative shape key offset */
- if(refdata && eve->keyindex < refkb->totelem)
- sub_v3_v3v3(co, co, refdata + eve->keyindex*3);
-
- madd_v3_v3fl(eve->co, co, blend);
- }
- else {
- /* in blend mode, we interpolate to the shape key */
- interp_v3_v3v3(eve->co, eve->co, co, blend);
- }
-
- blended= 1;
- }
- }
- }
- }
-
- 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), PropertyRNA *UNUSED(prop), 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);
- }
- }
- }
- }
-
- 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", 0, "Add", "Add rather than blend between shapes");
-}
-
-/************************ 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.*/
-/* This whole tool needs to be redone, its rather poorly implemented...*/
-
-typedef struct Collection{
- struct Collection *next, *prev;
- int index;
- ListBase collectionbase;
-} Collection;
-
-typedef struct CollectedEdge{
- struct CollectedEdge *next, *prev;
- EditEdge *eed;
-} CollectedEdge;
-
-#define MERGELIMIT 0.000001
-
-static void build_edgecollection(EditMesh *em, 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){
- 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){
- 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){
- 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;
- ebalanced = 0;
- }
- }
- }
- }
-
- /*3rd pass, set all the edge flags (unnessecary?)*/
- for(eed=em->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){
- if(eed->f&SELECT){
- if(allcollections->first){
- for(edgecollection = allcollections->first; edgecollection; edgecollection=edgecollection->next){
- if(edgecollection->index == eed->tmp.l){
- newedge = MEM_mallocN(sizeof(CollectedEdge), "collected edge");
- newedge->eed = eed;
- BLI_addtail(&(edgecollection->collectionbase), newedge);
- collectionfound = 1;
- break;
- }
- else collectionfound = 0;
- }
- }
- if(allcollections->first == NULL || collectionfound == 0){
- newcollection = MEM_mallocN(sizeof(Collection), "element collection");
- 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
- 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 boundaries 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.
-*/
-typedef struct wUV{
- struct wUV *next, *prev;
- ListBase nodes;
- float u, v; /*cached copy of UV coordinates pointed to by nodes*/
- EditVert *eve;
- int f;
-} wUV;
-
-typedef struct wUVNode{
- struct wUVNode *next, *prev;
- float *u; /*pointer to original tface data*/
- float *v; /*pointer to original tface data*/
-} wUVNode;
-
-typedef struct wUVEdge{
- struct wUVEdge *next, *prev;
- float v1uv[2], v2uv[2]; /*nasty.*/
- struct wUV *v1, *v2; /*oriented same as editedge*/
- EditEdge *eed;
- int f;
-} wUVEdge;
-
-typedef struct wUVEdgeCollect{ /*used for grouping*/
- struct wUVEdgeCollect *next, *prev;
- wUVEdge *uved;
- int id;
-} wUVEdgeCollect;
-
-static void append_weldedUV(EditMesh *em, 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);
-
- 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");
- newnode->u = &(tf->uv[tfindex][0]);
- newnode->v = &(tf->uv[tfindex][1]);
- BLI_addtail(&(curwvert->nodes), newnode);
- found = 1;
- 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)
-{
- 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);
- }
-}
-
-static void append_weldedUVEdge(EditMesh *em, EditFace *efa, EditEdge *eed, ListBase *uvedges)
-{
- wUVEdge *curwedge, *newwedge;
- int v1tfindex, v2tfindex, found;
- MTFace *tf = CustomData_em_get(&em->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;
- else /* if(eed->v2 == efa->v4) */ v2tfindex = 3;
-
- for(curwedge=uvedges->first; curwedge; curwedge=curwedge->next){
- if(curwedge->eed == eed && curwedge->v1uv[0] == tf->uv[v1tfindex][0] && curwedge->v1uv[1] == tf->uv[v1tfindex][1] && curwedge->v2uv[0] == tf->uv[v2tfindex][0] && curwedge->v2uv[1] == tf->uv[v2tfindex][1]){
- found = 1;
- 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];
- newwedge->v1uv[1] = tf->uv[v1tfindex][1];
- 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)
-{
- 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);
- }
-
-
- //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){
- if(curwedge->eed->v1 == curwvert->eve && curwedge->v1uv[0] == curwvert->u && curwedge->v1uv[1] == curwvert->v){
- curwedge->v1 = curwvert;
- break;
- }
- }
- for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){
- if(curwedge->eed->v2 == curwvert->eve && curwedge->v2uv[0] == curwvert->u && curwedge->v2uv[1] == curwvert->v){
- curwedge->v2 = curwvert;
- break;
- }
- }
- }
-}
-
-static void free_weldedUVs(ListBase *uvverts)
-{
- wUV *curwvert;
- for(curwvert = uvverts->first; curwvert; curwvert=curwvert->next) BLI_freelistN(&(curwvert->nodes));
- BLI_freelistN(uvverts);
-}
-
-static void collapse_edgeuvs(EditMesh *em)
-{
- ListBase uvedges, uvverts, allcollections;
- wUVEdge *curwedge;
- wUVNode *curwnode;
- wUVEdgeCollect *collectedwuve, *newcollectedwuve;
- Collection *wuvecollection, *newcollection;
- int curtag, balanced, collectionfound= 0, vcount;
- float avg[2];
-
- if (!EM_texFaceCheck(em))
- return;
-
- uvverts.first = uvverts.last = uvedges.first = uvedges.last = allcollections.first = allcollections.last = NULL;
-
- build_weldedUVs(em, &uvverts);
- build_weldedUVEdges(em, &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;
- for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){
- if(curwedge->v1->f != curwedge->v2->f){
- if(curwedge->v1->f > curwedge->v2->f) curwedge->v1->f = curwedge->v2->f;
- else curwedge->v2->f = curwedge->v1->f;
- balanced = 0;
- }
- }
- }
-
- 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){
- if(wuvecollection->index == curwedge->f){
- newcollectedwuve = MEM_callocN(sizeof(wUVEdgeCollect), "Collected Welded UV Edge");
- newcollectedwuve->uved = curwedge;
- BLI_addtail(&(wuvecollection->collectionbase), newcollectedwuve);
- collectionfound = 1;
- break;
- }
-
- else collectionfound = 0;
- }
- }
- if(allcollections.first == NULL || collectionfound == 0){
- newcollection = MEM_callocN(sizeof(Collection), "element collection");
- 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];
- *(curwnode->v) = avg[1];
- }
- for(curwnode=collectedwuve->uved->v2->nodes.first; curwnode; curwnode=curwnode->next){
- *(curwnode->u) = avg[0];
- *(curwnode->v) = avg[1];
- }
- }
- }
-
- free_weldedUVs(&uvverts);
- BLI_freelistN(&uvedges);
- freecollections(&allcollections);
-}
-
-/*End UV Edge collapse code*/
-
-static void collapseuvs(EditMesh *em, EditVert *mergevert)
-{
- EditFace *efa;
- MTFace *tf;
- int uvcount;
- float uvav[2];
-
- if (!EM_texFaceCheck(em))
- 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);
-
- if(efa->v1->f1 && ELEM(mergevert, NULL, efa->v1)) {
- uvav[0] += tf->uv[0][0];
- uvav[1] += tf->uv[0][1];
- uvcount += 1;
- }
- if(efa->v2->f1 && ELEM(mergevert, NULL, efa->v2)){
- uvav[0] += tf->uv[1][0];
- uvav[1] += tf->uv[1][1];
- uvcount += 1;
- }
- if(efa->v3->f1 && ELEM(mergevert, NULL, efa->v3)){
- uvav[0] += tf->uv[2][0];
- uvav[1] += tf->uv[2][1];
- uvcount += 1;
- }
- if(efa->v4 && efa->v4->f1 && ELEM(mergevert, NULL, efa->v4)){
- uvav[0] += tf->uv[3][0];
- uvav[1] += tf->uv[3][1];
- uvcount += 1;
- }
- }
-
- if(uvcount > 0) {
- 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);
-
- 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][1] = uvav[1];
- }
- if(efa->v3->f1){
- tf->uv[2][0] = uvav[0];
- tf->uv[2][1] = uvav[1];
- }
- if(efa->v4 && efa->v4->f1){
- tf->uv[3][0] = uvav[0];
- tf->uv[3][1] = uvav[1];
- }
- }
- }
-}
-
-static int collapseEdges(EditMesh *em)
-{
- EditVert *eve;
- EditEdge *eed;
-
- ListBase allcollections;
- CollectedEdge *curredge;
- Collection *edgecollection;
-
- int totedges, mergecount,vcount /*, groupcount*/;
- float avgcount[3];
-
- allcollections.first = 0;
- allcollections.last = 0;
-
- mergecount = 0;
-
- build_edgecollection(em, &allcollections);
- /*groupcount = BLI_countlist(&allcollections);*/ /*UNUSED*/
-
-
- 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)) {
- /*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(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);
- }
-
- }
- freecollections(&allcollections);
- removedoublesflag(em, 1, 0, MERGELIMIT);
-
- return mergecount;
-}
-
-static int merge_firstlast(EditMesh *em, int first, int uvmerge)
-{
- EditVert *eve,*mergevert;
- EditSelection *ese;
-
- /* do sanity check in mergemenu in edit.c ?*/
- if(first == 0){
- ese = em->selected.last;
- mergevert= (EditVert*)ese->data;
- }
- else{
- ese = em->selected.first;
- mergevert = (EditVert*)ese->data;
- }
-
- if(mergevert->f&SELECT){
- for (eve=em->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];
-
- 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);
- }
- }
-}
-
-static int merge_target(bContext *C, EditMesh *em, 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(eve->f&SELECT) eve->f1 = 1;
- }
- collapseuvs(em, 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;
- int totvert= em->totvert, totedge= em->totedge, totface= em->totface;
-
- 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 (!(totvert != em->totvert || totedge != em->totedge || totface != em->totface))
- 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), PropertyRNA *UNUSED(prop), 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");
-}
-
-/************************ 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;
-
-#define PATH_SELECT_EDGE_LENGTH 0
-#define PATH_SELECT_TOPOLOGICAL 1
-
-static int select_vertex_path_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
- EditVert *eve, *s, *t;
- EditEdge *eed;
- PathEdge *newpe, *currpe;
- PathNode *currpn;
- PathNode *Q;
- int v, *previous, pathvert, pnindex; /*pnindex redundant?*/
- int unbalanced, totnodes;
- 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;
- }
-
- }
-
- /*need to find out if t is actually reachable by s....*/
- eve->f1 = 0;
- }
-
- if(s != NULL && t != NULL) {
- 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 (type == PATH_SELECT_EDGE_LENGTH) {
- 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 (type == PATH_SELECT_EDGE_LENGTH) {
- 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_WARNING, "Path Selection requires that exactly two vertices be selected");
- return OPERATOR_CANCELLED;
- }
-
- 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)
-{
- 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(!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;
- 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)
-{
- EditEdge *eed;
- EditFace *efa;
- CollectedEdge *curredge;
-
- /*1st test*/
- for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
- curredge->eed->v1->f1 = 0;
- curredge->eed->v2->f1 = 0;
- }
- for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
- curredge->eed->v1->f1++;
- curredge->eed->v2->f1++;
- }
- for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
- 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){
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4) efa->e4->f1++;
- }
- for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
- if(curredge->eed->f1 > 2) return(0);
- }
- return(1);
-}
-
-static int loop_bisect(EditMesh *em, 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(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){
- if(sf2) break;
- else if(sf1){
- if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf2 = efa;
- }
- else{
- 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){
- 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) ){
- balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 1;
- balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 1;
- balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 1;
- if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 1;
- if(balancededges){
- unbalanced = 1;
- efa->f1 = 1;
- totsf1++;
- }
- }
- }
- }
- }
-
- /*do sf2*/
- unbalanced = 1;
- while(unbalanced){
- unbalanced = 0;
- for(efa=em->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) ){
- balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 2;
- balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 2;
- balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 2;
- if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 2;
- if(balancededges){
- unbalanced = 1;
- efa->f1 = 2;
- totsf2++;
- }
- }
- }
- }
- }
-
- if(totsf1 < totsf2) return(1);
- else return(2);
-}
-
-static int loop_to_region(bContext *C, wmOperator *UNUSED(op))
-{
- 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);
-
- 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;
-}
-
-/********************** 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)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- EditFace *efa;
- short change = 0;
- 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;
- }
-
- 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(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 {
- 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;
- }
- else {
- tf->uv[2][0]= u1;
- tf->uv[2][1]= v1;
- }
- }
- 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;
-}
-
-static int mesh_mirror_uvs(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- EditFace *efa;
- short change = 0;
- 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;
- }
-
- 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) {
- 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;
-
- u1= tf->uv[3][0];
- v1= tf->uv[3][1];
-
- 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;
- }
- else {
- 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;
- }
-
- } 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;
-
- u1= tf->uv[3][0];
- v1= tf->uv[3][1];
-
- 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;
- }
- else {
- 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;
- }
- }
- 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;
-}
-
-static int mesh_rotate_colors(bContext *C, wmOperator *op)
-{
- 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 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;
- }
-
- 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(efa->v4) {
- mcol[0]= mcol[3];
- mcol[3]= mcol[2];
- } else {
- mcol[0]= mcol[2];
- }
- mcol[2]= mcol[1];
- mcol[1]= tmpcol;
- } else {
- mcol[0]= mcol[1];
- mcol[1]= mcol[2];
-
- if(efa->v4) {
- mcol[2]= mcol[3];
- mcol[3]= tmpcol;
- }
- else
- mcol[2]= tmpcol;
- }
- 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;
-}
-
-
-static int mesh_mirror_colors(bContext *C, wmOperator *op)
-{
- 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_WARNING, "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, 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);
- EM_select_face(w, 1);
-
-
- w= EM_face_from_faces(em, efaa[0], efaa[1],
- vindex[0], 4+vindex[2], 4+vindex[3], -1);
- EM_select_face(w, 1);
-
- 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);
- EM_select_face(w, 1);
-
- w= EM_face_from_faces(em, efaa[0], efaa[1],
- vindex[0], 4+vindex[1], 4+vindex[3], -1);
- EM_select_face(w, 1);
-
- 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)
- mult_m4_m4m4(mat, rv3d->viewmat, OBACT->obmat); /* 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, "SELECTED", 0, "Selected", "" },
- { 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;
- }
- }
-
- recalc_editnormals(em);
-}
-
-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 || ese->type != EDITVERT) {
- BKE_report(op->reports, RPT_WARNING, "This operator requires an active vertex (last selected)");
- return OPERATOR_CANCELLED;
- }
- else {
- 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");
-}
-
-/********************** Freestyle Face Mark Operator *************************/
-
-static int mesh_mark_freestyle_face_exec(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");
- EditFace *efa;
-
- /* auto-enable Freestyle face mark drawing */
- if(!clear) {
- me->drawflag |= ME_DRAW_FREESTYLE_FACE;
- }
-
- if(!clear) {
- for(efa= em->faces.first; efa; efa=efa->next) {
- if(efa->f & SELECT)
- efa->flag |= ME_FREESTYLE_FACE;
- }
- } else {
- for(efa= em->faces.first; efa; efa=efa->next) {
- if(efa->f & SELECT)
- efa->flag &= ~ME_FREESTYLE_FACE;
- }
- }
-
- 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_freestyle_face(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Mark Freestyle Face";
- ot->description= "(un)mark selected faces for exclusion from Freestyle feature edge detection";
- ot->idname= "MESH_OT_mark_freestyle_face";
-
- /* api callbacks */
- ot->exec= mesh_mark_freestyle_face_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
-}
diff --git a/source/blender/editors/mesh/knifetool.c b/source/blender/editors/mesh/knifetool.c
new file mode 100755
index 00000000000..8e56a357487
--- /dev/null
+++ b/source/blender/editors/mesh/knifetool.c
@@ -0,0 +1,2314 @@
+/*
+ * ***** 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.
+ *
+ *
+ * Contributor(s): Joseph Eagar, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#define _USE_MATH_DEFINES
+
+
+#include "MEM_guardedalloc.h"
+
+
+#include "BLI_blenlib.h"
+#include "BLI_array.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_smallhash.h"
+#include "BLI_scanfill.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h" /* for paint cursor */
+
+
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_view3d.h"
+#include "ED_mesh.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "BKE_tessmesh.h"
+#include "BLI_editVert.h"
+
+#include "mesh_intern.h"
+
+/* this code here is kindof messy. . .I might need to eventually rework it - joeedh */
+
+#define MAXGROUP 30
+#define KMAXDIST 10 /* max mouse distance from edge before not detecting it */
+
+/* knifetool operator */
+typedef struct KnifeVert {
+ BMVert *v; /* non-NULL if this is an original vert */
+ ListBase edges;
+
+ float co[3], cageco[3], sco[3]; /* sco is screen coordinates for cageco */
+ short flag, draw, isface, inspace;
+} 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;
+
+typedef struct BMEdgeHit {
+ KnifeEdge *kfe;
+ float hit[3], cagehit[3];
+ float realhit[3]; /* used in midpoint mode */
+ float schit[3];
+ float l; /* lambda along cut line */
+ float perc; /* lambda along hit line */
+ KnifeVert *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], vertcage[3];
+ float prevco[3], prevcage[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;
+ int cut_through;
+ float clipsta, clipend;
+
+ enum {
+ MODE_IDLE,
+ MODE_DRAGGING,
+ MODE_CONNECT,
+ MODE_PANNING
+ } mode;
+
+ int snap_midpoints, prevmode, extend;
+ int ignore_edge_snapping, ignore_vert_snapping;
+ int prevmval[2];
+
+ enum {
+ ANGLE_FREE,
+ ANGLE_0,
+ ANGLE_45,
+ ANGLE_90,
+ ANGLE_135
+ } angle_snapping;
+
+ int is_space, prev_is_space; /*1 if current cut location, vertco, isn't on the mesh */
+ float (*cagecos)[3];
+} knifetool_opdata;
+
+static ListBase *knife_get_face_kedges(knifetool_opdata *kcd, BMFace *f);
+
+static void knife_input_ray_cast(knifetool_opdata *kcd, const int mval_i[2],
+ float r_origin[3], float r_ray[3]);
+
+static void knife_project_v3(knifetool_opdata *kcd, const float co[3], float sco[3])
+{
+ ED_view3d_project_float(kcd->ar, co, sco, kcd->projmat);
+}
+
+static ListBase *knife_empty_list(knifetool_opdata *kcd) {
+ ListBase *lst;
+
+ lst = BLI_memarena_alloc(kcd->arena, sizeof(ListBase));
+ lst->first = lst->last = NULL;
+ return lst;
+}
+
+static void knife_append_list(knifetool_opdata *kcd, ListBase *lst, void *elem) {
+ Ref *ref;
+
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = elem;
+ BLI_addtail(lst, ref);
+}
+
+static KnifeEdge *new_knife_edge(knifetool_opdata *kcd)
+{
+ kcd->totkedge++;
+ return BLI_mempool_calloc(kcd->kedges);
+}
+
+static void knife_add_to_vert_edges(knifetool_opdata *kcd, KnifeEdge* kfe)
+{
+ knife_append_list(kcd, &kfe->v1->edges, kfe);
+ knife_append_list(kcd, &kfe->v2->edges, kfe);
+}
+
+static KnifeVert *new_knife_vert(knifetool_opdata *kcd, float *co, float *cageco)
+{
+ KnifeVert *kfv = BLI_mempool_calloc(kcd->kverts);
+
+ kcd->totkvert++;
+
+ copy_v3_v3(kfv->co, co);
+ copy_v3_v3(kfv->cageco, cageco);
+ 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, kcd->cagecos[BM_elem_index_get(v)]);
+ 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) {
+ 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);
+
+ knife_add_to_vert_edges(kcd, kfe);
+
+ BLI_ghash_insert(kcd->origedgemap, e, kfe);
+
+ BM_ITER(f, &iter, kcd->em->bm, BM_FACES_OF_EDGE, e) {
+ knife_append_list(kcd, &kfe->faces, f);
+
+ /* 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++;
+ kcd->prev_is_space = kcd->is_space;
+ kcd->is_space = 0;
+ kcd->prevmval[0] = kcd->vc.mval[0];
+ kcd->prevmval[1] = kcd->vc.mval[1];
+
+ copy_v3_v3(kcd->prevco, kcd->vertco);
+ copy_v3_v3(kcd->prevcage, kcd->vertcage);
+
+ if (kcd->prevvert == NULL && kcd->prevedge == NULL && is_zero_v3(kcd->prevcage)) {
+ /* Make prevcage a point on the view ray to mouse closest to a point on model: choose vertex 0 */
+ float origin[3], ray[3], co[3];
+ BMVert *v0;
+
+ knife_input_ray_cast(kcd, kcd->vc.mval, origin, ray);
+ add_v3_v3v3(co, origin, ray);
+ v0 = BM_vert_at_index(kcd->em->bm, 0);
+ if (v0) {
+ closest_to_line_v3(kcd->prevcage, v0->co, co, origin);
+ copy_v3_v3(kcd->prevco, kcd->prevcage);
+ copy_v3_v3(kcd->vertcage, kcd->prevcage);
+ copy_v3_v3(kcd->vertco, kcd->prevco);
+ }
+ }
+}
+
+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 = knife_empty_list(kcd);
+
+ BM_ITER(e, &iter, kcd->em->bm, BM_EDGES_OF_FACE, f) {
+ knife_append_list(kcd, lst, get_bm_knife_edge(kcd, e));
+ }
+
+ BLI_ghash_insert(kcd->kedgefacemap, f, lst);
+ }
+
+ return lst;
+}
+
+/* finds the proper face to restrict face fill to */
+static 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 void knife_edge_append_face(knifetool_opdata *kcd, KnifeEdge *kfe, BMFace *f)
+{
+ knife_append_list(kcd, knife_get_face_kedges(kcd, f), kfe);
+ knife_append_list(kcd, &kfe->faces, f);
+}
+
+static KnifeVert *knife_split_edge(knifetool_opdata *kcd, KnifeEdge *kfe, float co[3], KnifeEdge **newkfe_out)
+{
+ KnifeEdge *newkfe = new_knife_edge(kcd);
+ Ref *ref;
+ float perc, cageco[3];
+
+ perc = len_v3v3(co, kfe->v1->co) / len_v3v3(kfe->v1->co, kfe->v2->co);
+ interp_v3_v3v3(cageco, kfe->v1->cageco, kfe->v2->cageco, perc);
+
+ newkfe->v1 = kfe->v1;
+ newkfe->v2 = new_knife_vert(kcd, co, cageco);
+ 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)
+ knife_edge_append_face(kcd, newkfe, ref->ref);
+
+ knife_add_to_vert_edges(kcd, newkfe);
+
+ newkfe->draw = kfe->draw;
+ newkfe->e = kfe->e;
+
+ *newkfe_out = newkfe;
+
+ return newkfe->v2;
+}
+
+static void knife_add_single_cut(knifetool_opdata *kcd)
+{
+ KnifeEdge *kfe = new_knife_edge(kcd), *kfe2 = NULL, *kfe3 = NULL;
+
+ if (kcd->prevvert && kcd->prevvert == kcd->curvert)
+ return;
+ if (kcd->prevedge && kcd->prevedge == kcd->curedge)
+ return;
+
+ kfe->draw = 1;
+
+ 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, kcd->prevco);
+ kfe->v1->draw = kfe->draw = !kcd->prev_is_space;
+ kfe->v1->inspace = kcd->prev_is_space;
+ kfe->draw = !kcd->prev_is_space;
+ 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, kcd->vertco);
+ kfe->v2->draw = !kcd->is_space;
+ kfe->v2->isface = 1;
+ kfe->v2->inspace = kcd->is_space;
+
+ if (kcd->is_space)
+ kfe->draw = 0;
+
+ kcd->curvert = kfe->v2;
+ }
+
+ knife_find_basef(kcd, kfe);
+
+ knife_add_to_vert_edges(kcd, kfe);
+
+ 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);
+ copy_v3_v3(kcd->prevcage, kcd->vertcage);
+ kcd->prev_is_space = kcd->is_space;
+ kcd->prevmval[0] = kcd->vc.mval[0];
+ kcd->prevmval[1] = kcd->vc.mval[1];
+}
+
+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_single_cut_through(knifetool_opdata *kcd,
+ KnifeVert *v1, KnifeVert *v2, BMFace *f)
+{
+ KnifeEdge *kfenew;
+
+ kfenew = new_knife_edge(kcd);
+ kfenew->draw = 1;
+ kfenew->basef = f;
+ kfenew->v1 = v1;
+ kfenew->v2 = v2;
+ kfenew->draw = 1;
+
+ knife_add_to_vert_edges(kcd, kfenew);
+
+ if (!find_ref(&kfenew->faces, f))
+ knife_edge_append_face(kcd, kfenew, f);
+}
+
+static void knife_get_vert_faces(knifetool_opdata *kcd, KnifeVert* kfv, BMFace *facef, ListBase *lst)
+{
+ BMIter bmiter;
+ BMFace *f;
+
+ if (kfv->isface && facef) {
+ knife_append_list(kcd, lst, facef);
+ }
+ else if (kfv->v) {
+ BMesh *bm = kcd->em->bm;
+ BM_ITER(f, &bmiter, bm, BM_FACES_OF_VERT, kfv->v) {
+ knife_append_list(kcd, lst, f);
+ }
+ }
+}
+
+static void knife_get_edge_faces(knifetool_opdata *kcd, KnifeEdge* kfe, ListBase *lst)
+{
+ BMIter bmiter;
+ BMFace *f;
+
+ if (kfe->e) {
+ BMesh *bm = kcd->em->bm;
+ BM_ITER(f, &bmiter, bm, BM_FACES_OF_EDGE, kfe->e) {
+ knife_append_list(kcd, lst, f);
+ }
+ }
+}
+
+/* BMESH_TODO: add more functionality to cut-through:
+ * - cutting "in face" (e.g., holes) should cut in all faces, not just visible one
+ * - perhaps improve O(n^2) algorithm used here */
+static void knife_cut_through(knifetool_opdata *kcd)
+{
+ BMEdgeHit *lh, *lh2;
+ BMFace *f;
+ KnifeEdge *kfe, *kfe2, *kfe3;
+ KnifeVert *v1, *v2, *firstv = NULL, *lastv = NULL;
+ ListBase firstfaces = {NULL, NULL}, lastfaces = { NULL, NULL};
+ Ref *r, *r2;
+ KnifeEdge **splitkfe;
+ int i, j, found;
+
+ if (!kcd->totlinehit) {
+ /* if no linehits then no interesting back face stuff to do */
+ knife_add_single_cut(kcd);
+ return;
+ }
+
+ qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit);
+ splitkfe = MEM_callocN(kcd->totlinehit * sizeof(KnifeEdge *), "knife_cut_through");
+
+ if (kcd->prevvert) {
+ if (kcd->prevvert == kcd->curvert)
+ return;
+ firstv = kcd->prevvert;
+ knife_get_vert_faces(kcd, firstv, kcd->prevbmface, &firstfaces);
+ }
+ else if (kcd->prevedge) {
+ if (kcd->prevedge == kcd->curedge)
+ return;
+ firstv = knife_split_edge(kcd, kcd->prevedge, kcd->prevco, &kfe3);
+ knife_get_edge_faces(kcd, kcd->prevedge, &firstfaces);
+ }
+
+ if (kcd->curvert) {
+ lastv = kcd->curvert;
+ knife_get_vert_faces(kcd, lastv, kcd->curbmface, &lastfaces);
+ }
+ else if (kcd->curedge) {
+ lastv = knife_split_edge(kcd, kcd->curedge, kcd->vertco, &kfe3);
+ knife_get_edge_faces(kcd, kcd->curedge, &lastfaces);
+ }
+
+ if (firstv) {
+ /* For each face incident to firstv,
+ * find the first following linehit (if any) sharing that face and connect */
+ for (r = firstfaces.first; r; r = r->next ) {
+ f = r->ref;
+ found = 0;
+ for (j = 0, lh2 = kcd->linehits; j < kcd->totlinehit; j++, lh2++) {
+ kfe2 = lh2->kfe;
+ for (r2 = kfe2->faces.first; r2; r2 = r2->next) {
+ if (r2->ref == f) {
+ v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]);
+ knife_add_single_cut_through(kcd, firstv, v2, f);
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found && lastv) {
+ for (r2 = lastfaces.first; r2; r2 = r2->next) {
+ if (r2->ref == f) {
+ knife_add_single_cut_through(kcd, firstv, lastv, f);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ for (i = 0, lh = kcd->linehits; i < kcd->totlinehit; i++, lh++) {
+ kfe = lh->kfe;
+
+ /* For each face attached to edge for this linehit,
+ * find the first following linehit (if any) sharing that face and connect */
+ for (r = kfe->faces.first; r; r = r->next) {
+ f = r->ref;
+ found = 0;
+ for (j = i + 1, lh2 = lh + 1; j < kcd->totlinehit; j++, lh2++) {
+ kfe2 = lh2->kfe;
+ for (r2 = kfe2->faces.first; r2; r2 = r2->next) {
+ if (r2->ref == f) {
+ v1 = splitkfe[i]? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]);
+ v2 = splitkfe[j]? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]);
+ knife_add_single_cut_through(kcd, v1, v2, f);
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found && lastv) {
+ for (r2 = lastfaces.first; r2; r2 = r2->next) {
+ if (r2->ref == f) {
+ v1 = splitkfe[i]? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]);
+ knife_add_single_cut_through(kcd, v1, lastv, f);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ MEM_freeN(splitkfe);
+ MEM_freeN(kcd->linehits);
+ kcd->linehits = NULL;
+ kcd->totlinehit = 0;
+
+ /* set up for next cut */
+ kcd->prevbmface = kcd->curbmface;
+ kcd->prevvert = kcd->curvert;
+ kcd->prevedge = kcd->curedge;
+ copy_v3_v3(kcd->prevco, kcd->vertco);
+ copy_v3_v3(kcd->prevcage, kcd->vertcage);
+ kcd->prev_is_space = kcd->is_space;
+ kcd->prevmval[0] = kcd->vc.mval[0];
+ kcd->prevmval[1] = kcd->vc.mval[1];
+}
+
+static void knife_add_cut(knifetool_opdata *kcd)
+{
+ /* BMEditMesh *em = kcd->em;*/ /* UNUSED */
+ knifetool_opdata oldkcd = *kcd;
+
+ if (kcd->cut_through) {
+ knife_cut_through(kcd);
+ }
+ else 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);
+ copy_v3_v3(kcd->prevcage, firstlh->cagehit);
+ kcd->prevedge = NULL;
+ kcd->prevbmface = f;
+ }
+ lastlh = firstlh = NULL;
+ }
+
+ if (len_v3v3(kcd->prevcage, lh->realhit) < FLT_EPSILON * 80)
+ continue;
+ if (len_v3v3(kcd->vertcage, lh->realhit) < FLT_EPSILON * 80)
+ continue;
+
+ if (kcd->prev_is_space || kcd->is_space) {
+ kcd->prev_is_space = kcd->is_space = 0;
+ copy_v3_v3(kcd->prevco, lh->hit);
+ copy_v3_v3(kcd->prevcage, lh->cagehit);
+ kcd->prevedge = lh->kfe;
+ kcd->curbmface = lh->f;
+ continue;
+ }
+
+ kcd->is_space = 0;
+ kcd->curedge = lh->kfe;
+ kcd->curbmface = lh->f;
+ kcd->curvert = lh->v;
+ copy_v3_v3(kcd->vertco, lh->hit);
+ copy_v3_v3(kcd->vertcage, lh->cagehit);
+
+ knife_add_single_cut(kcd);
+ }
+
+ kcd->curbmface = oldkcd.curbmface;
+ kcd->curvert = oldkcd.curvert;
+ kcd->curedge = oldkcd.curedge;
+ kcd->is_space = oldkcd.is_space;
+ copy_v3_v3(kcd->vertco, oldkcd.vertco);
+ copy_v3_v3(kcd->vertcage, oldkcd.vertcage);
+
+ 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 *UNUSED(kcd))
+{
+
+}
+
+static void knifetool_draw_angle_snapping(knifetool_opdata *kcd)
+{
+ bglMats mats;
+ double u[3], u1[2], u2[2], v1[3], v2[3], dx, dy;
+ double wminx, wminy, wmaxx, wmaxy;
+
+ /* make u the window coords of prevcage */
+ view3d_get_transformation(kcd->ar, kcd->vc.rv3d, kcd->ob, &mats);
+ gluProject(kcd->prevcage[0], kcd->prevcage[1], kcd->prevcage[2],
+ mats.modelview, mats.projection, mats.viewport,
+ &u[0], &u[1], &u[2]);
+
+ /* make u1, u2 the points on window going through u at snap angle */
+ wminx = kcd->ar->winrct.xmin;
+ wmaxx = kcd->ar->winrct.xmin + kcd->ar->winx;
+ wminy = kcd->ar->winrct.ymin;
+ wmaxy = kcd->ar->winrct.ymin + kcd->ar->winy;
+
+ switch (kcd->angle_snapping) {
+ case ANGLE_0:
+ u1[0] = wminx;
+ u2[0] = wmaxx;
+ u1[1] = u2[1] = u[1];
+ break;
+ case ANGLE_90:
+ u1[0] = u2[0] = u[0];
+ u1[1] = wminy;
+ u2[1] = wmaxy;
+ break;
+ case ANGLE_45:
+ /* clip against left or bottom */
+ dx = u[0] - wminx;
+ dy = u[1] - wminy;
+ if (dy > dx) {
+ u1[0] = wminx;
+ u1[1] = u[1] - dx;
+ }
+ else {
+ u1[0] = u[0] - dy;
+ u1[1] = wminy;
+ }
+ /* clip against right or top */
+ dx = wmaxx - u[0];
+ dy = wmaxy - u[1];
+ if (dy > dx) {
+ u2[0] = wmaxx;
+ u2[1] = u[1] + dx;
+ }
+ else {
+ u2[0] = u[0] + dy;
+ u2[1] = wmaxy;
+ }
+ break;
+ case ANGLE_135:
+ /* clip against right or bottom */
+ dx = wmaxx - u[0];
+ dy = u[1] - wminy;
+ if (dy > dx) {
+ u1[0] = wmaxx;
+ u1[1] = u[1] - dx;
+ }
+ else {
+ u1[0] = u[0] + dy;
+ u1[1] = wminy;
+ }
+ /* clip against left or top */
+ dx = u[0] - wminx;
+ dy = wmaxy - u[1];
+ if (dy > dx) {
+ u2[0] = wminx;
+ u2[1] = u[1] + dx;
+ }
+ else {
+ u2[0] = u[0] - dy;
+ u2[1] = wmaxy;
+ }
+ break;
+ default:
+ return;
+ }
+
+ /* unproject u1 and u2 back into object space */
+ gluUnProject(u1[0], u1[1], 0.0,
+ mats.modelview, mats.projection, mats.viewport,
+ &v1[0], &v1[1], &v1[2]);
+ gluUnProject(u2[0], u2[1], 0.0,
+ mats.modelview, mats.projection, mats.viewport,
+ &v2[0], &v2[1], &v2[2]);
+
+ glColor3f(0.6, 0.6, 0.6);
+ glLineWidth(2.0);
+ glBegin(GL_LINES);
+ glVertex3dv(v1);
+ glVertex3dv(v2);
+ glEnd();
+}
+
+/* modal loop selection drawing callback */
+static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+{
+ knifetool_opdata *kcd = arg;
+
+ glDisable(GL_DEPTH_TEST);
+
+ glPolygonOffset(1.0f, 1.0f);
+
+ glPushMatrix();
+ glMultMatrixf(kcd->ob->obmat);
+
+ if (kcd->mode == MODE_DRAGGING) {
+ if (kcd->angle_snapping != ANGLE_FREE)
+ knifetool_draw_angle_snapping(kcd);
+
+ glColor3f(0.1, 0.1, 0.1);
+ glLineWidth(2.0);
+
+ glBegin(GL_LINES);
+ glVertex3fv(kcd->prevcage);
+ glVertex3fv(kcd->vertcage);
+ glEnd();
+
+ glLineWidth(1.0);
+ }
+
+ if (kcd->curedge) {
+ glColor3f(0.5, 0.3, 0.15);
+ glLineWidth(2.0);
+
+ glBegin(GL_LINES);
+ glVertex3fv(kcd->curedge->v1->cageco);
+ glVertex3fv(kcd->curedge->v2->cageco);
+ glEnd();
+
+ glLineWidth(1.0);
+ }
+ else if (kcd->curvert) {
+ glColor3f(0.8, 0.2, 0.1);
+ glPointSize(11);
+
+ glBegin(GL_POINTS);
+ glVertex3fv(kcd->vertcage);
+ glEnd();
+ }
+
+ if (kcd->curbmface) {
+ glColor3f(0.1, 0.8, 0.05);
+ glPointSize(9);
+
+ glBegin(GL_POINTS);
+ glVertex3fv(kcd->vertcage);
+ 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(11);
+ 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->cageco, sv1);
+ knife_project_v3(kcd, lh->kfe->v2->cageco, sv2);
+ knife_project_v3(kcd, lh->cagehit, lh->schit);
+
+ if (len_v2v2(lh->schit, sv1) < kcd->vthresh / 4.0f) {
+ copy_v3_v3(lh->cagehit, lh->kfe->v1->cageco);
+ glVertex3fv(lh->cagehit);
+ lh->v = lh->kfe->v1;
+ }
+ else if (len_v2v2(lh->schit, sv2) < kcd->vthresh / 4.0f) {
+ copy_v3_v3(lh->cagehit, lh->kfe->v2->cageco);
+ glVertex3fv(lh->cagehit);
+ lh->v = lh->kfe->v2;
+ }
+ }
+ glEnd();
+
+ /* now draw the rest */
+ glColor4f(0.1, 0.8, 0.05, 0.4);
+ glPointSize(7);
+ glBegin(GL_POINTS);
+ lh = kcd->linehits;
+ for (i = 0; i < kcd->totlinehit; i++, lh++) {
+ glVertex3fv(lh->cagehit);
+ }
+ 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->cageco);
+ glVertex3fv(kfe->v2->cageco);
+ }
+
+ glEnd();
+ glLineWidth(1.0);
+ }
+
+ if (kcd->totkvert > 0) {
+ BLI_mempool_iter iter;
+ KnifeVert *kfv;
+
+ glPointSize(5.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->cageco);
+ }
+
+ glEnd();
+ }
+
+ glPopMatrix();
+ glEnable(GL_DEPTH_TEST);
+}
+
+/* do we need to keep these functions? - campbell */
+
+static int UNUSED_FUNCTION(kfe_vert_in_edge)(KnifeEdge *e, KnifeVert *v)
+{
+ return e->v1 == v || e->v2 == v;
+}
+
+static int UNUSED_FUNCTION(point_on_line)(float p[3], float v1[3], float v2[3])
+{
+ float d = dist_to_line_segment_v3(p, v1, v2);
+ if (d < 0.01) {
+ d = len_v3v3(v1, v2);
+ if (d == 0.0)
+ return 0;
+
+ d = len_v3v3(p, v1) / d;
+
+ if (d >= -FLT_EPSILON * 10 || d <= 1.0 + FLT_EPSILON * 10)
+ return 1;
+ }
+
+ return 0;
+}
+
+static float len_v3_tri_side_max(const float v1[3], const float v2[3], const float v3[3])
+{
+ const float s1 = len_v3v3(v1, v2);
+ const float s2 = len_v3v3(v2, v3);
+ const float s3 = len_v3v3(v3, v1);
+
+ return MAX3(s1, s2, s3);
+}
+
+static BMEdgeHit *knife_edge_tri_isect(knifetool_opdata *kcd, BMBVHTree *bmtree,
+ const float v1[3], const float v2[3], const 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;
+ unsigned int tot = 0;
+ int i, j;
+
+ /* for comparing distances, error of intersection depends on triangle scale.
+ * need to scale down before squaring for accurate comparison */
+ const float depsilon = 50 * FLT_EPSILON * len_v3_tri_side_max(v1, v2, v3);
+ const float depsilon_squared = depsilon * depsilon;
+
+ copy_v3_v3(cos + 0, 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];
+ BMFace *hitf;
+ ListBase *lst = knife_get_face_kedges(kcd, l1->f);
+ Ref *ref;
+
+ for (ref = lst->first; ref; ref = ref->next) {
+ KnifeEdge *kfe = ref->ref;
+
+ //if (kfe == kcd->curedge || kfe == kcd->prevedge)
+ // continue;
+
+ if (isect_line_tri_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3, &lambda, uv)) {
+ float no[3], view[3], sp[3];
+
+ interp_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco, lambda);
+
+ if (kcd->curvert && len_squared_v3v3(kcd->curvert->cageco, p) < depsilon_squared)
+ continue;
+ if (kcd->prevvert && len_squared_v3v3(kcd->prevvert->cageco, p) < depsilon_squared)
+ continue;
+ if ( len_squared_v3v3(kcd->prevcage, p) < depsilon_squared ||
+ len_squared_v3v3(kcd->vertcage, p) < depsilon_squared)
+ {
+ continue;
+ }
+
+ knife_project_v3(kcd, p, sp);
+ view3d_unproject(mats, view, sp[0], sp[1], 0.0f);
+ mul_m4_v3(kcd->ob->imat, view);
+
+ if (kcd->cut_through) {
+ hitf = FALSE;
+ }
+ else {
+ /* check if this point is visible in the viewport */
+ sub_v3_v3(view, p);
+ normalize_v3(view);
+
+ copy_v3_v3(no, view);
+ mul_v3_fl(no, 0.003);
+
+ /* go towards view a bit */
+ add_v3_v3(p, no);
+
+ /* ray cast */
+ hitf = BMBVH_RayCast(bmtree, p, no, NULL, NULL);
+ }
+
+ /* ok, if visible add the new point */
+ if (!hitf && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
+ BMEdgeHit hit;
+
+ if ( len_squared_v3v3(p, kcd->vertco) < depsilon_squared ||
+ len_squared_v3v3(p, kcd->prevco) < depsilon_squared)
+ {
+ continue;
+ }
+
+ hit.kfe = kfe;
+ hit.v = NULL;
+
+ knife_find_basef(kcd, kfe);
+ hit.f = kfe->basef;
+ hit.perc = len_v3v3(p, kfe->v1->cageco) / len_v3v3(kfe->v1->cageco, kfe->v2->cageco);
+ copy_v3_v3(hit.cagehit, p);
+
+ interp_v3_v3v3(p, kfe->v1->co, kfe->v2->co, hit.perc);
+ copy_v3_v3(hit.realhit, p);
+
+ /* BMESH_TODO: should also snap to vertices */
+ if (kcd->snap_midpoints) {
+ float perc = hit.perc;
+
+ /* select the closest from the edge endpoints or the midpoint */
+ if (perc < 0.25f) {
+ perc = 0.0f;
+ }
+ else if (perc < 0.75f) {
+ perc = 0.5f;
+ }
+ else {
+ perc = 1.0f;
+ }
+
+ interp_v3_v3v3(hit.hit, kfe->v1->co, kfe->v2->co, perc);
+ interp_v3_v3v3(hit.cagehit, kfe->v1->cageco, kfe->v2->cageco, perc);
+ }
+ else {
+ copy_v3_v3(hit.hit, p);
+ }
+ knife_project_v3(kcd, hit.cagehit, hit.schit);
+
+ BLI_array_append(edges, hit);
+ BLI_smallhash_insert(ehash, (intptr_t)kfe, NULL);
+ }
+ }
+ }
+ }
+ }
+
+ if (results)
+ MEM_freeN(results);
+
+ BLI_bvhtree_free(tree2);
+ *count = BLI_array_count(edges);
+
+ return edges;
+}
+
+static void knife_bgl_get_mats(knifetool_opdata *UNUSED(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 (or all, if cutting through) 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];
+ int i, c1, c2;
+
+ knife_bgl_get_mats(kcd, &mats);
+
+ if (kcd->linehits) {
+ MEM_freeN(kcd->linehits);
+ kcd->linehits = NULL;
+ kcd->totlinehit = 0;
+ }
+
+ copy_v3_v3(v1, kcd->prevcage);
+ copy_v3_v3(v2, kcd->vertcage);
+
+ /* project screen line's 3d coordinates back into 2d */
+ knife_project_v3(kcd, v1, s1);
+ knife_project_v3(kcd, v2, s2);
+
+ if (len_v2v2(s1, s2) < 1)
+ return;
+
+ /* unproject screen line */
+ ED_view3d_win_to_segment_clip(kcd->ar, kcd->vc.v3d, s1, v1, v3);
+ ED_view3d_win_to_segment_clip(kcd->ar, kcd->vc.v3d, s2, v2, v4);
+
+ 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);
+
+ 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, v2, 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->schit, s1) / len_v2v2(s2, s1);
+ }
+
+ BLI_smallhash_release(ehash);
+}
+
+static void knife_input_ray_cast(knifetool_opdata *kcd, const int mval_i[2],
+ float r_origin[3], float r_ray[3])
+{
+ bglMats mats;
+ float mval[2], imat[3][3];
+
+ knife_bgl_get_mats(kcd, &mats);
+
+ mval[0] = (float)mval_i[0];
+ mval[1] = (float)mval_i[1];
+
+ /* unproject to find view ray */
+ view3d_unproject(&mats, r_origin, mval[0], mval[1], 0.0f);
+
+ if (kcd->is_ortho) {
+ negate_v3_v3(r_ray, kcd->vc.rv3d->viewinv[2]);
+ }
+ else {
+ sub_v3_v3v3(r_ray, r_origin, kcd->vc.rv3d->viewinv[3]);
+ }
+ normalize_v3(r_ray);
+
+ /* transform into object space */
+ invert_m4_m4(kcd->ob->imat, kcd->ob->obmat);
+ copy_m3_m4(imat, kcd->ob->obmat);
+ invert_m3(imat);
+
+ mul_m4_v3(kcd->ob->imat, r_origin);
+ mul_m3_v3(imat, r_ray);
+}
+
+
+static BMFace *knife_find_closest_face(knifetool_opdata *kcd, float co[3], float cageco[3], int *is_space)
+{
+ BMFace *f;
+ int dist = KMAXDIST;
+ float origin[3];
+ float ray[3];
+
+ /* unproject to find view ray */
+ knife_input_ray_cast(kcd, kcd->vc.mval, origin, ray);
+ add_v3_v3v3(co, origin, ray);
+
+ f = BMBVH_RayCast(kcd->bmbvh, origin, ray, co, cageco);
+
+ if (is_space)
+ *is_space = !f;
+
+ 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.
+ * This just puts a point 1.0f infront of the view. */
+ add_v3_v3v3(co, origin, ray);
+ }
+
+ 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;
+ int is_space;
+ float co[3], cageco[3], sco[3];
+
+ f = knife_find_closest_face(kcd, co, cageco, &is_space);
+
+ if (f && !is_space) {
+ ListBase *lst;
+ Ref *ref;
+ float dis;
+ int c = 0;
+
+ knife_project_v3(kcd, cageco, 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->cageco, 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->cageco);
+ mul_m4_v3(kcd->vc.obedit->obmat, vec);
+
+ if (ED_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], float cagep[3], BMFace **fptr, int *is_space)
+{
+ BMFace *f;
+ float co[3], cageco[3], sco[3], maxdist = knife_snap_size(kcd, kcd->ethresh);
+
+ if (kcd->ignore_vert_snapping)
+ maxdist *= 0.5;
+
+ f = knife_find_closest_face(kcd, co, cageco, NULL);
+ *is_space = !f;
+
+ /* set p to co, in case we don't find anything, means a face cut */
+ copy_v3_v3(p, co);
+ copy_v3_v3(cagep, cageco);
+
+ kcd->curbmface = f;
+
+ if (f) {
+ KnifeEdge *cure = NULL;
+ ListBase *lst;
+ Ref *ref;
+ float dis, curdis = FLT_MAX;
+
+ knife_project_v3(kcd, cageco, 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->cageco, kfe->v1->sco);
+ knife_project_v3(kcd, kfe->v2->cageco, 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 = labda_PdistVL2Dfl(sco, kfe->v1->sco, kfe->v2->sco);
+ float vec[3];
+
+ vec[0] = kfe->v1->cageco[0] + labda*(kfe->v2->cageco[0] - kfe->v1->cageco[0]);
+ vec[1] = kfe->v1->cageco[1] + labda*(kfe->v2->cageco[1] - kfe->v1->cageco[1]);
+ vec[2] = kfe->v1->cageco[2] + labda*(kfe->v2->cageco[2] - kfe->v1->cageco[2]);
+ mul_m4_v3(kcd->vc.obedit->obmat, vec);
+
+ if (ED_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) {
+ if (!kcd->ignore_edge_snapping || !(cure->e)) {
+ if (kcd->snap_midpoints) {
+ mid_v3_v3v3(p, cure->v1->co, cure->v2->co);
+ mid_v3_v3v3(cagep, cure->v1->cageco, cure->v2->cageco);
+ }
+ else {
+ float d;
+
+ closest_to_line_segment_v3(cagep, cageco, cure->v1->cageco, cure->v2->cageco);
+ d = len_v3v3(cagep, cure->v1->cageco) / len_v3v3(cure->v1->cageco, cure->v2->cageco);
+ interp_v3_v3v3(p, cure->v1->co, cure->v2->co, d);
+ }
+ }
+ else {
+ return NULL;
+ }
+ }
+
+ 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], float cagep[3], BMFace **fptr, int *is_space)
+{
+ BMFace *f;
+ float co[3], cageco[3], sco[3], maxdist = knife_snap_size(kcd, kcd->vthresh);
+
+ if (kcd->ignore_vert_snapping)
+ maxdist *= 0.5;
+
+ f = knife_find_closest_face(kcd, co, cageco, is_space);
+
+ /* set p to co, in case we don't find anything, means a face cut */
+ copy_v3_v3(p, co);
+ copy_v3_v3(cagep, p);
+ kcd->curbmface = f;
+
+ if (f) {
+ ListBase *lst;
+ Ref *ref;
+ KnifeVert *curv = NULL;
+ float dis, curdis = FLT_MAX;
+
+ knife_project_v3(kcd, cageco, 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->cageco, 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->cageco);
+ mul_m4_v3(kcd->vc.obedit->obmat, vec);
+
+ if (ED_view3d_test_clipping(kcd->vc.rv3d, vec, 1) == 0) {
+ curv = kfv;
+ curdis = dis;
+ }
+ }
+ else {
+ curv = kfv;
+ curdis = dis;
+ }
+ }
+ }
+ }
+
+ if (!kcd->ignore_vert_snapping || !(curv && curv->v)) {
+ if (fptr)
+ *fptr = f;
+
+ if (curv && p) {
+ copy_v3_v3(p, curv->co);
+ copy_v3_v3(cagep, curv->cageco);
+ }
+
+ return curv;
+ }
+ else {
+ if (fptr)
+ *fptr = f;
+
+ return NULL;
+ }
+ }
+
+ if (fptr)
+ *fptr = NULL;
+
+ return NULL;
+}
+
+static void knife_snap_angle(knifetool_opdata *kcd)
+{
+ int dx, dy;
+ float w, abs_tan;
+
+ dx = kcd->vc.mval[0] - kcd->prevmval[0];
+ dy = kcd->vc.mval[1] - kcd->prevmval[1];
+ if (dx == 0 || dy == 0)
+ return;
+
+ w = (float)dy / (float)dx;
+ abs_tan = fabsf(w);
+ if (abs_tan <= 0.4142f) { /* tan(22.5 degrees) = 0.4142 */
+ kcd->angle_snapping = ANGLE_0;
+ kcd->vc.mval[1] = kcd->prevmval[1];
+ }
+ else if (abs_tan < 2.4142f) { /* tan(67.5 degrees) = 2.4142 */
+ if (w > 0) {
+ kcd->angle_snapping = ANGLE_45;
+ kcd->vc.mval[1] = kcd->prevmval[1] + dx;
+ }
+ else {
+ kcd->angle_snapping = ANGLE_135;
+ kcd->vc.mval[1] = kcd->prevmval[1] - dx;
+ }
+ }
+ else {
+ kcd->angle_snapping = ANGLE_90;
+ kcd->vc.mval[0] = kcd->prevmval[0];
+ }
+}
+
+/* update active knife edge/vert pointers */
+static int knife_update_active(knifetool_opdata *kcd)
+{
+ if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING)
+ knife_snap_angle(kcd);
+
+ kcd->curvert = NULL; kcd->curedge = NULL; kcd->curbmface = NULL;
+
+ kcd->curvert = knife_find_closest_vert(kcd, kcd->vertco, kcd->vertcage, &kcd->curbmface, &kcd->is_space);
+ if (!kcd->curvert) {
+ kcd->curedge = knife_find_closest_edge(kcd, kcd->vertco, kcd->vertcage, &kcd->curbmface, &kcd->is_space);
+ }
+
+ /* if no hits are found this would normally default to (0,0,0) so instead
+ * get a point at the mouse ray closest to the previous point.
+ * Note that drawing lines in `free-space` isn't properly supported
+ * but theres no guarantee (0,0,0) has any geometry either - campell */
+ if (kcd->curvert == NULL && kcd->curedge == NULL) {
+ float origin[3], ray[3], co[3];
+
+ knife_input_ray_cast(kcd, kcd->vc.mval, origin, ray);
+ add_v3_v3v3(co, origin, ray);
+
+ closest_to_line_v3(kcd->vertcage, kcd->prevcage, co, origin);
+ }
+
+ if (kcd->mode == MODE_DRAGGING) {
+ knife_find_line_hits(kcd);
+ }
+ return 1;
+}
+
+#define MARK 4
+#define DEL 8
+#define VERT_ON_EDGE 16
+#define VERT_ORIG 32
+#define FACE_FLIP 64
+#define BOUNDARY 128
+#define FACE_NEW 256
+
+typedef struct facenet_entry {
+ struct facenet_entry *next, *prev;
+ KnifeEdge *kfe;
+} facenet_entry;
+
+static void rnd_offset_co(float co[3], float scale)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ co[i] += (BLI_drand()-0.5)*scale;
+ }
+}
+
+static void remerge_faces(knifetool_opdata *kcd)
+{
+ BMesh *bm = kcd->em->bm;
+ SmallHash svisit, *visit = &svisit;
+ BMIter iter;
+ BMFace *f;
+ BMFace **stack = NULL;
+ BLI_array_declare(stack);
+ BMFace **faces = NULL;
+ BLI_array_declare(faces);
+ BMOperator bmop;
+ int idx;
+
+ BMO_op_initf(bm, &bmop, "beautify_fill faces=%ff constrain_edges=%fe", FACE_NEW, BOUNDARY);
+
+ BMO_op_exec(bm, &bmop);
+ BMO_slot_buffer_flag_enable(bm, &bmop, "geomout", FACE_NEW, BM_FACE);
+
+ BMO_op_finish(bm, &bmop);
+
+ BLI_smallhash_init(visit);
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BMIter eiter;
+ BMEdge *e;
+ BMFace *f2;
+
+ if (!BMO_elem_flag_test(bm, f, FACE_NEW))
+ continue;
+
+ if (BLI_smallhash_haskey(visit, (intptr_t)f))
+ continue;
+
+ BLI_array_empty(stack);
+ BLI_array_empty(faces);
+ BLI_array_append(stack, f);
+ BLI_smallhash_insert(visit, (intptr_t)f, NULL);
+
+ do {
+ f2 = BLI_array_pop(stack);
+
+ BLI_array_append(faces, f2);
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_FACE, f2) {
+ BMIter fiter;
+ BMFace *f3;
+
+ if (BMO_elem_flag_test(bm, e, BOUNDARY))
+ continue;
+
+ BM_ITER(f3, &fiter, bm, BM_FACES_OF_EDGE, e) {
+ if (!BMO_elem_flag_test(bm, f3, FACE_NEW))
+ continue;
+ if (BLI_smallhash_haskey(visit, (intptr_t)f3))
+ continue;
+
+ BLI_smallhash_insert(visit, (intptr_t)f3, NULL);
+ BLI_array_append(stack, f3);
+ }
+ }
+ } while (BLI_array_count(stack) > 0);
+
+ if (BLI_array_count(faces) > 0) {
+ idx = BM_elem_index_get(faces[0]);
+
+ f2 = BM_faces_join(bm, faces, BLI_array_count(faces));
+ if (f2) {
+ BMO_elem_flag_enable(bm, f2, FACE_NEW);
+ BM_elem_index_set(f2, idx); /* set_dirty! */ /* BMESH_TODO, check if this is valid or not */
+ }
+ }
+ }
+ /* BMESH_TODO, check if the code above validates the indicies */
+ /* bm->elem_index_dirty &= ~BM_FACE; */
+ bm->elem_index_dirty |= BM_FACE;
+
+ BLI_smallhash_release(visit);
+
+ BLI_array_free(stack);
+ BLI_array_free(faces);
+}
+
+/* use edgenet to fill faces. this is a bit annoying and convoluted.*/
+static void knifenet_fill_faces(knifetool_opdata *kcd)
+{
+ BMesh *bm = kcd->em->bm;
+ BMIter bmiter;
+ BLI_mempool_iter iter;
+ BMFace *f;
+ BMEdge *e;
+ KnifeVert *kfv;
+ KnifeEdge *kfe;
+ facenet_entry *entry;
+ ListBase *face_nets = MEM_callocN(sizeof(ListBase)*bm->totface, "face_nets");
+ BMFace **faces = MEM_callocN(sizeof(BMFace *) * bm->totface, "faces knife");
+ MemArena *arena = BLI_memarena_new(1 << 16, "knifenet_fill_faces");
+ SmallHash shash;
+ int i, j, k = 0, totface = bm->totface;
+
+ BMO_push(bm, NULL);
+ bmesh_begin_edit(bm, BMO_OP_FLAG_UNTAN_MULTIRES);
+
+ /* BMESH_TODO this should be valid now, leaving here until we can ensure this - campbell */
+ i = 0;
+ BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) {
+ BM_elem_index_set(f, i); /* set_inline */
+ faces[i] = f;
+ i++;
+ }
+ bm->elem_index_dirty &= ~BM_FACE;
+
+ BM_ITER(e, &bmiter, bm, BM_EDGES_OF_MESH, NULL) {
+ BMO_elem_flag_enable(bm, e, BOUNDARY);
+ }
+
+ /* 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) {
+ /* shouldn't we be at least copying the normal? - if not some comment here should explain why - campbell */
+ kfv->v = BM_vert_create(bm, kfv->co, NULL);
+ kfv->flag = 1;
+ BMO_elem_flag_enable(bm, kfv->v, DEL);
+ }
+ else {
+ kfv->flag = 0;
+ BMO_elem_flag_enable(bm, kfv->v, VERT_ORIG);
+ }
+
+ BMO_elem_flag_enable(bm, kfv->v, MARK);
+ }
+
+ /* we want to only do changed faces. first, go over new edges and add to
+ * face net lists.*/
+ i = j = k = 0;
+ BLI_mempool_iternew(kcd->kedges, &iter);
+ for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) {
+ Ref *ref;
+ if (!kfe->v1 || !kfe->v2 || kfe->v1->inspace || kfe->v2->inspace)
+ continue;
+
+ i++;
+
+ if (kfe->e && kfe->v1->v == kfe->e->v1 && kfe->v2->v == kfe->e->v2) {
+ kfe->oe = kfe->e;
+ continue;
+ }
+
+ j++;
+
+ if (kfe->e) {
+ kfe->oe = kfe->e;
+
+ BMO_elem_flag_enable(bm, kfe->e, DEL);
+ BMO_elem_flag_disable(bm, kfe->e, BOUNDARY);
+ kfe->e = NULL;
+ }
+
+ kfe->e = BM_edge_create(bm, kfe->v1->v, kfe->v2->v, NULL, TRUE);
+ BMO_elem_flag_enable(bm, kfe->e, BOUNDARY);
+
+ for (ref = kfe->faces.first; ref; ref = ref->next) {
+ f = ref->ref;
+
+ entry = BLI_memarena_alloc(arena, sizeof(*entry));
+ entry->kfe = kfe;
+ BLI_addtail(face_nets + BM_elem_index_get(f), entry);
+ }
+ }
+
+ /* go over original edges, and add to faces with new geometry */
+ BLI_mempool_iternew(kcd->kedges, &iter);
+ for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) {
+ Ref *ref;
+
+ if (!kfe->v1 || !kfe->v2 || kfe->v1->inspace || kfe->v2->inspace)
+ continue;
+ if (!(kfe->oe && kfe->v1->v == kfe->oe->v1 && kfe->v2->v == kfe->oe->v2))
+ continue;
+
+ k++;
+
+ BMO_elem_flag_enable(bm, kfe->e, BOUNDARY);
+ kfe->oe = kfe->e;
+
+ for (ref = kfe->faces.first; ref; ref = ref->next) {
+ f = ref->ref;
+
+ if (face_nets[BM_elem_index_get(f)].first) {
+ entry = BLI_memarena_alloc(arena, sizeof(*entry));
+ entry->kfe = kfe;
+ BLI_addtail(face_nets + BM_elem_index_get(f), entry);
+ }
+ }
+ }
+
+ for (i = 0; i < totface; i++) {
+ SmallHash *hash = &shash;
+ EditFace *efa;
+ EditVert *eve, *lasteve;
+ int j;
+ float rndscale = FLT_EPSILON * 25;
+
+ f = faces[i];
+ BLI_smallhash_init(hash);
+
+ if (face_nets[i].first)
+ BMO_elem_flag_enable(bm, f, DEL);
+
+ BLI_begin_edgefill();
+
+ for (entry = face_nets[i].first; entry; entry = entry->next) {
+ if (!BLI_smallhash_haskey(hash, (intptr_t)entry->kfe->v1)) {
+ eve = BLI_addfillvert(entry->kfe->v1->v->co);
+ eve->xs = 0;
+ rnd_offset_co(eve->co, rndscale);
+ eve->tmp.p = entry->kfe->v1->v;
+ BLI_smallhash_insert(hash, (intptr_t)entry->kfe->v1, eve);
+ }
+
+ if (!BLI_smallhash_haskey(hash, (intptr_t)entry->kfe->v2)) {
+ eve = BLI_addfillvert(entry->kfe->v2->v->co);
+ eve->xs = 0;
+ rnd_offset_co(eve->co, rndscale);
+ eve->tmp.p = entry->kfe->v2->v;
+ BLI_smallhash_insert(hash, (intptr_t)entry->kfe->v2, eve);
+ }
+ }
+
+ for (j = 0, entry = face_nets[i].first; entry; entry = entry->next, j++) {
+ lasteve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v1);
+ eve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v2);
+
+ eve->xs++;
+ lasteve->xs++;
+ }
+
+ for (j = 0, entry = face_nets[i].first; entry; entry = entry->next, j++) {
+ lasteve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v1);
+ eve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v2);
+
+ if (eve->xs > 1 && lasteve->xs > 1) {
+ EditEdge *eed;
+ eed = BLI_addfilledge(lasteve, eve);
+ if (entry->kfe->oe)
+ eed->f = FILLBOUNDARY; /* mark as original boundary edge */
+
+ BMO_elem_flag_disable(bm, entry->kfe->e->v1, DEL);
+ BMO_elem_flag_disable(bm, entry->kfe->e->v2, DEL);
+ }
+ else {
+ if (lasteve->xs < 2)
+ BLI_remlink(&fillvertbase, lasteve);
+ if (eve->xs < 2)
+ BLI_remlink(&fillvertbase, eve);
+ }
+ }
+
+ BLI_edgefill(0);
+
+ for (efa = fillfacebase.first; efa; efa = efa->next) {
+ BMVert *v1 = efa->v3->tmp.p, *v2 = efa->v2->tmp.p, *v3 = efa->v1->tmp.p;
+ BMFace *f2;
+ BMLoop *l_iter;
+ BMVert *verts[3] = {v1, v2, v3};
+
+ if (v1 == v2 || v2 == v3 || v1 == v3)
+ continue;
+ if (BM_face_exists(bm, verts, 3, &f2))
+ continue;
+
+ f2 = BM_face_create_quad_tri(bm,
+ v1, v2, v3, NULL,
+ NULL, FALSE);
+
+ BMO_elem_flag_enable(bm, f2, FACE_NEW);
+
+ l_iter = BM_FACE_FIRST_LOOP(f2);
+ do {
+ BMO_elem_flag_disable(bm, l_iter->e, DEL);
+ } while ((l_iter = l_iter->next) != BM_FACE_FIRST_LOOP(f2));
+
+ BMO_elem_flag_disable(bm, f2, DEL);
+ BM_elem_index_set(f2, i); /* set_dirty! */ /* note, not 100% sure this is dirty? need to check */
+
+ BM_face_normal_update(bm, f2);
+ if (dot_v3v3(f->no, f2->no) < 0.0f) {
+ BM_face_normal_flip(bm, f2);
+ }
+ }
+
+ BLI_end_edgefill();
+ BLI_smallhash_release(hash);
+ }
+ bm->elem_index_dirty |= BM_FACE;
+
+ /* interpolate customdata */
+ BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) {
+ BMLoop *l1;
+ BMFace *f2;
+ BMIter liter1;
+
+ if (!BMO_elem_flag_test(bm, f, FACE_NEW))
+ continue;
+
+ f2 = faces[BM_elem_index_get(f)];
+ if (BM_elem_index_get(f) < 0 || BM_elem_index_get(f) >= totface) {
+ fprintf(stderr, "%s: face index out of range! (bmesh internal error)\n", __func__);
+ }
+
+ BM_elem_attrs_copy(bm, bm, f2, f);
+
+ BM_ITER(l1, &liter1, bm, BM_LOOPS_OF_FACE, f) {
+ BM_loop_interp_from_face(bm, l1, f2, TRUE, TRUE);
+ }
+ }
+
+ /* merge triangles back into faces */
+ remerge_faces(kcd);
+
+ /* delete left over faces */
+ BMO_op_callf(bm, "del geom=%ff context=%i", DEL, DEL_ONLYFACES);
+ BMO_op_callf(bm, "del geom=%fe context=%i", DEL, DEL_EDGES);
+ BMO_op_callf(bm, "del geom=%fv context=%i", DEL, DEL_VERTS);
+
+ if (face_nets)
+ MEM_freeN(face_nets);
+ if (faces)
+ MEM_freeN(faces);
+ BLI_memarena_free(arena);
+
+ BMO_error_clear(bm); /* remerge_faces sometimes raises errors, so make sure to clear them */
+
+ bmesh_end_edit(bm, BMO_OP_FLAG_UNTAN_MULTIRES);
+ BMO_pop(bm);
+}
+
+/* called on tool confirmation */
+static void knifetool_finish(bContext *C, wmOperator *op)
+{
+ knifetool_opdata *kcd = op->customdata;
+
+ knifenet_fill_faces(kcd);
+
+ DAG_id_tag_update(kcd->ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, kcd->ob->data);
+}
+
+/* copied from paint_image.c */
+static int project_knife_view_clip(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
+{
+ int orth = ED_view3d_clip_range_get(v3d, rv3d, clipsta, clipend);
+
+ if (orth) { /* only needed for ortho */
+ float fac = 2.0f / ((*clipend) - (*clipsta));
+ *clipsta *= fac;
+ *clipend *= fac;
+ }
+
+ return orth;
+}
+
+static 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);
+ ED_view3d_ob_project_mat_get(ar->regiondata, kcd->ob, kcd->projmat);
+ //mult_m4_m4m4(kcd->projmat, kcd->vc.rv3d->winmat, kcd->vc.rv3d->viewmat);
+
+ 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 *UNUSED(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);
+
+ if (kcd->cagecos)
+ MEM_freeN(kcd->cagecos);
+
+ /* destroy kcd itself */
+ MEM_freeN(kcd);
+ op->customdata = NULL;
+}
+
+static void cage_mapped_verts_callback(void *userData, int index, float *co,
+ float *UNUSED(no_f), short *UNUSED(no_s))
+{
+ void **data = userData;
+ BMEditMesh *em = data[0];
+ float (*cagecos)[3] = data[1];
+ SmallHash *hash = data[2];
+
+ if (index >= 0 && index < em->bm->totvert && !BLI_smallhash_haskey(hash, index)) {
+ BLI_smallhash_insert(hash, index, NULL);
+ copy_v3_v3(cagecos[index], co);
+ }
+}
+
+/* called when modal loop selection gets set up... */
+static int knifetool_init(bContext *C, wmOperator *op, int UNUSED(do_cut))
+{
+ knifetool_opdata *kcd;
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ DerivedMesh *cage, *final;
+ SmallHash shash;
+ void *data[3];
+
+ /* alloc new customdata */
+ kcd = op->customdata = MEM_callocN(sizeof(knifetool_opdata), "knifetool Modal Op Data");
+
+ /* assign the drawing handle for drawing preview line... */
+ kcd->ob = obedit;
+ 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->em = ((Mesh *)kcd->ob->data)->edit_btmesh;
+
+ BM_mesh_elem_index_ensure(kcd->em->bm, BM_VERT);
+
+ cage = editbmesh_get_derived_cage_and_final(scene, obedit, kcd->em, &final, CD_MASK_DERIVEDMESH);
+ kcd->cagecos = MEM_callocN(sizeof(float) * 3 * kcd->em->bm->totvert, "knife cagecos");
+ data[0] = kcd->em;
+ data[1] = kcd->cagecos;
+ data[2] = &shash;
+
+ BLI_smallhash_init(&shash);
+ cage->foreachMappedVert(cage, cage_mapped_verts_callback, data);
+ BLI_smallhash_release(&shash);
+
+ kcd->bmbvh = BMBVH_NewBVH(kcd->em, BMBVH_USE_CAGE|BMBVH_RETURN_ORIG, scene, obedit);
+ kcd->arena = BLI_memarena_new(1 << 15, "knife");
+ kcd->vthresh = KMAXDIST - 1;
+ kcd->ethresh = KMAXDIST;
+
+ kcd->extend = 1;
+
+ knife_recalc_projmat(kcd);
+
+ ED_region_tag_redraw(kcd->ar);
+
+ kcd->refs = BLI_mempool_create(sizeof(Ref), 1, 2048, FALSE, FALSE);
+ kcd->kverts = BLI_mempool_create(sizeof(KnifeVert), 1, 512, FALSE, TRUE);
+ kcd->kedges = BLI_mempool_create(sizeof(KnifeEdge), 1, 512, FALSE, TRUE);
+
+ 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");
+
+ /* cut all the way through the mesh if use_occlude_geometry button not pushed */
+ kcd->cut_through = !(kcd->vc.v3d->flag & V3D_ZBUF_SELECT);
+
+ 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;
+}
+
+enum {
+ KNF_MODAL_CANCEL = 1,
+ KNF_MODAL_CONFIRM,
+ KNF_MODAL_MIDPOINT_ON,
+ KNF_MODAL_MIDPOINT_OFF,
+ KNF_MODAL_NEW_CUT,
+ KNF_MODEL_IGNORE_SNAP_ON,
+ KNF_MODEL_IGNORE_SNAP_OFF,
+ KNF_MODAL_ADD_CUT,
+ KNF_MODAL_ANGLE_SNAP_TOGGLE
+};
+
+wmKeyMap* knifetool_modal_keymap(wmKeyConfig *keyconf)
+{
+ static EnumPropertyItem modal_items[] = {
+ {KNF_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
+ {KNF_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
+ {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap To Midpoints On", ""},
+ {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap To Midpoints Off", ""},
+ {KNF_MODEL_IGNORE_SNAP_ON, "IGNORE_SNAP_ON", 0, "Ignore Snapping On", ""},
+ {KNF_MODEL_IGNORE_SNAP_OFF, "IGNORE_SNAP_OFF", 0, "Ignore Snapping Off", ""},
+ {KNF_MODAL_ANGLE_SNAP_TOGGLE, "ANGLE_SNAP_TOGGLE", 0, "Toggle Angle Snapping", ""},
+ {KNF_MODAL_NEW_CUT, "NEW_CUT", 0, "End Current Cut", ""},
+ {KNF_MODAL_ADD_CUT, "ADD_CUT", 0, "Add Cut", ""},
+
+ {0, NULL, 0, NULL, NULL}};
+
+ wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Knife Tool Modal Map");
+
+ /* this function is called for each spacetype, only needs to add map once */
+ if (keymap) return NULL;
+
+ keymap = WM_modalkeymap_add(keyconf, "Knife Tool Modal Map", modal_items);
+
+ /* items for modal map */
+ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM);
+ WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, KNF_MODAL_ADD_CUT);
+ WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM);
+ WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM);
+ WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM);
+ WM_modalkeymap_add_item(keymap, EKEY, KM_PRESS, 0, 0, KNF_MODAL_NEW_CUT);
+
+ WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_MIDPOINT_ON);
+ WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KNF_MODAL_MIDPOINT_OFF);
+ WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_MIDPOINT_ON);
+ WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_RELEASE, KM_ANY, 0, KNF_MODAL_MIDPOINT_OFF);
+
+ WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_ON);
+ WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_OFF);
+ WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_PRESS, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_ON);
+ WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_RELEASE, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_OFF);
+
+ WM_modalkeymap_add_item(keymap, CKEY, KM_PRESS, 0, 0, KNF_MODAL_ANGLE_SNAP_TOGGLE);
+
+ WM_modalkeymap_assign(keymap, "MESH_OT_knifetool");
+
+ return keymap;
+}
+
+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) {
+ knifetool_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+
+ view3d_operator_needs_opengl(C);
+
+ if (kcd->mode == MODE_PANNING)
+ kcd->mode = kcd->prevmode;
+
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case KNF_MODAL_CANCEL:
+ /* finish */
+ ED_region_tag_redraw(kcd->ar);
+
+ knifetool_exit(C, op);
+
+ return OPERATOR_CANCELLED;
+ case KNF_MODAL_CONFIRM:
+ /* finish */
+ ED_region_tag_redraw(kcd->ar);
+
+ knifetool_finish(C, op);
+ knifetool_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ case KNF_MODAL_MIDPOINT_ON:
+ kcd->snap_midpoints = 1;
+
+ knife_recalc_projmat(kcd);
+ knife_update_active(kcd);
+ ED_region_tag_redraw(kcd->ar);
+ break;
+ case KNF_MODAL_MIDPOINT_OFF:
+ kcd->snap_midpoints = 0;
+
+ knife_recalc_projmat(kcd);
+ knife_update_active(kcd);
+ ED_region_tag_redraw(kcd->ar);
+ break;
+ case KNF_MODEL_IGNORE_SNAP_ON:
+ ED_region_tag_redraw(kcd->ar);
+ kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = 1;
+ break;
+ case KNF_MODEL_IGNORE_SNAP_OFF:
+ ED_region_tag_redraw(kcd->ar);
+ kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = 0;
+ break;
+ case KNF_MODAL_ANGLE_SNAP_TOGGLE:
+ kcd->angle_snapping = !kcd->angle_snapping;
+ break;
+ case KNF_MODAL_NEW_CUT:
+ ED_region_tag_redraw(kcd->ar);
+ knife_finish_cut(kcd);
+ kcd->mode = MODE_IDLE;
+ break;
+ case KNF_MODAL_ADD_CUT:
+ knife_recalc_projmat(kcd);
+
+ if (kcd->mode == MODE_DRAGGING) {
+ knife_add_cut(kcd);
+ if (!kcd->extend) {
+ knife_finish_cut(kcd);
+ kcd->mode = MODE_IDLE;
+ }
+ }
+ else if (kcd->mode != MODE_PANNING) {
+ knife_start_cut(kcd);
+ kcd->mode = MODE_DRAGGING;
+ }
+
+ ED_region_tag_redraw(kcd->ar);
+ break;
+ }
+ }
+ else { /* non-modal-mapped events */
+ switch (event->type) {
+ case WHEELUPMOUSE:
+ case WHEELDOWNMOUSE:
+ return OPERATOR_PASS_THROUGH;
+ case MIDDLEMOUSE:
+ if (event->val != KM_RELEASE) {
+ if (kcd->mode != MODE_PANNING)
+ kcd->prevmode = kcd->mode;
+ kcd->mode = MODE_PANNING;
+ }
+ else {
+ kcd->mode = kcd->prevmode;
+ }
+
+ ED_region_tag_redraw(kcd->ar);
+ return OPERATOR_PASS_THROUGH;
+
+ case MOUSEMOVE: /* mouse moved somewhere to select another loop */
+ if (kcd->mode != MODE_PANNING) {
+ 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;
+ }
+ }
+
+ /* keep going until the user confirms */
+ return OPERATOR_RUNNING_MODAL;
+}
+
+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 c317eabd48a..59861d674f2 100644
--- a/source/blender/editors/mesh/loopcut.c
+++ b/source/blender/editors/mesh/loopcut.c
@@ -30,6 +30,8 @@
#include <float.h>
+#define _USE_MATH_DEFINES
+#include <math.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
@@ -39,7 +41,6 @@
#include "DNA_screen_types.h"
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
-#include "DNA_windowmanager_types.h"
#include "MEM_guardedalloc.h"
@@ -47,9 +48,9 @@
#include "BLI_array.h"
#include "BLI_blenlib.h"
+#include "BLI_math.h"
#include "BLI_dynstr.h" /*for WM_operator_pystring */
#include "BLI_editVert.h"
-#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_blender.h"
@@ -59,6 +60,8 @@
#include "BKE_modifier.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_tessmesh.h"
+#include "BKE_depsgraph.h"
#include "BIF_gl.h"
#include "BIF_glutil.h" /* for paint cursor */
@@ -94,8 +97,8 @@ typedef struct tringselOpData {
ViewContext vc;
Object *ob;
- EditMesh *em;
- EditEdge *eed;
+ BMEditMesh *em;
+ BMEdge *eed;
NumInput num;
int extend;
@@ -130,17 +133,62 @@ 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_face_other_loop(l->e, l->f, eed->v1);
+ rev = (l2 == l->prev);
+ while (l2->v != lasteed->v1 && l2->v != lasteed->v2) {
+ l2 = rev ? l2->prev : 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;
BLI_array_declare(edges);
float co[2][3];
- int looking=1, i, tot=0;
+ int i, tot=0;
+
+ memset(v, 0, sizeof(v));
if (!startedge)
return;
@@ -152,110 +200,87 @@ static void edgering_sel(tringselOpData *lcd, int previewlines, int select)
}
if (!lcd->extend) {
- EM_clear_flag_all(lcd->em, SELECT);
+ EDBM_flag_disable_all(lcd->em, BM_ELEM_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 */
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0;
- eed->f2= 0;
- }
+ if (select) {
+ BMW_init(&walker, em->bm, BMW_EDGERING,
+ BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_NIL_LAY);
- 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++;
+ eed = BMW_begin(&walker, startedge);
+ for (; eed; eed=BMW_step(&walker)) {
+ BM_elem_select_set(em->bm, eed, TRUE);
}
+ BMW_end(&walker);
+
+ return;
}
-
- // 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,
+ BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_NIL_LAY);
+
+ 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);
+ copy_v3_v3(edges[tot][0], co[0]);
+ copy_v3_v3(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];
-
- BLI_array_growone(edges);
- copy_v3_v3(edges[tot][0], co[0]);
- copy_v3_v3(edges[tot][1], co[1]);
- tot++;
- }
- }
- }
- } else {
- select = (startedge->f & SELECT) == 0;
+ if (lasteed != startedge && BM_edge_share_faces(lasteed, startedge)) {
+ v[1][0] = v[0][0];
+ v[1][1] = v[0][1];
+
+ edgering_find_order(em, lasteed, startedge, lastv1, v);
+
+ for(i=1;i<=previewlines;i++){
+ if (!v[0][0] || !v[0][1] || !v[1][0] || !v[1][1])
+ continue;
+
+ 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);
+ copy_v3_v3(edges[tot][0], co[0]);
+ copy_v3_v3(edges[tot][1], co[1]);
+ tot++;
}
}
+ BMW_end(&walker);
lcd->edges = edges;
lcd->totedge = tot;
}
@@ -265,7 +290,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;
}
@@ -274,17 +300,18 @@ 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_mesh_esubdivideflag(lcd->ob, em->bm, BM_ELEM_SELECT, 0.0f,
+ 0.0f, 0, cuts, SUBDIV_SELECT_LOOPCUT,
+ SUBD_PATH, 0, 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)
@@ -292,30 +319,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_store_selection(em, lcd->eed->v1); /* low priority TODO, get vertrex close to mouse */
if(em->selectmode & SCE_SELECT_EDGE)
- EM_store_selection(em, lcd->eed, EDITEDGE);
+ EDBM_store_selection(em, lcd->eed);
- 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;
@@ -344,7 +373,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;
@@ -359,13 +388,16 @@ 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;
}
+/* for bmesh this tool is in bmesh_select.c */
+#if 0
+
static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt)
{
tringselOpData *lcd;
@@ -411,11 +443,13 @@ static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt)
return OPERATOR_FINISHED;
}
+#endif
+
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))
@@ -433,7 +467,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);
@@ -443,22 +477,23 @@ 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 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 RETKEY:
case LEFTMOUSE: /* 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;
@@ -467,6 +502,11 @@ static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event)
ED_region_tag_redraw(lcd->ar);
break;
case RIGHTMOUSE: /* abort */ // XXX hardcoded
+ ED_region_tag_redraw(lcd->ar);
+ ringsel_exit(C, op);
+ ED_area_headerprint(CTX_wm_area(C), NULL);
+
+ return OPERATOR_FINISHED;
case ESCKEY:
if (event->val == KM_RELEASE) {
/* cancel */
@@ -478,35 +518,37 @@ static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event)
ED_region_tag_redraw(lcd->ar);
break;
- case WHEELUPMOUSE: /* change number of cuts */
case PADPLUSKEY:
case PAGEUPKEY:
- if (event->val == KM_PRESS) {
- cuts++;
- RNA_int_set(op->ptr, "number_cuts",cuts);
- ringsel_find_edge(lcd, cuts);
-
- ED_region_tag_redraw(lcd->ar);
- }
+ 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 WHEELDOWNMOUSE: /* change number of cuts */
case PADMINUS:
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);
-
- ED_region_tag_redraw(lcd->ar);
- }
+ 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;
@@ -539,6 +581,9 @@ static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
+/* for bmesh this tool is in bmesh_select.c */
+#if 0
+
void MESH_OT_edgering_select (wmOperatorType *ot)
{
/* description */
@@ -556,6 +601,8 @@ void MESH_OT_edgering_select (wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
}
+#endif
+
void MESH_OT_loopcut (wmOperatorType *ot)
{
/* description */
@@ -565,7 +612,7 @@ void MESH_OT_loopcut (wmOperatorType *ot)
/* 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 09ae5e08d60..0d7d6ca8108 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -41,6 +41,8 @@
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
+#include "BLI_utildefines.h"
+#include "BLI_array.h"
#include "BLI_math.h"
#include "BLI_editVert.h"
#include "BLI_edgehash.h"
@@ -55,6 +57,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"
@@ -71,19 +74,31 @@
#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
layer data pointer to find where the active layer has ended up.
+
this is necassary because the deletion functions only support deleting the active
layer. */
@@ -93,15 +108,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_data_layer_free(me->edit_btmesh->bm, data, type);
}
else {
- CustomData_free_layer_active(data, type, me->totface);
- mesh_update_customdata_pointers(me);
+ CustomData_free_layer_active(data, type, tot);
+ mesh_update_customdata_pointers(me, TRUE);
}
- 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 */
@@ -162,8 +177,13 @@ static void delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *la
}
}
-static void copy_editface_active_customdata(EditMesh *em, int type, int index)
+static void copy_editface_active_customdata(BMEditMesh *em, int type, int index)
{
+#if 1 /*BMESH_TODO*/
+ (void)em;
+ (void)type;
+ (void)index;
+#else
EditFace *efa;
int n= CustomData_get_active_layer(&em->fdata, type);
@@ -171,44 +191,174 @@ static void copy_editface_active_customdata(EditMesh *em, int type, int index)
void *data= CustomData_em_get_n(&em->fdata, efa->data, type, n);
CustomData_em_set_n(&em->fdata, efa->data, type, index, data);
}
+#endif
+}
+
+int ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me)
+{
+ BMEditMesh *em= me->edit_btmesh;
+ MLoopUV *luv;
+ BLI_array_declare(polylengths);
+ int *polylengths = NULL;
+ BLI_array_declare(uvs);
+ float **uvs = NULL;
+ float **fuvs = NULL;
+ int i, j;
+
+ if (em) {
+ /* Collect BMesh UVs */
+
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+
+ BLI_assert(CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV));
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ 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);
+ BLI_array_append(uvs, luv->uv);
+ i++;
+ }
+
+ BLI_array_append(polylengths, efa->len);
+ }
+ }
+ else {
+ /* Collect Mesh UVs */
+
+ MPoly *mp;
+
+ BLI_assert(CustomData_has_layer(&me->ldata, CD_MLOOPUV));
+
+ for (j = 0; j < me->totpoly; j++) {
+ mp = &me->mpoly[j];
+
+ for (i = 0; i < mp->totloop; i++) {
+ luv = &me->mloopuv[mp->loopstart + i];
+ BLI_array_append(uvs, luv->uv);
+ }
+
+ BLI_array_append(polylengths, mp->totloop);
+ }
+ }
+
+ fuvs = uvs;
+ for (j = 0; j < BLI_array_count(polylengths); j++) {
+ int len = polylengths[j];
+
+ if (len == 3) {
+ fuvs[0][0] = 0.0;
+ fuvs[0][1] = 0.0;
+
+ fuvs[1][0] = 1.0;
+ fuvs[1][1] = 0.0;
+
+ fuvs[2][0] = 1.0;
+ fuvs[2][1] = 1.0;
+ } else if (len == 4) {
+ fuvs[0][0] = 0.0;
+ fuvs[0][1] = 0.0;
+
+ fuvs[1][0] = 1.0;
+ fuvs[1][1] = 0.0;
+
+ fuvs[2][0] = 1.0;
+ fuvs[2][1] = 1.0;
+
+ fuvs[3][0] = 0.0;
+ fuvs[3][1] = 1.0;
+ /*make sure we ignore 2-sided faces*/
+ } else if (len > 2) {
+ float fac = 0.0f, dfac = 1.0f / (float)len;
+
+ dfac *= M_PI*2;
+
+ for (i = 0; i < len; i++) {
+ fuvs[i][0] = 0.5f * sin(fac) + 0.5f;
+ fuvs[i][1] = 0.5f * cos(fac) + 0.5f;
+
+ fac += dfac;
+ }
+ }
+
+ fuvs += len;
+ }
+
+ /* BMESH_TODO: Copy poly UVs onto CD_MTFACE layer for tesselated faces */
+
+ BLI_array_free(uvs);
+ BLI_array_free(polylengths);
+
+ DAG_id_tag_update(&me->id, 0);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
+
+ return 1;
}
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);
- if(layernum >= MAX_MTFACE)
+ layernum = CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY);
+ if (layernum >= MAX_MTFACE)
return -1;
- EM_add_data_layer(em, &em->fdata, CD_MTFACE, name);
+ BM_data_layer_add(em->bm, &em->bm->pdata, CD_MTEXPOLY);
+ CustomData_set_layer_active(&em->bm->pdata, CD_MTEXPOLY, layernum);
+ CustomData_set_layer_name(&em->bm->pdata, CD_MTEXPOLY, layernum, name);
- if(layernum) /* copy data from active UV */
+ /* copy data from active UV */
+ if (layernum)
copy_editface_active_customdata(em, CD_MTFACE, layernum);
- if(active_set || layernum==0)
- CustomData_set_layer_active(&em->fdata, CD_MTFACE, layernum);
+ if (active_set || layernum == 0) {
+ CustomData_set_layer_active(&em->bm->pdata, CD_MTEXPOLY, layernum);
+ }
+
+ BM_data_layer_add(em->bm, &em->bm->ldata, CD_MLOOPUV);
+ CustomData_set_layer_name(&em->bm->ldata, CD_MLOOPUV, layernum, name);
+
+ CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPUV, layernum);
+ if(active_set || layernum == 0) {
+ CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPUV, layernum);
+ }
}
else {
- layernum= CustomData_number_of_layers(&me->fdata, CD_MTFACE);
- if(layernum >= MAX_MTFACE)
+ layernum = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
+ if (layernum >= MAX_MTFACE)
return -1;
- if(me->mtface)
+ 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);
CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DUPLICATE, me->mtface, me->totface, name);
- else
+ } 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);
CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface, name);
+ }
+
+ if (active_set || layernum == 0) {
+ CustomData_set_layer_active(&me->pdata, CD_MTEXPOLY, layernum);
+ CustomData_set_layer_active(&me->ldata, CD_MLOOPUV, layernum);
- if(active_set || layernum==0)
CustomData_set_layer_active(&me->fdata, CD_MTFACE, layernum);
+ }
- mesh_update_customdata_pointers(me);
+ mesh_update_customdata_pointers(me, TRUE);
}
+ ED_mesh_uv_loop_reset(C, me);
+
DAG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
@@ -217,17 +367,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);
@@ -236,38 +391,50 @@ int ED_mesh_uv_texture_remove(bContext *C, Object *ob, Mesh *me)
int ED_mesh_color_add(bContext *C, Scene *UNUSED(scene), Object *UNUSED(ob), 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_MCOL);
- if(layernum >= MAX_MCOL)
+ layernum= CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL);
+ if (layernum >= MAX_MCOL) {
return -1;
+ }
- EM_add_data_layer(em, &em->fdata, CD_MCOL, name);
+ BM_data_layer_add(em->bm, &em->bm->pdata, CD_MLOOPCOL);
+ CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum);
- if(layernum) /* copy data from active vertex color layer */
+ /* copy data from active vertex color layer */
+ if (layernum) {
copy_editface_active_customdata(em, CD_MCOL, layernum);
+ }
- if(active_set || layernum==0)
- CustomData_set_layer_active(&em->fdata, CD_MCOL, layernum);
+ if (active_set || layernum == 0) {
+ 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 -1;
+ }
- if(me->mcol)
- CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DUPLICATE, me->mcol, me->totface, name);
- else
+ if(me->mloopcol) {
+ CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DUPLICATE, me->mloopcol, me->totloop, name);
+ CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DUPLICATE, me->mloopcol, me->totface, name);
+ }
+ else {
+ CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop, name);
CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface, name);
+ }
- if(active_set || layernum==0)
+ if(active_set || layernum==0) {
+ CustomData_set_layer_active(&me->ldata, CD_MLOOPCOL, layernum);
CustomData_set_layer_active(&me->fdata, CD_MCOL, layernum);
+ }
- mesh_update_customdata_pointers(me);
+ mesh_update_customdata_pointers(me, TRUE);
}
DAG_id_tag_update(&me->id, 0);
@@ -278,12 +445,11 @@ int ED_mesh_color_add(bContext *C, Scene *UNUSED(scene), Object *UNUSED(ob), Mes
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;
@@ -297,12 +463,11 @@ int ED_mesh_color_remove(bContext *C, Object *ob, Mesh *me)
int ED_mesh_color_remove_named(bContext *C, Object *ob, Mesh *me, const char *name)
{
- CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata;
CustomDataLayer *cdl;
int index;
- index= CustomData_get_named_layer_index(data, CD_MCOL, name);
- cdl= (index == -1)? NULL: &data->layers[index];
+ index= CustomData_get_named_layer_index(&me->ldata, CD_MLOOPCOL, name);
+ cdl= (index == -1)? NULL: &me->ldata.layers[index];
if(!cdl)
return 0;
@@ -384,25 +549,24 @@ 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(bmain, 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;
/* load_editMesh free's pointers used by CustomData layers which might be used by DerivedMesh too,
* so signal to re-create DerivedMesh here (sergey) */
@@ -589,10 +753,35 @@ void MESH_OT_sticky_remove(wmOperatorType *ot)
void ED_mesh_update(Mesh *mesh, bContext *C, int calc_edges)
{
- if(calc_edges || (mesh->totface && mesh->totedge == 0))
+ int *polyindex = NULL;
+ float (*face_nors)[3];
+
+ if(mesh->totface > 0 && mesh->totpoly == 0)
+ convert_mfaces_to_mpolys(mesh);
+
+ if(calc_edges || (mesh->totpoly && mesh->totedge == 0))
BKE_mesh_calc_edges(mesh, calc_edges);
- mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mface, mesh->totface, NULL);
+ /* TODO, make this optional, we dont always want this! */
+ BKE_mesh_tessface_calc(mesh);
+
+ polyindex = CustomData_get_layer(&mesh->fdata, CD_POLYINDEX);
+ /* add a normals layer for tesselated faces, a tessface normal will
+ contain the normal of the poly the face was tesselated from. */
+ face_nors = CustomData_add_layer(&mesh->fdata, CD_NORMAL, CD_CALLOC, NULL, mesh->totface);
+
+ mesh_calc_normals_mapping(
+ mesh->mvert,
+ mesh->totvert,
+ mesh->mloop,
+ mesh->mpoly,
+ mesh->totloop,
+ mesh->totpoly,
+ NULL /* polyNors_r */,
+ mesh->mface,
+ mesh->totface,
+ polyindex,
+ face_nors);
DAG_id_tag_update(&mesh->id, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, mesh);
@@ -616,7 +805,7 @@ static void mesh_add_verts(Mesh *mesh, int len)
CustomData_free(&mesh->vdata, mesh->totvert);
mesh->vdata= vdata;
- mesh_update_customdata_pointers(mesh);
+ mesh_update_customdata_pointers(mesh, FALSE);
/* scan the input list and insert the new vertices */
@@ -636,7 +825,7 @@ void ED_mesh_transform(Mesh *me, float *mat)
for(i= 0; i < me->totvert; i++, mvert++)
mul_m4_v3((float (*)[4])mat, mvert->co);
- mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+ mesh_calc_normals_mapping(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL);
}
static void mesh_add_edges(Mesh *mesh, int len)
@@ -659,7 +848,7 @@ static void mesh_add_edges(Mesh *mesh, int len)
CustomData_free(&mesh->edata, mesh->totedge);
mesh->edata= edata;
- mesh_update_customdata_pointers(mesh);
+ mesh_update_customdata_pointers(mesh, FALSE); /* new edges dont change tessellation */
/* set default flags */
medge= &mesh->medge[mesh->totedge];
@@ -689,7 +878,7 @@ static void mesh_add_faces(Mesh *mesh, int len)
CustomData_free(&mesh->fdata, mesh->totface);
mesh->fdata= fdata;
- mesh_update_customdata_pointers(mesh);
+ mesh_update_customdata_pointers(mesh, TRUE);
/* set default flags */
mface= &mesh->mface[mesh->totface];
@@ -699,6 +888,60 @@ static void mesh_add_faces(Mesh *mesh, int len)
mesh->totface= totface;
}
+static void mesh_add_loops(Mesh *mesh, int len)
+{
+ CustomData ldata;
+ int totloop;
+
+ if(len == 0)
+ return;
+
+ totloop= mesh->totloop + len; /* new face count */
+
+ /* update customdata */
+ CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloop);
+ CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop);
+
+ if(!CustomData_has_layer(&ldata, CD_MLOOP))
+ CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloop);
+
+ CustomData_free(&mesh->ldata, mesh->totloop);
+ mesh->ldata= ldata;
+ mesh_update_customdata_pointers(mesh, TRUE);
+
+ mesh->totloop= totloop;
+}
+
+static void mesh_add_polys(Mesh *mesh, int len)
+{
+ CustomData pdata;
+ MPoly *mpoly;
+ int i, totpoly;
+
+ if(len == 0)
+ return;
+
+ totpoly= mesh->totpoly + len; /* new face count */
+
+ /* update customdata */
+ CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpoly);
+ CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly);
+
+ if(!CustomData_has_layer(&pdata, CD_MPOLY))
+ CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpoly);
+
+ CustomData_free(&mesh->pdata, mesh->totpoly);
+ mesh->pdata= pdata;
+ mesh_update_customdata_pointers(mesh, TRUE);
+
+ /* set default flags */
+ mpoly= &mesh->mpoly[mesh->totpoly];
+ for(i=0; i<len; i++, mpoly++)
+ mpoly->flag= ME_FACE_SEL;
+
+ mesh->totpoly= totpoly;
+}
+
static void mesh_remove_verts(Mesh *mesh, int len)
{
int totvert;
@@ -742,7 +985,7 @@ static void mesh_remove_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;
}
@@ -758,7 +1001,7 @@ 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;
}
@@ -768,9 +1011,9 @@ void ED_mesh_faces_add(Mesh *mesh, ReportList *reports, int 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);
@@ -778,7 +1021,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;
}
@@ -788,7 +1031,7 @@ void ED_mesh_vertices_add(Mesh *mesh, ReportList *reports, int count)
void ED_mesh_faces_remove(Mesh *mesh, ReportList *reports, int count)
{
- if(mesh->edit_mesh) {
+ if(mesh->edit_btmesh) {
BKE_report(reports, RPT_ERROR, "Can't remove faces in edit mode");
return;
}
@@ -802,7 +1045,7 @@ void ED_mesh_faces_remove(Mesh *mesh, ReportList *reports, int count)
void ED_mesh_edges_remove(Mesh *mesh, ReportList *reports, int count)
{
- if(mesh->edit_mesh) {
+ if(mesh->edit_btmesh) {
BKE_report(reports, RPT_ERROR, "Can't remove edges in edit mode");
return;
}
@@ -816,7 +1059,7 @@ void ED_mesh_edges_remove(Mesh *mesh, ReportList *reports, int count)
void ED_mesh_vertices_remove(Mesh *mesh, ReportList *reports, int count)
{
- if(mesh->edit_mesh) {
+ if(mesh->edit_btmesh) {
BKE_report(reports, RPT_ERROR, "Can't remove vertices in edit mode");
return;
}
@@ -828,7 +1071,27 @@ void ED_mesh_vertices_remove(Mesh *mesh, ReportList *reports, int count)
mesh_remove_verts(mesh, count);
}
-void ED_mesh_calc_normals(Mesh *me)
+void ED_mesh_loops_add(Mesh *mesh, ReportList *reports, int count)
+{
+ if(mesh->edit_btmesh) {
+ BKE_report(reports, RPT_ERROR, "Can't add loops in edit mode.");
+ return;
+ }
+
+ mesh_add_loops(mesh, count);
+}
+
+void ED_mesh_polys_add(Mesh *mesh, ReportList *reports, int count)
+{
+ if(mesh->edit_btmesh) {
+ BKE_report(reports, RPT_ERROR, "Can't add polys in edit mode.");
+ return;
+ }
+
+ mesh_add_polys(mesh, count);
+}
+
+void ED_mesh_calc_normals(Mesh *mesh)
{
- mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+ mesh_calc_normals_mapping(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL, NULL, 0, NULL, NULL);
}
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 88fecae3c32..16c1da06383 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -37,14 +37,60 @@
struct bContext;
struct wmOperatorType;
-struct wmOperator;
struct ViewContext;
+struct BMEditMesh;
+struct BMesh;
+struct BMEdge;
+struct BMFace;
+struct BMOperator;
+struct wmOperator;
+struct wmKeyMap;
+struct wmKeyConfig;
+struct EnumPropertyItem;
+
+/* ******************** 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, const int report);
+
+void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag);
+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);
+
+/* TODO, move to math_geometry.c */
+float labda_PdistVL2Dfl(const float v1[3], const float v2[3], const float v3[3]);
/* ******************** 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);
+#if 0 /* REMOVE AFTER BMESH MERGE */
/* ******************* editmesh.c */
@@ -52,6 +98,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);
@@ -63,6 +113,8 @@ 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);
+#endif
+
void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc);
void MESH_OT_separate(struct wmOperatorType *ot);
@@ -85,6 +137,8 @@ void MESH_OT_duplicate(struct wmOperatorType *ot);
void MESH_OT_fgon_make(struct wmOperatorType *ot);
void MESH_OT_fgon_clear(struct wmOperatorType *ot);
+#if 0 /* REMOVE AFTER BMESH MERGE */
+
/* ******************* editmesh_lib.c */
void EM_stats_update(EditMesh *em);
@@ -133,15 +187,21 @@ extern int convex(float *v1, float *v2, float *v3, float *v4);
extern struct EditFace *EM_face_from_faces(EditMesh *em, struct EditFace *efa1,
struct EditFace *efa2, int i1, int i2, int i3, int i4);
+#endif
+
extern int EM_view3d_poll(struct bContext *C);
-/* ******************* editmesh_loop.c */
+struct wmKeyMap* knifetool_modal_keymap(struct wmKeyConfig *keyconf);
+
+/* ******************* knifetool.c */
void MESH_OT_knife_cut(struct wmOperatorType *ot);
-/* ******************* editmesh_mods.c */
+/* ******************* bmesh_select.c */
void MESH_OT_loop_select(struct wmOperatorType *ot);
void MESH_OT_select_all(struct wmOperatorType *ot);
+void MESH_OT_select_interior_faces(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_non_manifold(struct wmOperatorType *ot);
@@ -150,6 +210,7 @@ void MESH_OT_select_linked_pick(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);
+void MESH_OT_select_loose_verts(struct wmOperatorType *ot);
void MESH_OT_select_mirror(struct wmOperatorType *ot);
void MESH_OT_normals_make_consistent(struct wmOperatorType *ot);
void MESH_OT_faces_select_linked_flat(struct wmOperatorType *ot);
@@ -163,49 +224,23 @@ void MESH_OT_mark_sharp(struct wmOperatorType *ot);
void MESH_OT_mark_freestyle_edge(struct wmOperatorType *ot);
void MESH_OT_vertices_smooth(struct wmOperatorType *ot);
void MESH_OT_noise(struct wmOperatorType *ot);
+void EXPORT_MESH_OT_wavefront(struct wmOperatorType *ot);
void MESH_OT_flip_normals(struct wmOperatorType *ot);
void MESH_OT_solidify(struct wmOperatorType *ot);
void MESH_OT_select_nth(struct wmOperatorType *ot);
+void MESH_OT_select_next_loop(struct wmOperatorType *ot);
+extern struct EnumPropertyItem *corner_type_items;
-extern EditEdge *findnearestedge(struct 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(struct 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
-#define SUBDIV_SELECT_LOOPCUT 3
-
-/* edge subdivide corner cut types */
-#define SUBDIV_CORNER_PATH 0
-#define SUBDIV_CORNER_INNERVERT 1
-#define SUBDIV_CORNER_FAN 2
-
-extern EnumPropertyItem corner_type_items[];
+#if 0 /* REMOVE AFTER BMESH MERGE */
void join_triangles(EditMesh *em);
int removedoublesflag(EditMesh *em, short flag, short automerge, float limit); /* return amount */
void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float fractal, int beautify, int numcuts, int corner_pattern, int seltype);
int EdgeSlide(EditMesh *em, struct wmOperator *op, short immediate, float imperc);
+#endif
+
void MESH_OT_merge(struct wmOperatorType *ot);
void MESH_OT_subdivide(struct wmOperatorType *ot);
void MESH_OT_remove_doubles(struct wmOperatorType *ot);
@@ -219,6 +254,7 @@ void MESH_OT_fill(struct wmOperatorType *ot);
void MESH_OT_beautify_fill(struct wmOperatorType *ot);
void MESH_OT_quads_convert_to_tris(struct wmOperatorType *ot);
void MESH_OT_tris_convert_to_quads(struct wmOperatorType *ot);
+void MESH_OT_dissolve_limited(struct wmOperatorType *ot);
void MESH_OT_edge_flip(struct wmOperatorType *ot);
void MESH_OT_faces_shade_smooth(struct wmOperatorType *ot);
void MESH_OT_faces_shade_flat(struct wmOperatorType *ot);
@@ -231,9 +267,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);
@@ -253,9 +292,23 @@ 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);
+void MESH_OT_bevel(struct wmOperatorType *ot);
+
+void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot);
+
/* ******************* mesh_navmesh.c */
void MESH_OT_navmesh_make(struct wmOperatorType *ot);
void MESH_OT_navmesh_face_copy(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c
index 973659cbb35..99947cb9ae2 100644
--- a/source/blender/editors/mesh/mesh_navmesh.c
+++ b/source/blender/editors/mesh/mesh_navmesh.c
@@ -46,6 +46,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_report.h"
+#include "BKE_tessmesh.h"
#include "BLI_editVert.h"
#include "BLI_listbase.h"
@@ -90,11 +91,11 @@ static void createVertsTrisData(bContext *C, LinkNode* obs, int *nverts_r, float
BLI_linklist_append(&dms, (void*)dm);
nverts+= dm->getNumVerts(dm);
- nfaces= dm->getNumFaces(dm);
+ nfaces= dm->getNumTessFaces(dm);
ntris+= nfaces;
/* resolve quad faces */
- mface= dm->getFaceArray(dm);
+ mface= dm->getTessFaceArray(dm);
for(i= 0; i<nfaces; i++) {
MFace* mf= &mface[i];
if(mf->v4)
@@ -129,8 +130,8 @@ static void createVertsTrisData(bContext *C, LinkNode* obs, int *nverts_r, float
}
/* create tris */
- curnfaces= dm->getNumFaces(dm);
- mface= dm->getFaceArray(dm);
+ curnfaces= dm->getNumTessFaces(dm);
+ mface= dm->getTessFaceArray(dm);
for(i= 0; i<curnfaces; i++) {
MFace* mf= &mface[i];
@@ -292,7 +293,7 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts
static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh, struct recast_polyMeshDetail *dmesh, Base* base)
{
float co[3], rot[3];
- EditMesh *em;
+ BMEditMesh *em;
int i,j, k;
unsigned short* v;
int face[3];
@@ -320,14 +321,11 @@ static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
}
ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER);
- em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+ em= (((Mesh *)obedit->data))->edit_btmesh;
if(!createob) {
/* clear */
- 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));
+ EDBM_ClearMesh(em);
}
/* create verts for polygon mesh */
@@ -341,12 +339,12 @@ static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
co[1]= bmin[1] + v[1]*ch;
co[2]= bmin[2] + v[2]*cs;
SWAP(float, co[1], co[2]);
- addvertlist(em, co, NULL);
+ BM_vert_create(em->bm, co, NULL);
}
/* create custom data layer to save polygon idx */
- CustomData_add_layer_named(&em->fdata, CD_RECAST, CD_CALLOC, NULL, 0, "createRepresentation recastData");
-
+ CustomData_add_layer_named(&em->bm->pdata, CD_RECAST, CD_CALLOC, NULL, 0, "createRepresentation recastData");
+
/* create verts and faces for detailed mesh */
meshes= recast_polyMeshDetailGetMeshes(dmesh, &nmeshes);
polys= recast_polyMeshGetPolys(pmesh, NULL, &nvp);
@@ -354,7 +352,7 @@ static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
tris= recast_polyMeshDetailGetTris(dmesh, NULL);
for(i= 0; i<nmeshes; i++) {
- int uniquevbase= em->totvert;
+ int uniquevbase= em->bm->totvert;
unsigned int vbase= meshes[4*i+0];
unsigned short ndv= meshes[4*i+1];
unsigned short tribase= meshes[4*i+2];
@@ -371,39 +369,40 @@ static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
for(j= nv; j<ndv; j++) {
copy_v3_v3(co, &dverts[3*(vbase + j)]);
SWAP(float, co[1], co[2]);
- addvertlist(em, co, NULL);
+ BM_vert_create(em->bm, co, NULL);
}
- EM_init_index_arrays(em, 1, 0, 0);
+ EDBM_init_index_arrays(em, 1, 0, 0);
/* create faces */
for(j= 0; j<trinum; j++) {
unsigned char* tri= &tris[4*(tribase+j)];
- EditFace* newFace;
+ BMFace* newFace;
int* polygonIdx;
for(k= 0; k<3; k++) {
if(tri[k]<nv)
- face[k]= p[tri[k]]; /* shared vertex */
+ face[k] = p[tri[k]]; /* shared vertex */
else
- face[k]= uniquevbase+tri[k]-nv; /* unique vertex */
+ face[k] = uniquevbase+tri[k]-nv; /* unique vertex */
}
- newFace= addfacelist(em, EM_get_vert_for_index(face[0]), EM_get_vert_for_index(face[2]),
- EM_get_vert_for_index(face[1]), NULL, NULL, NULL);
+ newFace= BM_face_create_quad_tri(em->bm,
+ EDBM_get_vert_for_index(em, face[0]),
+ EDBM_get_vert_for_index(em, face[2]),
+ EDBM_get_vert_for_index(em, face[1]), NULL,
+ NULL, FALSE);
/* set navigation polygon idx to the custom layer */
- polygonIdx= (int*)CustomData_em_get(&em->fdata, newFace->data, CD_RECAST);
+ polygonIdx= (int*)CustomData_bmesh_get(&em->bm->pdata, newFace->head.data, CD_RECAST);
*polygonIdx= i+1; /* add 1 to avoid zero idx */
}
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
}
recast_destroyPolyMesh(pmesh);
recast_destroyPolyMeshDetail(dmesh);
- BKE_mesh_end_editmesh((Mesh*)obedit->data, em);
-
DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
@@ -485,22 +484,23 @@ void MESH_OT_navmesh_make(wmOperatorType *ot)
static int navmesh_face_copy_exec(bContext *C, wmOperator *op)
{
Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
/* do work here */
- EditFace *efa_act= EM_get_actFace(em, 0);
+ BMFace *efa_act= BM_active_face_get(em->bm, FALSE);
if(efa_act) {
- if(CustomData_has_layer(&em->fdata, CD_RECAST)) {
- EditFace *efa;
- int targetPolyIdx= *(int*)CustomData_em_get(&em->fdata, efa_act->data, CD_RECAST);
+ if(CustomData_has_layer(&em->bm->pdata, CD_RECAST)) {
+ BMFace *efa;
+ BMIter iter;
+ int targetPolyIdx= *(int*)CustomData_bmesh_get(&em->bm->pdata, efa_act->head.data, CD_RECAST);
targetPolyIdx= targetPolyIdx>=0? targetPolyIdx : -targetPolyIdx;
if(targetPolyIdx > 0) {
/* set target poly idx to other selected faces */
- for (efa= (EditFace *)em->faces.first; efa; efa= efa->next) {
- if((efa->f & SELECT) && efa != efa_act) {
- int* recastDataBlock= (int*)CustomData_em_get(&em->fdata, efa->data, CD_RECAST);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if(BM_elem_flag_test(efa, BM_ELEM_SELECT) && efa != efa_act) {
+ int* recastDataBlock= (int*)CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_RECAST);
*recastDataBlock= targetPolyIdx;
}
}
@@ -514,8 +514,6 @@ static int navmesh_face_copy_exec(bContext *C, wmOperator *op)
DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
- BKE_mesh_end_editmesh((Mesh*)obedit->data, em);
-
return OPERATOR_FINISHED;
}
@@ -539,19 +537,20 @@ static int compare(const void * a, const void * b)
return ( *(int*)a - *(int*)b );
}
-static int findFreeNavPolyIndex(EditMesh* em)
+static int findFreeNavPolyIndex(BMEditMesh* em)
{
/* construct vector of indices */
- int numfaces= em->totface;
+ int numfaces= em->bm->totface;
int* indices= MEM_callocN(sizeof(int)*numfaces, "findFreeNavPolyIndex(indices)");
- EditFace* ef= (EditFace*)em->faces.last;
- int i, idx= 0, freeIdx= 1;
+ BMFace* ef;
+ BMIter iter;
+ int i, idx= em->bm->totface-1, freeIdx= 1;
- while(ef) {
- int polyIdx= *(int*)CustomData_em_get(&em->fdata, ef->data, CD_RECAST);
+ /*XXX this originally went last to first, but that isn't possible anymore*/
+ BM_ITER(ef, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ int polyIdx= *(int*)CustomData_bmesh_get(&em->bm->pdata, ef->head.data, CD_RECAST);
indices[idx]= polyIdx;
- idx++;
- ef= ef->prev;
+ idx--;
}
qsort(indices, numfaces, sizeof(int), compare);
@@ -573,21 +572,22 @@ static int findFreeNavPolyIndex(EditMesh* em)
static int navmesh_face_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
- EditFace *ef;
-
- if(CustomData_has_layer(&em->fdata, CD_RECAST)) {
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMFace *ef;
+ BMIter iter;
+
+ if(CustomData_has_layer(&em->bm->pdata, CD_RECAST)) {
int targetPolyIdx= findFreeNavPolyIndex(em);
if(targetPolyIdx>0) {
/* set target poly idx to selected faces */
- ef= (EditFace*)em->faces.last;
- while(ef) {
- if(ef->f & SELECT) {
- int *recastDataBlock= (int*)CustomData_em_get(&em->fdata, ef->data, CD_RECAST);
+ /*XXX this originally went last to first, but that isn't possible anymore*/
+
+ BM_ITER(ef, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if(BM_elem_flag_test(ef, BM_ELEM_SELECT)) {
+ int *recastDataBlock= (int*)CustomData_bmesh_get(&em->bm->pdata, ef->head.data, CD_RECAST);
*recastDataBlock= targetPolyIdx;
}
- ef= ef->prev;
}
}
}
@@ -595,7 +595,6 @@ static int navmesh_face_add_exec(bContext *C, wmOperator *UNUSED(op))
DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
- BKE_mesh_end_editmesh((Mesh*)obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -619,7 +618,7 @@ static int navmesh_obmode_data_poll(bContext *C)
Object *ob = ED_object_active_context(C);
if (ob && (ob->mode == OB_MODE_OBJECT) && (ob->type == OB_MESH)) {
Mesh *me= ob->data;
- return CustomData_has_layer(&me->fdata, CD_RECAST);
+ return CustomData_has_layer(&me->pdata, CD_RECAST);
}
return FALSE;
}
@@ -638,7 +637,7 @@ static int navmesh_reset_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = ED_object_active_context(C);
Mesh *me= ob->data;
- CustomData_free_layers(&me->fdata, CD_RECAST, me->totface);
+ CustomData_free_layers(&me->pdata, CD_RECAST, me->totpoly);
BKE_mesh_ensure_navmesh(me);
@@ -668,7 +667,7 @@ static int navmesh_clear_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = ED_object_active_context(C);
Mesh *me= ob->data;
- CustomData_free_layers(&me->fdata, CD_RECAST, me->totface);
+ CustomData_free_layers(&me->pdata, CD_RECAST, me->totpoly);
DAG_id_tag_update(&me->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, &me->id);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index e6268d80c21..90f125cf75a 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -60,6 +60,7 @@
void ED_operatortypes_mesh(void)
{
WM_operatortype_append(MESH_OT_select_all);
+ WM_operatortype_append(MESH_OT_select_interior_faces);
WM_operatortype_append(MESH_OT_select_more);
WM_operatortype_append(MESH_OT_select_less);
WM_operatortype_append(MESH_OT_select_non_manifold);
@@ -69,6 +70,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_hide);
WM_operatortype_append(MESH_OT_reveal);
WM_operatortype_append(MESH_OT_select_by_number_vertices);
+ WM_operatortype_append(MESH_OT_select_loose_verts);
WM_operatortype_append(MESH_OT_select_mirror);
WM_operatortype_append(MESH_OT_normals_make_consistent);
WM_operatortype_append(MESH_OT_merge);
@@ -84,16 +86,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);
@@ -103,14 +107,15 @@ 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_uvs_reverse);
WM_operatortype_append(MESH_OT_colors_rotate);
- WM_operatortype_append(MESH_OT_colors_mirror);
+ WM_operatortype_append(MESH_OT_colors_reverse);
WM_operatortype_append(MESH_OT_fill);
WM_operatortype_append(MESH_OT_beautify_fill);
WM_operatortype_append(MESH_OT_quads_convert_to_tris);
WM_operatortype_append(MESH_OT_tris_convert_to_quads);
+ WM_operatortype_append(MESH_OT_dissolve_limited);
WM_operatortype_append(MESH_OT_edge_flip);
WM_operatortype_append(MESH_OT_faces_shade_smooth);
WM_operatortype_append(MESH_OT_faces_shade_flat);
@@ -132,7 +137,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_vertices_smooth);
WM_operatortype_append(MESH_OT_noise);
WM_operatortype_append(MESH_OT_flip_normals);
- WM_operatortype_append(MESH_OT_knife_cut);
+ //WM_operatortype_append(MESH_OT_knife_cut);
WM_operatortype_append(MESH_OT_rip);
WM_operatortype_append(MESH_OT_blend_from_shape);
WM_operatortype_append(MESH_OT_shape_propagate_to_all);
@@ -150,6 +155,14 @@ 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);
+
+ WM_operatortype_append(MESH_OT_bevel);
+
+ WM_operatortype_append(MESH_OT_select_next_loop);
+
+ WM_operatortype_append(MESH_OT_bridge_edge_loops);
#ifdef WITH_GAMEENGINE
WM_operatortype_append(MESH_OT_navmesh_make);
@@ -165,7 +178,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;
}
@@ -201,32 +214,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", FALSE);
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", FALSE);
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", FALSE);
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");
- RNA_enum_set(otmacro->ptr, "type", 4);
+ otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude_verts_indiv");
otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_enum_set(otmacro->ptr, "proportional", 0);
RNA_boolean_set(otmacro->ptr, "mirror", FALSE);
@@ -321,6 +330,7 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
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", JKEY, KM_PRESS, 0, 0);
/* use KM_CLICK because same key is used for tweaks */
kmi = WM_keymap_add_item(keymap, "MESH_OT_dupli_extrude_cursor", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0);
@@ -331,8 +341,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);
@@ -352,5 +362,6 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
}
ED_object_generic_keymap(keyconf, keymap, 3);
+ knifetool_modal_keymap(keyconf);
}
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index b94b60fc279..1b5011402fc 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -66,6 +66,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
@@ -79,14 +80,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)
{
@@ -97,16 +98,17 @@ int join_mesh_exec(bContext *C, wmOperator *op)
Mesh *me;
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 a, b, totcol, totmat=0, totedge=0, totvert=0, ok=0;
+ int totloop=0, totpoly=0, vertofs, *matmap=NULL;
+ int i, j, index, haskey=0, edgeofs, 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");
@@ -126,7 +128,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)
@@ -280,14 +283,18 @@ 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);
@@ -398,7 +405,30 @@ int join_mesh_exec(bContext *C, wmOperator *op)
mvert+= me->totvert;
}
- if(me->totface) {
+ if(me->totedge) {
+ CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
+ CustomData_copy_data(&me->edata, &edata, 0, edgeofs, me->totedge);
+
+ for(a=0; a<me->totedge; a++, medge++) {
+ medge->v1+= vertofs;
+ medge->v2+= vertofs;
+ }
+ }
+
+ if (me->totloop) {
+ if(base->object!=ob)
+ multiresModifier_prepare_join(scene, base->object, ob);
+
+ CustomData_merge(&me->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloop);
+ CustomData_copy_data(&me->ldata, &ldata, 0, loopofs, me->totloop);
+
+ for(a=0; a<me->totloop; a++, mloop++) {
+ mloop->v += vertofs;
+ mloop->e += edgeofs;
+ }
+ }
+
+ if(me->totpoly) {
/* make mapping for materials */
for(a=1; a<=base->object->totcol; a++) {
ma= give_current_material(base->object, a);
@@ -411,43 +441,23 @@ int join_mesh_exec(bContext *C, wmOperator *op)
}
}
- if(base->object!=ob)
- multiresModifier_prepare_join(scene, base->object, ob);
-
- CustomData_merge(&me->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface);
- CustomData_copy_data(&me->fdata, &fdata, 0, faceofs, me->totface);
-
- for(a=0; a<me->totface; a++, mface++) {
- mface->v1+= vertofs;
- mface->v2+= vertofs;
- mface->v3+= vertofs;
- if(mface->v4) mface->v4+= vertofs;
-
- if (matmap)
- mface->mat_nr= matmap[(int)mface->mat_nr];
- else
- mface->mat_nr= 0;
- }
-
- faceofs += me->totface;
- }
-
- if(me->totedge) {
- CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
- CustomData_copy_data(&me->edata, &edata, 0, edgeofs, me->totedge);
+ 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->totedge; a++, medge++) {
- medge->v1+= vertofs;
- medge->v2+= vertofs;
+ for(a=0; a<me->totpoly; a++, mpoly++) {
+ mpoly->loopstart += loopofs;
+ mpoly->mat_nr= matmap ? matmap[(int)mpoly->mat_nr] : 0;
}
- edgeofs += me->totedge;
+ polyofs += me->totpoly;
}
-
- /* vertofs is used to help newly added verts be reattached to their edge/face
- * (cannot be set earlier, or else reattaching goes wrong)
+
+ /* 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)
@@ -461,17 +471,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);
+ mesh_update_customdata_pointers(me, TRUE); /* BMESH_TODO, check if this arg can be failse, non urgent - campbell */
/* old material array */
for(a=1; a<=ob->totcol; a++) {
@@ -527,11 +540,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);
@@ -738,7 +751,7 @@ static intptr_t mesh_octree_find_index(MocNode **bt, MVert *mvert, float *co)
return (*bt)->index[a]-1;
}
else {
- EditVert *eve= (EditVert *)((*bt)->index[a]);
+ BMVert *eve= (BMVert *)((*bt)->index[a]);
if(compare_v3v3(eve->co, co, MOC_THRESH))
return (*bt)->index[a];
}
@@ -758,7 +771,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;
@@ -784,10 +797,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 {
@@ -819,10 +833,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));
}
}
@@ -898,9 +913,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;
@@ -918,20 +934,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)
{
intptr_t 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_VERTS_OF_MESH, NULL) {
+ if (v == eve)
+ break;
+ index++;
+ }
+
+ if (index == em->bm->totvert) {
return NULL;
}
}
@@ -939,22 +963,23 @@ static EditVert *editmesh_get_x_mirror_vert_topo(Object *ob, struct EditMesh *em
poinval= mesh_topo_store.index_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)
{
if (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_TOPO) {
- return editmesh_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_topo(ob, em, eve, index);
+ }
+ else {
+ 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)
+
+static float *editmesh_get_mirror_uv(BMEditMesh *em, int axis, float *uv, float *mirrCent, float *face_cent)
{
float vec[2];
float cent_vec[2];
@@ -982,25 +1007,30 @@ 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)
@@ -1049,7 +1079,8 @@ 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)
+/* BMESH_TODO, convert to MPoly (functions above also) */
+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 c8adfbda708..da8009ecc22 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -516,7 +516,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 *UNUSED(obe))
{
ListBase *lb= lbu;
ListBase *editelems= lbe;
@@ -534,7 +534,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 *UNUSED(obe))
{
ListBase *editelems= lbe;
ListBase *lb;
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index e7232524a21..05c042a4182 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenkernel
../../blenlib
../../blenloader
+ ../../bmesh
../../gpu
../../ikplugin
../../imbuf
diff --git a/source/blender/editors/object/SConscript b/source/blender/editors/object/SConscript
index d4739236ba1..883d0ca20ae 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
incs += ' #extern/recastnavigation'
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index dce2179db24..1b289732302 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -250,7 +250,7 @@ int ED_object_add_generic_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(ev
}
int ED_object_add_generic_get_opts(bContext *C, wmOperator *op, float *loc,
- float *rot, int *enter_editmode, unsigned int *layer)
+ float *rot, int *enter_editmode, unsigned int *layer, int *is_view_aligned)
{
View3D *v3d = CTX_wm_view3d(C);
int a, layer_values[20];
@@ -298,7 +298,9 @@ int ED_object_add_generic_get_opts(bContext *C, wmOperator *op, float *loc,
else
RNA_float_get_array(op->ptr, "rotation", rot);
-
+ if (is_view_aligned)
+ *is_view_aligned = view_align;
+
RNA_float_get_array(op->ptr, "location", loc);
if(*layer == 0) {
@@ -352,7 +354,7 @@ static int object_add_exec(bContext *C, wmOperator *op)
unsigned int layer;
float loc[3], rot[3];
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
+ if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
ED_object_add_type(C, RNA_enum_get(op->ptr, "type"), loc, rot, enter_editmode, layer);
@@ -409,7 +411,7 @@ static Object *effector_add_type(bContext *C, wmOperator *op, int type)
object_add_generic_invoke_options(C, op);
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
+ if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL))
return NULL;
if(type==PFIELD_GUIDE) {
@@ -489,7 +491,7 @@ static int object_camera_add_exec(bContext *C, wmOperator *op)
object_add_generic_invoke_options(C, op);
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
+ if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
ob= ED_object_add_type(C, OB_CAMERA, loc, rot, FALSE, layer);
@@ -543,7 +545,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
object_add_generic_invoke_options(C, op); // XXX these props don't get set right when only exec() is called
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
+ if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
if(obedit==NULL || obedit->type!=OB_MBALL) {
@@ -612,7 +614,7 @@ static int object_add_text_exec(bContext *C, wmOperator *op)
float loc[3], rot[3];
object_add_generic_invoke_options(C, op); // XXX these props don't get set right when only exec() is called
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
+ if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
if(obedit && obedit->type==OB_FONT)
@@ -653,7 +655,7 @@ static int object_armature_add_exec(bContext *C, wmOperator *op)
float loc[3], rot[3];
object_add_generic_invoke_options(C, op); // XXX these props don't get set right when only exec() is called
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
+ if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
if ((obedit==NULL) || (obedit->type != OB_ARMATURE)) {
@@ -721,7 +723,7 @@ static int object_lamp_add_exec(bContext *C, wmOperator *op)
float loc[3], rot[3];
object_add_generic_invoke_options(C, op);
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
+ if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
ob= ED_object_add_type(C, OB_LAMP, loc, rot, FALSE, layer);
@@ -777,7 +779,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
float loc[3], rot[3];
object_add_generic_invoke_options(C, op);
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
+ if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
if(group) {
@@ -809,7 +811,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
object_add_generic_invoke_options(C, op);
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
+ if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
ob= ED_object_add_type(C, OB_SPEAKER, loc, rot, FALSE, layer);
@@ -1368,7 +1370,9 @@ static int convert_exec(bContext *C, wmOperator *op)
dm= mesh_get_derived_final(scene, newob, CD_MASK_MESH);
/* dm= mesh_create_derived_no_deform(ob1, NULL); this was called original (instead of get_derived). man o man why! (ton) */
- DM_to_mesh(dm, newob->data);
+ DM_to_mesh(dm, newob->data, newob);
+
+ /* re-tesselation is called by DM_to_mesh */
dm->release(dm);
object_free_modifiers(newob); /* after derivedmesh calls! */
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index d325b49c211..5f3a7cfe93b 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -367,16 +367,16 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image* ima, MPassKnownData
DerivedMesh *dm= bkr->lores_dm;
ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
const int lvl= bkr->lvl;
- const int tot_face= dm->getNumFaces(dm);
+ const int tot_face= dm->getNumTessFaces(dm);
MVert *mvert= dm->getVertArray(dm);
- MFace *mface= dm->getFaceArray(dm);
- MTFace *mtface= dm->getFaceDataArray(dm, CD_MTFACE);
+ MFace *mface= dm->getTessFaceArray(dm);
+ MTFace *mtface= dm->getTessFaceDataArray(dm, CD_MTFACE);
float *pvtangent= NULL;
if(CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1)
DM_add_tangent_layer(dm);
- pvtangent= DM_get_face_data_layer(dm, CD_TANGENT);
+ pvtangent= DM_get_tessface_data_layer(dm, CD_TANGENT);
if(tot_face > 0) { /* sanity check */
int f= 0;
@@ -387,7 +387,7 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image* ima, MPassKnownData
data.mvert= mvert;
data.mtface= mtface;
data.pvtangent= pvtangent;
- data.precomputed_normals= dm->getFaceDataArray(dm, CD_NORMAL); /* don't strictly need this */
+ data.precomputed_normals= dm->getTessFaceDataArray(dm, CD_NORMAL); /* don't strictly need this */
data.w= ibuf->x;
data.h= ibuf->y;
data.lores_dm= dm;
@@ -514,7 +514,7 @@ static void get_ccgdm_data(DerivedMesh *lodm, DerivedMesh *hidm, const int *orig
int grid_size, S, face_side;
int *grid_offset, g_index;
- lodm->getFace(lodm, face_index, &mface);
+ lodm->getTessFace(lodm, face_index, &mface);
grid_size= hidm->getGridSize(hidm);
grid_data= hidm->getGridData(hidm);
@@ -619,7 +619,7 @@ static void *init_heights_data(MultiresBakeRender *bkr, Image *ima)
height_data->ssdm= subsurf_make_derived_from_derived(bkr->lores_dm, &smd, 0, NULL, 0, 0, 0);
}
- height_data->origindex= lodm->getFaceDataArray(lodm, CD_ORIGINDEX);
+ height_data->origindex= lodm->getTessFaceDataArray(lodm, CD_ORIGINDEX);
return (void*)height_data;
}
@@ -631,7 +631,7 @@ static void *init_normal_data(MultiresBakeRender *bkr, Image *UNUSED(ima))
normal_data= MEM_callocN(sizeof(MNormalBakeData), "MultiresBake normalData");
- normal_data->origindex= lodm->getFaceDataArray(lodm, CD_ORIGINDEX);
+ normal_data->origindex= lodm->getTessFaceDataArray(lodm, CD_ORIGINDEX);
return (void*)normal_data;
}
@@ -709,7 +709,7 @@ static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm,
int pixel= ibuf->x*y + x;
float vec[3], p0[3], p1[3], n[3], len;
- lores_dm->getFace(lores_dm, face_index, &mface);
+ lores_dm->getTessFace(lores_dm, face_index, &mface);
st0= mtface[face_index].uv[0];
st1= mtface[face_index].uv[1];
@@ -729,7 +729,7 @@ static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm,
if(height_data->ssdm) {
get_ccgdm_data(lores_dm, height_data->ssdm, height_data->origindex, 0, face_index, uv[0], uv[1], p0, n);
} else {
- lores_dm->getFace(lores_dm, face_index, &mface);
+ lores_dm->getTessFace(lores_dm, face_index, &mface);
if(mface.v4) {
interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 1, p0);
@@ -776,7 +776,7 @@ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm,
int pixel= ibuf->x*y + x;
float n[3], vec[3], tmp[3]= {0.5, 0.5, 0.5};
- lores_dm->getFace(lores_dm, face_index, &mface);
+ lores_dm->getTessFace(lores_dm, face_index, &mface);
st0= mtface[face_index].uv[0];
st1= mtface[face_index].uv[1];
@@ -822,7 +822,7 @@ static void count_images(MultiresBakeRender *bkr)
bkr->image.first= bkr->image.last= NULL;
bkr->tot_image= 0;
- totface= dm->getNumFaces(dm);
+ totface= dm->getNumTessFaces(dm);
for(a= 0; a<totface; a++)
mtface[a].tpage->id.flag&= ~LIB_DOIT;
@@ -949,6 +949,7 @@ static int multiresbake_check(bContext *C, wmOperator *op)
ok= 0;
} else {
+ /* BMESH_TODO - use MPoly rather then tessface */
a= me->totface;
while (ok && a--) {
Image *ima= me->mtface[a].tpage;
@@ -995,7 +996,9 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l
*lvl= mmd->lvl;
if(*lvl==0) {
- return NULL;
+ DerivedMesh *tmp_dm= CDDM_from_mesh(me, ob);
+ dm= CDDM_copy(tmp_dm);
+ tmp_dm->release(tmp_dm);
} else {
MultiresModifierData tmp_mmd= *mmd;
DerivedMesh *cddm= CDDM_from_mesh(me, ob);
@@ -1157,7 +1160,7 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa
DerivedMesh *dm= data->lores_dm;
MTFace *mtface= CustomData_get_layer(&dm->faceData, CD_MTFACE);
- clear_images(mtface, dm->getNumFaces(dm));
+ clear_images(mtface, dm->getNumTessFaces(dm));
}
}
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 1286ac850f6..a28b5c4feaa 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -79,6 +79,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"
@@ -321,18 +322,18 @@ void ED_object_exit_editmode(bContext *C, int flag)
// if(EM_texFaceCheck())
- 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(obedit->restore_mode & OB_MODE_WEIGHT_PAINT) {
mesh_octree_table(NULL, NULL, NULL, 'e');
mesh_mirrtopo_table(NULL, 'e');
@@ -442,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);
}
@@ -1004,7 +1005,10 @@ static void UNUSED_FUNCTION(copy_attr_menu)(Main *bmain, Scene *scene, View3D *v
* view3d_edit_object_copyattrmenu() and in toolbox.c
*/
- strcpy(str, "Copy Attributes %t|Location%x1|Rotation%x2|Size%x3|Draw Options%x4|Time Offset%x5|Dupli%x6|Object Color%x31|%l|Mass%x7|Damping%x8|All Physical Attributes%x11|Properties%x9|Logic Bricks%x10|Protected Transform%x29|%l");
+ strcpy(str,
+ "Copy Attributes %t|Location%x1|Rotation%x2|Size%x3|Draw Options%x4|"
+ "Time Offset%x5|Dupli%x6|Object Color%x31|%l|Mass%x7|Damping%x8|All Physical Attributes%x11|Properties%x9|"
+ "Logic Bricks%x10|Protected Transform%x29|%l");
strcat (str, "|Object Constraints%x22");
strcat (str, "|NLA Strips%x26");
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index de991f28e4a..2083c51efa9 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -55,6 +55,7 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_deform.h"
+#include "BKE_tessmesh.h"
#include "RNA_define.h"
#include "RNA_access.h"
@@ -71,13 +72,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_elem_flag_test(eve, BM_ELEM_SELECT)) totvert++;
}
if(totvert==0) return 0;
@@ -86,8 +88,8 @@ static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float
nr= 0;
zero_v3(cent);
- 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_elem_flag_test(eve, BM_ELEM_SELECT)) {
*index= nr; index++;
add_v3_v3(cent, eve->co);
}
@@ -99,7 +101,7 @@ 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)
{
zero_v3(cent);
@@ -108,11 +110,12 @@ static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, floa
int totvert=0;
MDeformVert *dvert;
- EditVert *eve;
+ BMVert *eve;
+ BMIter iter;
/* 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) {
if(defvert_find_weight(dvert, defgrp_index) > 0.0f) {
@@ -132,25 +135,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_elem_select_set(em->bm, eve, TRUE);
if(index < hmd->totindex-1) index++;
}
+
+ nr++;
}
- EM_select_flush(em);
- BKE_mesh_end_editmesh(me, em);
+ EDBM_select_flush(em);
}
static int return_editlattice_indexar(Lattice *editlatt, int *tot, int **indexar, float *cent)
@@ -300,20 +305,19 @@ static int object_hook_index_array(Scene *scene, Object *obedit, int *tot, int *
case OB_MESH:
{
Mesh *me= obedit->data;
- EditMesh *em;
- load_editMesh(scene, obedit);
- make_editMesh(scene, obedit);
+ BMEditMesh *em;
- em = BKE_mesh_get_editmesh(me);
+ EDBM_LoadEditBMesh(scene, obedit);
+ EDBM_MakeEditBMesh(scene->toolsettings, scene, obedit);
+
+ 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;
}
}
@@ -382,7 +386,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);
@@ -742,6 +746,7 @@ void OBJECT_OT_hook_recenter(wmOperatorType *ot)
static int object_hook_assign_exec(bContext *C, wmOperator *op)
{
+ Scene *scene= CTX_data_scene(C);
PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
int num= RNA_enum_get(op->ptr, "modifier");
Object *ob=NULL;
@@ -765,7 +770,7 @@ static int object_hook_assign_exec(bContext *C, wmOperator *op)
/* assign functionality */
- if(!object_hook_index_array(CTX_data_scene(C), ob, &tot, &indexar, name, cent)) {
+ if(!object_hook_index_array(scene, ob, &tot, &indexar, name, cent)) {
BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group");
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 73c5c50f448..526706b566d 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -159,6 +159,7 @@ void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot);
void OBJECT_OT_meshdeform_bind(struct wmOperatorType *ot);
void OBJECT_OT_explode_refresh(struct wmOperatorType *ot);
void OBJECT_OT_ocean_bake(struct wmOperatorType *ot);
+void OBJECT_OT_test_multires(struct wmOperatorType *ot);
/* object_constraint.c */
void OBJECT_OT_constraint_add(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c
index cac167ad84f..9f3bc9bbf37 100644
--- a/source/blender/editors/object/object_lattice.c
+++ b/source/blender/editors/object/object_lattice.c
@@ -366,7 +366,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 *UNUSED(obdata))
{
UndoLattice *ult= (UndoLattice*)data;
EditLatt *editlatt= (EditLatt *)edata;
@@ -375,7 +375,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 *UNUSED(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 ed5899d81a8..e8a09732313 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -68,6 +68,7 @@
#include "BKE_ocean.h"
#include "BKE_particle.h"
#include "BKE_softbody.h"
+#include "BKE_tessmesh.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -214,15 +215,15 @@ static int object_modifier_remove(Object *ob, ModifierData *md, int *sort_depsgr
}
if(ok) {
- 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_data_layer_free(em->bm, &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);
}
}
}
@@ -446,6 +447,17 @@ static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, M
return 0;
}
+ /*
+ 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;
@@ -457,7 +469,7 @@ static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, M
return 0;
}
- dm = mesh_create_derived_for_modifier(scene, ob, md);
+ dm = mesh_create_derived_for_modifier(scene, ob, md, 0);
if (!dm) {
BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply");
return 0;
@@ -515,19 +527,19 @@ static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob,
return 0;
}
} else {
- dm = mesh_create_derived_for_modifier(scene, ob, md);
+ dm = mesh_create_derived_for_modifier(scene, ob, md, 1);
if (!dm) {
BKE_report(reports, RPT_ERROR, "Modifier returned error, skipping apply");
return 0;
}
- DM_to_mesh(dm, me);
+ DM_to_mesh(dm, me, ob);
dm->release(dm);
if(md->type == eModifierType_Multires) {
- 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);
}
}
}
@@ -1165,6 +1177,66 @@ void OBJECT_OT_multires_reshape(wmOperatorType *ot)
edit_modifier_properties(ot);
}
+static int multires_test_exec(bContext *C, wmOperator *op)
+{
+ Object *ob= ED_object_active_context(C);
+ Mesh *me = ob->data;
+ MPoly *mp;
+ MDisps *mdisps;
+ int i, x = RNA_int_get(op->ptr, "x"), y = RNA_int_get(op->ptr, "y");
+
+ if (ob->type != OB_MESH || !me)
+ return OPERATOR_CANCELLED;
+
+ mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
+ if (!mdisps)
+ return OPERATOR_CANCELLED;
+
+ mp = me->mpoly;
+ for (i=0; i<me->totpoly; i++, mp++) {
+ MLoop *ml;
+ int j;
+
+ ml = me->mloop + mp->loopstart;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ MLoop *ml_prev = ME_POLY_LOOP_PREV(me->mloop, mp, j);
+ MLoop *ml_next = ME_POLY_LOOP_NEXT(me->mloop, mp, j);
+
+ if ((me->mvert[ml->v].flag&SELECT) && (me->mvert[ml_prev->v].flag&SELECT) && (me->mvert[ml_next->v].flag&SELECT)) {
+ MDisps *md = mdisps + mp->loopstart + j;
+ int res = sqrt(md->totdisp);
+
+ if (x >= res) x = res-1;
+ if (y >= res) y = res-1;
+
+ md->disps[y*res + x][2] += 1.0;
+ }
+ }
+ }
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_test_multires(wmOperatorType *ot)
+{
+ ot->name= "Multires Object Mode Test";
+ ot->description= "";
+ ot->idname= "OBJECT_OT_test_multires";
+
+ ot->poll= multires_poll;
+ ot->exec= multires_test_exec;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ RNA_def_int(ot->srna, "x", 0, 0, 100, "x", "x", 0, 100);
+ RNA_def_int(ot->srna, "y", 0, 0, 100, "y", "y", 0, 100);
+}
+
+
+
/****************** multires save external operator *********************/
static int multires_external_save_exec(bContext *C, wmOperator *op)
@@ -1177,7 +1249,7 @@ static int multires_external_save_exec(bContext *C, wmOperator *op)
if(!me)
return OPERATOR_CANCELLED;
- if(CustomData_external_test(&me->fdata, CD_MDISPS))
+ if(CustomData_external_test(&me->ldata, CD_MDISPS))
return OPERATOR_CANCELLED;
RNA_string_get(op->ptr, "filepath", path);
@@ -1185,8 +1257,8 @@ static int multires_external_save_exec(bContext *C, wmOperator *op)
if(relative)
BLI_path_rel(path, G.main->name);
- CustomData_external_add(&me->fdata, &me->id, CD_MDISPS, me->totface, path);
- CustomData_external_write(&me->fdata, &me->id, CD_MASK_MESH, me->totface, 0);
+ CustomData_external_add(&me->ldata, &me->id, CD_MDISPS, me->totloop, path);
+ CustomData_external_write(&me->ldata, &me->id, CD_MASK_MESH, me->totloop, 0);
return OPERATOR_FINISHED;
}
@@ -1206,7 +1278,7 @@ static int multires_external_save_invoke(bContext *C, wmOperator *op, wmEvent *U
if (!mmd)
return OPERATOR_CANCELLED;
- if(CustomData_external_test(&me->fdata, CD_MDISPS))
+ if(CustomData_external_test(&me->ldata, CD_MDISPS))
return OPERATOR_CANCELLED;
if(RNA_struct_property_is_set(op->ptr, "filepath"))
@@ -1247,11 +1319,11 @@ static int multires_external_pack_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = ED_object_active_context(C);
Mesh *me= ob->data;
- if(!CustomData_external_test(&me->fdata, CD_MDISPS))
+ if(!CustomData_external_test(&me->ldata, CD_MDISPS))
return OPERATOR_CANCELLED;
// XXX don't remove..
- CustomData_external_remove(&me->fdata, &me->id, CD_MDISPS, me->totface);
+ CustomData_external_remove(&me->ldata, &me->id, CD_MDISPS, me->totloop);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 09ae6365363..542b75e1f19 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -214,8 +214,9 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_bake_image);
WM_operatortype_append(OBJECT_OT_drop_named_material);
-}
+ WM_operatortype_append(OBJECT_OT_test_multires);
+}
void ED_operatormacros_object(void)
{
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 37461377506..f64f25391f9 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -79,6 +79,7 @@
#include "BKE_scene.h"
#include "BKE_speaker.h"
#include "BKE_texture.h"
+#include "BKE_tessmesh.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -94,9 +95,9 @@
#include "ED_curve.h"
#include "ED_keyframing.h"
#include "ED_object.h"
+#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_view3d.h"
-#include "ED_mesh.h"
#include "object_intern.h"
@@ -112,7 +113,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;
@@ -124,20 +126,19 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
if(obedit->type==OB_MESH) {
Mesh *me= obedit->data;
- EditMesh *em;
+ BMEditMesh *em;
- load_editMesh(scene, obedit);
- make_editMesh(scene, obedit);
+ EDBM_LoadEditBMesh(scene, obedit);
+ EDBM_MakeEditBMesh(scene->toolsettings, scene, obedit);
- em= BKE_mesh_get_editmesh(me);
+ em= me->edit_btmesh;
/* derivedMesh might be needed for solving parenting,
so re-create it here */
- makeDerivedMesh(scene, obedit, em, CD_MASK_BAREMESH);
+ makeDerivedMesh(scene, obedit, em, CD_MASK_BAREMESH, 0);
- eve= em->verts.first;
- while(eve) {
- if(eve->f & 1) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
if(v1==0) v1= nr;
else if(v2==0) v2= nr;
else if(v3==0) v3= nr;
@@ -145,10 +146,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
else break;
}
nr++;
- eve= eve->next;
}
-
- BKE_mesh_end_editmesh(me, em);
}
else if(ELEM(obedit->type, OB_SURF, OB_CURVE)) {
ListBase *editnurb= object_editcurve_get(obedit);
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index e57574af839..68c017adecd 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -51,6 +51,7 @@
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "BKE_tessmesh.h"
#include "BKE_multires.h"
#include "BKE_armature.h"
@@ -479,7 +480,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, int apply_lo
}
/* update normals */
- mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+ mesh_calc_normals_mapping(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL);
}
else if (ob->type==OB_ARMATURE) {
ED_armature_apply_transform(ob, mat);
@@ -656,37 +657,37 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
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);
+ 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);
+ }
}
}
- else {
- for(eve= em->verts.first; eve; eve= eve->next) {
- DO_MINMAX(eve->co, min, max);
- }
- mid_v3_v3v3(cent, min, max);
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ sub_v3_v3(eve->co, cent);
}
- 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);
- }
- 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 7fe98a604ec..78d90bb39d2 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -41,6 +41,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"
@@ -49,7 +50,6 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
-#include "BLI_editVert.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
@@ -58,6 +58,7 @@
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
+#include "BKE_tessmesh.h"
#include "BKE_report.h"
#include "BKE_DerivedMesh.h"
@@ -90,7 +91,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);
@@ -187,31 +188,33 @@ 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)) {
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;
-
if (use_vert_sel) {
- for (eve=em->verts.first; eve; eve=eve->next, i++) {
- (*dvert_arr)[i] = (eve->f & SELECT) ?
- CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT) : NULL;
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ (*dvert_arr)[i] = BM_elem_flag_test(eve, BM_ELEM_SELECT) ?
+ CustomData_em_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT) : NULL;
+ i++;
}
}
else {
- 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++;
}
}
@@ -511,19 +514,19 @@ void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum)
{
MDeformVert *dv= NULL;
- EditVert *eve;
+ BMVert *eve;
Mesh *me;
/* get the deform vertices corresponding to the 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= BM_vert_at_index(me->edit_btmesh->bm, vertnum);
if(!eve) {
return 0.0f;
}
- dv= CustomData_em_get(&me->edit_mesh->vdata, eve->data, CD_MDEFORMVERT);
+ dv= CustomData_bmesh_get(&me->edit_btmesh->bm->vdata, eve->head.data, CD_MDEFORMVERT);
}
else {
if(vertnum >= me->totvert) {
@@ -584,24 +587,23 @@ static void vgroup_select_verts(Object *ob, int select)
if(ob->type == OB_MESH) {
Mesh *me= ob->data;
- if (me->edit_mesh) {
- EditMesh *em = BKE_mesh_get_editmesh(me);
- EditVert *eve;
+ if (me->edit_btmesh) {
+ BMEditMesh *em = me->edit_btmesh;
+ BMIter iter;
+ BMVert *eve;
- for (eve=em->verts.first; eve; eve=eve->next) {
- if (!eve->h) {
- dv= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ dv= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
if (defvert_find_index(dv, def_nr)) {
- if (select) eve->f |= SELECT;
- else eve->f &= ~SELECT;
+ BM_elem_select_set(em->bm, eve, select);
}
}
}
- /* 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);
+ /* this has to be called, because this function operates on vertices only */
+ if(select) EDBM_select_flush(em); // vertices to edges/faces
+ else EDBM_deselect_flush(em);
}
else {
if (me->dvert) {
@@ -776,6 +778,8 @@ static int tryToAddVerts(int *verts, int length, int a, int b)
return added;
}
+/* BMESH_TODO - use MPoly's */
+
/* This finds all of the vertices connected to vert by an edge
and returns an array of indices of size count
@@ -1284,51 +1288,51 @@ static void vgroup_blend(Object *ob)
int i, dvert_tot=0;
const int def_nr= ob->actdef-1;
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)ob->data));
+ BMEditMesh *em= ((Mesh *)ob->data)->edit_btmesh;
// ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
if (em==NULL)
return;
if (BLI_findlink(&ob->defbase, def_nr)) {
- int sel1, sel2;
+ BMEdge *eed;
+ BMVert *eve;
+ BMIter iter;
+
int i1, i2;
- EditEdge *eed;
- EditVert *eve;
float *vg_weights;
float *vg_users;
+ int sel1, sel2;
- i= 0;
- for(eve= em->verts.first; eve; eve= eve->next)
- eve->tmp.l= i++;
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
- dvert_tot= i;
+ dvert_tot= em->bm->totvert;
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_elem_flag_test(eed->v1, BM_ELEM_SELECT);
+ sel2= BM_elem_flag_test(eed->v2, BM_ELEM_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= BM_elem_index_get(eed->v1);
+ i2= BM_elem_index_get(eed->v2);
eve= eed->v2;
}
else {
- i2= eed->v1->tmp.l;
- i1= eed->v2->tmp.l;
+ i2= BM_elem_index_get(eed->v1);
+ i1= BM_elem_index_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);
@@ -1340,10 +1344,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_elem_flag_test(eve, BM_ELEM_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);
@@ -1511,7 +1515,7 @@ void ED_vgroup_mirror(Object *ob, const short mirror_weights, const short flip_v
all_vgroups, def_nr \
)
- EditVert *eve, *eve_mirr;
+ BMVert *eve, *eve_mirr;
MDeformVert *dvert, *dvert_mirr;
short sel, sel_mirr;
int *flip_map, flip_map_len;
@@ -1543,33 +1547,37 @@ void ED_vgroup_mirror(Object *ob, const short mirror_weights, const short flip_v
/* 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;
if (em) {
- if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
+ BMIter iter;
+
+ if(!CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) {
goto cleanup;
}
- EM_cache_x_mirror_vert(ob, em);
+ EDBM_CacheMirrorVerts(em, FALSE);
/* Go through the list of editverts and assign them */
- for(eve=em->verts.first; eve; eve=eve->next){
- if((eve_mirr=eve->tmp.v)) {
- sel= eve->f & SELECT;
- sel_mirr= eve_mirr->f & SELECT;
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if((eve_mirr= EDBM_GetMirrorVert(em, eve))) {
+ sel= BM_elem_flag_test(eve, BM_ELEM_SELECT);
+ sel_mirr= BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT);
if((sel || sel_mirr) && (eve != eve_mirr)) {
- dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
- dvert_mirr= CustomData_em_get(&em->vdata, eve_mirr->data, CD_MDEFORMVERT);
+ dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
+ dvert_mirr= CustomData_bmesh_get(&em->bm->vdata, eve_mirr->head.data, CD_MDEFORMVERT);
if(dvert && dvert_mirr) {
VGROUP_MIRR_OP;
}
}
- eve->tmp.v= eve_mirr->tmp.v= NULL;
+ /* don't use these again */
+ EDBM_ClearMirrorVert(em, eve);
+ EDBM_ClearMirrorVert(em, eve_mirr);
}
}
- BKE_mesh_end_editmesh(me, em);
+ EDBM_EndMirrorCache(em);
}
else {
/* object mode / weight paint */
@@ -1771,19 +1779,19 @@ static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGr
if(ob->type == OB_MESH) {
Mesh *me= ob->data;
- if (me->edit_mesh) {
- EditVert *eve;
- EditMesh *em = BKE_mesh_get_editmesh(me);
+ if (me->edit_btmesh) {
+ BMEditMesh *em = me->edit_btmesh;
+ BMVert *eve;
+ BMIter iter;
- for (eve=em->verts.first; eve; eve=eve->next) {
- dv= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ dv= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
- if (dv && dv->dw && (allverts || (eve->f & SELECT))) {
+ if(dv && dv->dw && (allverts || BM_elem_flag_test(eve, BM_ELEM_SELECT))) {
MDeformWeight *dw = defvert_find_index(dv, def_nr);
defvert_remove_group(dv, dw); /* dw can be NULL */
}
}
- BKE_mesh_end_editmesh(me, em);
}
else {
MVert *mv;
@@ -1841,19 +1849,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);
@@ -1903,7 +1911,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);
@@ -1915,7 +1923,7 @@ static int vgroup_object_in_wpaint_vert_select(Object *ob)
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
return ( (ob->mode & OB_MODE_WEIGHT_PAINT) &&
- (me->edit_mesh == NULL) &&
+ (me->edit_btmesh == NULL) &&
(ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX) );
}
@@ -1968,25 +1976,26 @@ static void vgroup_assign_verts(Object *ob, const float weight)
if(ob->type == OB_MESH) {
Mesh *me= ob->data;
- if (me->edit_mesh) {
- EditMesh *em = BKE_mesh_get_editmesh(me);
- EditVert *eve;
- if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT))
- EM_add_data_layer(em, &em->vdata, CD_MDEFORMVERT, NULL);
+ if (me->edit_btmesh) {
+ BMEditMesh *em = me->edit_btmesh;
+ BMIter iter;
+ BMVert *eve;
+
+ if(!CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT))
+ BM_data_layer_add(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) {
- if (eve->f & SELECT) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
MDeformWeight *dw;
- dv= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); /* can be NULL */
+ dv= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); /* can be NULL */
dw= defvert_verify_index(dv, def_nr);
if (dw) {
dw->weight= weight;
}
}
}
- BKE_mesh_end_editmesh(me, em);
}
else {
MVert *mv;
@@ -2795,11 +2804,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, defbase_tot);
}
diff --git a/source/blender/editors/physics/SConscript b/source/blender/editors/physics/SConscript
index 188416eb04c..a478b2afb1c 100644
--- a/source/blender/editors/physics/SConscript
+++ b/source/blender/editors/physics/SConscript
@@ -5,7 +5,7 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
-incs += ' ../../gpu ../../blenloader'
+incs += ' ../../gpu ../../blenloader ../../bmesh'
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 dbf03e34c32..5648bc69099 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -1064,7 +1064,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");
@@ -1075,7 +1075,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);
@@ -2563,7 +2563,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
PTCacheEditPoint *newpoint, *new_points;
POINT_P; KEY_K;
HairKey *hkey;
- int *mirrorfaces;
+ int *mirrorfaces = NULL;
int rotation, totpart, newtotpart;
if(psys->flag & PSYS_GLOBAL_HAIR)
@@ -3067,6 +3067,8 @@ static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm,
return 0;
}
+ /* BMESH_ONLY, deform dm may not have tessface */
+ DM_ensure_tessface(dm);
if(pa_minmax==0){
@@ -3079,8 +3081,8 @@ static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm,
copy_v3_v3(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 */
@@ -3472,7 +3474,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
view3d_operator_needs_opengl(C);
selected= (short)count_selected_keys(scene, edit);
- dmax = MAX2(fabs(dx), fabs(dy));
+ dmax = maxf(fabsf(dx), fabsf(dy));
tot_steps = dmax/(0.2f * brush->size) + 1;
dx /= (float)tot_steps;
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index b26661da4a2..da3f7e1f7c1 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -649,6 +649,10 @@ static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
else
dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
+ /* BMESH_ONLY, deform dm may not have tessface */
+ DM_ensure_tessface(dm);
+
+
numverts = dm->getNumVerts (dm);
/* convert to global coordinates */
@@ -671,7 +675,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 db3f03c5d91..c9be7d0e5e0 100644
--- a/source/blender/editors/render/CMakeLists.txt
+++ b/source/blender/editors/render/CMakeLists.txt
@@ -26,6 +26,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 e7e883f9ef6..e496e4b4373 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 ../../freestyle'
incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern'
-incs += ' ../../blenloader'
+incs += ' ../../blenloader ../../bmesh'
if env['OURPLATFORM'] == 'linux':
cflags='-pthread'
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index f31777857b1..5e0f4629e11 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -63,6 +63,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"
@@ -168,13 +169,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_elem_flag_test(efa, BM_ELEM_SELECT))
efa->mat_nr= ob->actcol-1;
+ }
}
}
else if(ELEM(ob->type, OB_CURVE, OB_SURF)) {
@@ -227,13 +230,10 @@ 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;
if(em) {
- if(select)
- EM_select_by_material(em, ob->actcol-1);
- else
- EM_deselect_by_material(em, ob->actcol-1);
+ EDBM_deselect_by_material(em, ob->actcol-1, select);
}
}
else if ELEM(ob->type, OB_CURVE, OB_SURF) {
diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt
index 3614052684c..79a805cfa6e 100644
--- a/source/blender/editors/screen/CMakeLists.txt
+++ b/source/blender/editors/screen/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenkernel
../../blenlib
../../blenloader
+ ../../bmesh
../../imbuf
../../makesdna
../../makesrna
diff --git a/source/blender/editors/screen/SConscript b/source/blender/editors/screen/SConscript
index 1381c820224..ade26a0b80f 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_ops.c b/source/blender/editors/screen/screen_ops.c
index 2c652df93a0..22bac3a6699 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -55,6 +55,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"
@@ -314,7 +315,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;
}
@@ -367,18 +368,15 @@ int ED_operator_uvedit(bContext *C)
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;
}
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 9fa91af7aec..8a6a236d10f 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenkernel
../../blenlib
../../blenloader
+ ../../bmesh
../../gpu
../../imbuf
../../makesdna
diff --git a/source/blender/editors/sculpt_paint/SConscript b/source/blender/editors/sculpt_paint/SConscript
index dd82e01240b..8669ea6c695 100644
--- a/source/blender/editors/sculpt_paint/SConscript
+++ b/source/blender/editors/sculpt_paint/SConscript
@@ -8,7 +8,7 @@ defs = []
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../render/extern/include'
-incs += ' ../../gpu ../../makesrna ../../blenloader ../uvedit'
+incs += ' ../../gpu ../../makesrna ../../blenloader ../../bmesh ../uvedit'
if env['OURPLATFORM'] == 'linux':
cflags='-pthread'
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index b8b36954e22..681ab3a1492 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -84,6 +84,8 @@
#include "BKE_global.h"
#include "BKE_deform.h"
+#include "BKE_tessmesh.h"
+
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -2977,11 +2979,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? */
@@ -4647,7 +4649,7 @@ static int image_paint_poll(bContext *C)
static int uv_sculpt_brush_poll(bContext *C)
{
- EditMesh *em;
+ BMEditMesh *em;
int ret;
Object *obedit = CTX_data_edit_object(C);
SpaceImage *sima= CTX_wm_space_image(C);
@@ -4657,9 +4659,8 @@ static int uv_sculpt_brush_poll(bContext *C)
if(!uv_sculpt_brush(C) || !obedit || 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);
if(ret && sima) {
ARegion *ar= CTX_wm_region(C);
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 0705ea29985..70293765813 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -250,9 +250,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, const int xy[2], float uv[2])
{
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
- const int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
- MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf;
- int numfaces = dm->getNumFaces(dm), a, findex;
+ const 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];
@@ -265,7 +265,7 @@ void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const in
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 941e885c143..4ce304a62c4 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -43,6 +43,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_memarena.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -85,15 +86,45 @@
#include "paint_intern.h"
-/* polling - retrieve whether cursor should be set or operator should be done */
+/* check if we can do partial updayes and have them draw realtime
+ * (without rebuilding the 'derivedFinal') */
+static int vertex_paint_use_fast_update_check(Object *ob)
+{
+ DerivedMesh *dm = ob->derivedFinal;
+
+ if (dm) {
+ Mesh *me = get_mesh(ob);
+ if (me && me->mcol) {
+ return (me->mcol == CustomData_get_layer(&dm->faceData, CD_MCOL));
+ }
+ }
+
+ return FALSE;
+}
+
+/* if the polygons from the mesh and the 'derivedFinal' match
+ * we can assume that no modifiers are applied and that its worth adding tesselated faces
+ * so 'vertex_paint_use_fast_update_check()' returns TRUE */
+static int vertex_paint_use_tessface_check(Object *ob)
+{
+ DerivedMesh *dm = ob->derivedFinal;
+
+ if (dm) {
+ Mesh *me = get_mesh(ob);
+ return (me->mpoly == CustomData_get_layer(&dm->faceData, CD_MPOLY));
+ }
+
+ return FALSE;
+}
+/* polling - retrieve whether cursor should be set or operator should be done */
/* Returns true if vertex paint mode is active */
int vertex_paint_mode_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
- return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totface;
+ return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totpoly;
}
int vertex_paint_poll(bContext *C)
@@ -114,7 +145,7 @@ int weight_paint_mode_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
- return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totface;
+ return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totpoly;
}
int weight_paint_poll(bContext *C)
@@ -150,7 +181,7 @@ static VPaint *new_vpaint(int wpaint)
static int *get_indexarray(Mesh *me)
{
- return MEM_mallocN(sizeof(int)*(me->totface+1), "vertexpaint");
+ return MEM_mallocN(sizeof(int)*(me->totpoly+1), "vertexpaint");
}
@@ -188,7 +219,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,25 +285,109 @@ static void do_shared_vertexcol(Mesh *me)
MEM_freeN(scolmain);
}
+void do_shared_vertexcol(Mesh *me, int do_tessface)
+{
+ MLoop *ml = me->mloop;
+ MLoopCol *lcol = me->mloopcol;
+ MTexPoly *mtp = me->mtpoly;
+ MPoly *mp = me->mpoly;
+ float (*scol)[5];
+ int i, has_shared = 0;
+
+ /* 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)) && (me->editflag & ME_EDIT_PAINT_MASK)!=0)
+ 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;
+ has_shared = 1;
+ }
+
+ if (has_shared) {
+ 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);
+
+ if (has_shared && do_tessface) {
+ 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==NULL) 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->mloopcol) {
+ 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, TRUE);
+ }
+
+ if (vertex_paint_use_tessface_check(ob)) {
+ /* assume if these exist, that they are up to date & valid */
+ if (!me->mcol || !me->mface) {
+ /* should always be true */
+ if (me->mcol) {
+ memset(me->mcol, 255, 4*sizeof(MCol)*me->totface);
+ }
+
+ /* create tessfaces because they will be used for drawing & fast updates*/
+ BKE_mesh_tessface_calc(me); /* does own call to update pointers */
+ }
+ }
+ else {
+ if (me->totface) {
+ /* this wont be used, theres no need to keep it */
+ BKE_mesh_tessface_clear(me);
+ }
}
//if(shade)
// shadeMeshMCol(scene, ob, me);
//else
-
- memset(me->mcol, 255, 4*sizeof(MCol)*me->totface);
DAG_id_tag_update(&me->id, 0);
@@ -314,7 +429,7 @@ static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
return -1;
}
-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);
@@ -322,10 +437,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);
}
@@ -348,30 +463,34 @@ static void copy_wpaint_prev (VPaint *wp, MDeformVert *dverts, int dcount)
void vpaint_fill(Object *ob, unsigned int paintcol)
{
Mesh *me;
- MFace *mf;
- unsigned int *mcol;
- int i, selected;
+ MPoly *mp;
+ MLoopCol *lcol;
+ int i, j, selected;
me= get_mesh(ob);
- if(me==NULL || me->totface==0) return;
+ if(me==NULL || me->totpoly==0) return;
- if(!me->mcol) make_vertexcol(ob);
- if(!me->mcol) return; /* possible we can't make mcol's */
+ if(!me->mloopcol) make_vertexcol(ob);
+ if(!me->mloopcol) return; /* possible we can't make mcol's */
selected= (me->editflag & ME_EDIT_PAINT_MASK);
- mf = me->mface;
- mcol = (unsigned int*)me->mcol;
- for (i = 0; i < me->totface; i++, mf++, mcol+=4) {
- if (!selected || mf->flag & ME_FACE_SEL) {
- mcol[0] = paintcol;
- mcol[1] = paintcol;
- mcol[2] = 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;
}
}
+ /* remove stale me->mcol, will be added later */
+ BKE_mesh_tessface_clear(me);
+
DAG_id_tag_update(&me->id, 0);
}
@@ -380,7 +499,7 @@ void vpaint_fill(Object *ob, unsigned int paintcol)
void wpaint_fill(VPaint *wp, Object *ob, float paintweight)
{
Mesh *me= ob->data;
- MFace *mf;
+ MPoly *mf;
MDeformWeight *dw, *dw_prev;
int vgroup_active, vgroup_mirror= -1;
unsigned int index;
@@ -388,7 +507,7 @@ void wpaint_fill(VPaint *wp, Object *ob, float paintweight)
/* mutually exclusive, could be made into a */
const short paint_selmode= ME_EDIT_PAINT_SEL_MODE(me);
- if(me->totface==0 || me->dvert==NULL || !me->mface) return;
+ if(me->totpoly==0 || me->dvert==NULL || !me->mpoly) return;
vgroup_active = ob->actdef - 1;
@@ -399,15 +518,15 @@ void wpaint_fill(VPaint *wp, Object *ob, float paintweight)
copy_wpaint_prev(wp, me->dvert, me->totvert);
- for(index=0, mf= me->mface; index < me->totface; index++, mf++) {
- unsigned int fidx= mf->v4 ? 3:2;
+ for(index=0, mf= me->mpoly; index < me->totpoly; index++, mf++) {
+ unsigned int fidx= mf->totloop - 1;
if ((paint_selmode == SCE_SELECT_FACE) && !(mf->flag & ME_FACE_SEL)) {
continue;
}
do {
- unsigned int vidx= *(&mf->v1 + fidx);
+ unsigned int vidx= me->mloop[mf->loopstart + fidx].v;
if(!me->dvert[vidx].flag) {
if((paint_selmode == SCE_SELECT_VERTEX) && !(me->mvert[vidx].flag & SELECT)) {
@@ -455,7 +574,7 @@ void wpaint_fill(VPaint *wp, Object *ob, float paintweight)
}
/* XXX: should be re-implemented as a vertex/weight paint 'color correct' operator
-
+
void vpaint_dogamma(Scene *scene)
{
VPaint *vp= scene->toolsettings->vpaint;
@@ -473,12 +592,12 @@ void vpaint_dogamma(Scene *scene)
igam= 1.0/vp->gamma;
for(a=0; a<256; a++) {
-
+
fac= ((float)a)/255.0;
fac= vp->mul*pow( fac, igam);
-
+
temp= 255.9*fac;
-
+
if(temp<=0) gamtab[a]= 0;
else if(temp>=255) gamtab[a]= 255;
else gamtab[a]= temp;
@@ -487,11 +606,11 @@ void vpaint_dogamma(Scene *scene)
a= 4*me->totface;
cp= (unsigned char *)me->mcol;
while(a--) {
-
+
cp[1]= gamtab[ cp[1] ];
cp[2]= gamtab[ cp[2] ];
cp[3]= gamtab[ cp[3] ];
-
+
cp+= 4;
}
}
@@ -911,14 +1030,14 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
index= view3d_sample_backbuf(&vc, event->mval[0], event->mval[1]);
- if(index && index<=me->totface) {
+ if(index && index<=me->totpoly) {
DerivedMesh *dm= mesh_get_derived_final(vc.scene, vc.obact, CD_MASK_BAREMESH);
if(dm->getVertCo==NULL) {
BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations");
}
else {
- MFace *mf= ((MFace *)me->mface) + index-1;
+ MPoly *mf= ((MPoly *)me->mpoly) + index-1;
const int vgroup_active= vc.obact->actdef - 1;
ToolSettings *ts= vc.scene->toolsettings;
float mval_f[2];
@@ -929,10 +1048,10 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
mval_f[0]= (float)event->mval[0];
mval_f[1]= (float)event->mval[1];
- fidx= mf->v4 ? 3:2;
+ fidx= mf->totloop - 1;
do {
float co[3], sco[3], len;
- const int v_idx= (*(&mf->v1 + fidx));
+ const int v_idx= me->mloop[mf->loopstart + fidx].v;
dm->getVertCo(dm, v_idx, co);
project_float_noclip(vc.ar, co, sco);
len= len_squared_v2v2(mval_f, sco);
@@ -995,16 +1114,16 @@ static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA
index= view3d_sample_backbuf(&vc, win->eventstate->x - vc.ar->winrct.xmin, win->eventstate->y - vc.ar->winrct.ymin);
- if(index && index<=me->totface) {
+ if(index && index<=me->totpoly) {
const int defbase_tot= BLI_countlist(&vc.obact->defbase);
if(defbase_tot) {
- MFace *mf= ((MFace *)me->mface) + index-1;
- unsigned int fidx= mf->v4 ? 3:2;
+ MPoly *mf= ((MPoly *)me->mpoly) + index-1;
+ unsigned int fidx= mf->totloop - 1;
int *groups= MEM_callocN(defbase_tot*sizeof(int), "groups");
int found= FALSE;
do {
- MDeformVert *dvert= me->dvert + (*(&mf->v1 + fidx));
+ MDeformVert *dvert= me->dvert + me->mloop[mf->loopstart + fidx].v;
int i= dvert->totweight;
MDeformWeight *dw;
for(dw= dvert->dw; i > 0; dw++, i--) {
@@ -2031,7 +2150,7 @@ 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;
+ if(me==NULL || me->totpoly==0) return OPERATOR_PASS_THROUGH;
/* if nothing was added yet, we make dverts and a vertex deform group */
if (!me->dvert) {
@@ -2194,7 +2313,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
if(wp->flag & VP_AREA) {
/* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */
me->editflag &= ~ME_EDIT_VERT_SEL;
- totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size_pressure);
+ totindex= sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure);
me->editflag |= use_vert_sel ? ME_EDIT_VERT_SEL : 0;
}
else {
@@ -2205,22 +2324,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;
}
}
@@ -2236,42 +2355,40 @@ 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);
+ if(indexar[index] && indexar[index]<=me->totpoly) {
+ MPoly *mpoly= me->mpoly + (indexar[index]-1);
+ MLoop *ml = me->mloop + mpoly->loopstart;
+ int i;
if(use_vert_sel) {
- me->dvert[mface->v1].flag = (me->mvert[mface->v1].flag & SELECT);
- me->dvert[mface->v2].flag = (me->mvert[mface->v2].flag & SELECT);
- me->dvert[mface->v3].flag = (me->mvert[mface->v3].flag & SELECT);
- if(mface->v4) me->dvert[mface->v4].flag = (me->mvert[mface->v4].flag & SELECT);
+ for (i=0; i<mpoly->totloop; i++, ml++) {
+ me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT);
+ }
}
else {
- 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;
+ for (i=0; i<mpoly->totloop; i++, ml++) {
+ me->dvert[ml->v].flag = 1;
+ }
}
if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int);
- unsigned int fidx= mface->v4 ? 3:2;
if(wp->flag & VP_ONLYVGROUP)
dw_func= (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index;
else
dw_func= defvert_verify_index;
-
- do {
- unsigned int vidx= *(&mface->v1 + fidx);
+
+ ml = me->mloop + mpoly->loopstart;
+ for (i=0; i<mpoly->totloop; i++, ml++) {
+ unsigned int vidx= ml->v;
const float fac = calc_vp_strength_dl(wp, vc, wpd->vertexcosnos+6*vidx, mval, brush_size_pressure);
if (fac > 0.0f) {
dw = dw_func(&me->dvert[vidx], wpi.vgroup_active);
paintweight += dw ? (dw->weight * fac) : 0.0f;
totw += fac;
}
-
- } while (fidx--);
-
+ }
}
}
}
@@ -2281,14 +2398,16 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
}
for(index=0; index<totindex; index++) {
-
- if(indexar[index] && indexar[index]<=me->totface) {
- MFace *mf= me->mface + (indexar[index]-1);
- unsigned int fidx= mf->v4 ? 3:2;
- do {
- unsigned int vidx= *(&mf->v1 + fidx);
- if(me->dvert[vidx].flag) {
+ 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++) {
+ unsigned int vidx= ml->v;
+
+ if (me->dvert[vidx].flag) {
alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*vidx,
mval, brush_size_pressure, brush_alpha_pressure);
if(alpha) {
@@ -2296,7 +2415,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
}
me->dvert[vidx].flag= 0;
}
- } while (fidx--);
+ }
}
}
@@ -2436,7 +2555,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) {
@@ -2504,14 +2623,56 @@ 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];
+
+ /* modify 'me->mcol' directly, since the derived mesh is drawing from this array,
+ * otherwise we need to refresh the modifier stack */
+ int use_fast_update;
+
+ /*mpoly -> mface mapping*/
+ MemArena *polyfacemap_arena;
+ ListBase *polyfacemap;
} VPaintData;
+static void vpaint_build_poly_facemap(struct VPaintData *vd, Mesh *me)
+{
+ MFace *mf;
+ polyfacemap_e *e;
+ int *origIndex;
+ int i;
+
+ vd->polyfacemap_arena = BLI_memarena_new(1<<13, "vpaint tmp");
+ BLI_memarena_use_calloc(vd->polyfacemap_arena);
+
+ vd->polyfacemap = BLI_memarena_alloc(vd->polyfacemap_arena, sizeof(ListBase)*me->totpoly);
+
+ origIndex = CustomData_get_layer(&me->fdata, CD_POLYINDEX);
+ 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->polyfacemap_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);
@@ -2524,10 +2685,13 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent
/* 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");
@@ -2537,9 +2701,20 @@ 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);
-
+
+
+ /* are we painting onto a modified mesh?,
+ * if not we can skip face map trickyness */
+ if (vertex_paint_use_fast_update_check(ob)) {
+ vpaint_build_poly_facemap(vpd, me);
+ vpd->use_fast_update = TRUE;
+ }
+ else {
+ vpd->use_fast_update = FALSE;
+ }
+
/* 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 */
mult_m4_m4m4(mat, vpd->vc.rv3d->viewmat, ob->obmat);
@@ -2549,6 +2724,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,
const unsigned int index, const float mval[2],
const float brush_size_pressure, const float brush_alpha_pressure,
@@ -2591,6 +2767,100 @@ static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob,
}
}
}
+#endif
+
+/* BMESH version of vpaint_paint_face (commented above) */
+
+static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Object *ob,
+ const unsigned int index, const float mval[2],
+ const float brush_size_pressure, const float brush_alpha_pressure,
+ int UNUSED(flip)
+ )
+{
+ ViewContext *vc = &vpd->vc;
+ Brush *brush = paint_brush(&vp->paint);
+ Mesh *me = get_mesh(ob);
+ MPoly *mpoly= &me->mpoly[index];
+ MFace *mf;
+ MCol *mc;
+ MLoop *ml;
+ MLoopCol *mlc;
+ polyfacemap_e *e;
+ unsigned int *lcol = ((unsigned int*)me->mloopcol) + mpoly->loopstart;
+ unsigned int *lcolorig = ((unsigned int*)vp->vpaint_prev) + mpoly->loopstart;
+ float alpha;
+ int i, j;
+
+ int brush_alpha_pressure_i = (int)(brush_alpha_pressure*255.0f);
+
+ if(brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
+ unsigned int blend[4] = {0};
+ unsigned int tcol;
+ 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 *)&tcol;
+ 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,
+ brush_size_pressure, brush_alpha_pressure);
+ if(alpha > 0.0f) {
+ const int alpha_i = (int)(alpha*255.0f);
+ lcol[i] = vpaint_blend(vp, lcol[i], lcolorig[i], vpd->paintcol, alpha_i, brush_alpha_pressure_i);
+ }
+ }
+
+ if (vpd->use_fast_update) {
+
+#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[index].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
+ }
+
+}
static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
@@ -2613,7 +2883,9 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
RNA_float_get_array(itemptr, "mouse", mval);
flip = RNA_boolean_get(itemptr, "pen_flip");
-
+
+ (void)flip; /* BMESH_TODO */
+
view3d_operator_needs_opengl(C);
/* load projection matrix */
@@ -2625,7 +2897,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_pressure);
+ totindex= sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure);
}
else {
indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
@@ -2633,23 +2905,55 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
else totindex= 0;
}
- 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, brush_size_pressure, brush_alpha_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 == PAINT_BLEND_BLUR)
- do_shared_vertexcol(me);
+ for(index=0; index<totindex; index++) {
+
+ if(indexar[index] && indexar[index]<=me->totpoly) {
+ vpaint_paint_poly(vp, vpd, ob, indexar[index]-1, mval, brush_size_pressure, brush_alpha_pressure, flip);
+ }
+ }
+
+ swap_m4m4(vc->rv3d->persmat, mat);
+
+ /* was disabled because it is slow, but necessary for blur */
+ if(brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
+ int do_tessface = vpd->use_fast_update;
+ do_shared_vertexcol(me, do_tessface);
+ }
+
ED_region_tag_redraw(vc->ar);
-
- DAG_id_tag_update(ob->data, 0);
+
+ if (vpd->use_fast_update == FALSE) {
+ /* recalculate modifier stack to get new colors, slow,
+ * avoid this if we can! */
+ DAG_id_tag_update(ob->data, 0);
+ }
}
static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
@@ -2663,7 +2967,11 @@ static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
/* frees prev buffer */
copy_vpaint_prev(ts->vpaint, NULL, 0);
-
+
+ if (vpd->polyfacemap_arena) {
+ BLI_memarena_free(vpd->polyfacemap_arena);
+ }
+
MEM_freeN(vpd);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index d05582512ae..2bff8476ea9 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -107,7 +107,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;
}
@@ -904,10 +904,11 @@ static void calc_sculpt_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **n
polygon.) */
static void neighbor_average(SculptSession *ss, float avg[3], const unsigned vert)
{
- int i, skip= -1, total=0;
- IndexNode *node= ss->fmap[vert].first;
- char ncount= BLI_countlist(&ss->fmap[vert]);
- MFace *f;
+ int i, j, ok, total=0;
+ IndexNode *node= ss->pmap[vert].first;
+ char ncount= BLI_countlist(&ss->pmap[vert]);
+ MPoly *f;
+ MLoop *ml;
avg[0] = avg[1] = avg[2] = 0;
@@ -920,21 +921,34 @@ static void neighbor_average(SculptSession *ss, float avg[3], const unsigned ver
}
while(node){
- f= &ss->mface[node->index];
-
- if(f->v4) {
- skip= (f->v1==vert?2:
- f->v2==vert?3:
- f->v3==vert?0:
- f->v4==vert?1:-1);
- }
-
- for(i=0; i<(f->v4?4:3); ++i) {
- if(i != skip && (ncount!=2 || BLI_countlist(&ss->fmap[(&f->v1)[i]]) <= 2)) {
- if(ss->deform_cos) add_v3_v3(avg, ss->deform_cos[(&f->v1)[i]]);
- else add_v3_v3(avg, ss->mvert[(&f->v1)[i]].co);
- ++total;
+ f= &ss->mpoly[node->index];
+
+ /* find the loop in the poly whic references this vertex */
+ ok = FALSE;
+ ml = ss->mloop + f->loopstart;
+ for (j = 0; j < f->totloop; j++, ml++) {
+ if (ml->v == vert) {
+ ok = TRUE;
+ break;
+ }
+ }
+
+ if (ok) {
+ /* vertex was found */
+ unsigned int f_adj_v[3] = {
+ ME_POLY_LOOP_PREV(ss->mloop, f, j)->v,
+ ml->v,
+ ME_POLY_LOOP_NEXT(ss->mloop, f, j)->v};
+
+
+ for (i=0; i<3; ++i) {
+ if (ncount!=2 || BLI_countlist(&ss->pmap[f_adj_v[i]]) <= 2) {
+ if(ss->deform_cos) add_v3_v3(avg, ss->deform_cos[f_adj_v[i]]);
+ else add_v3_v3(avg, ss->mvert[f_adj_v[i]].co);
+ ++total;
+ }
}
+
}
node= node->next;
@@ -1108,7 +1122,7 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float
if(ss->multires) {
do_multires_smooth_brush(sd, ss, nodes[n], iteration != count ? 1.0f : last);
}
- else if(ss->fmap)
+ else if(ss->pmap)
do_mesh_smooth_brush(sd, ss, nodes[n], iteration != count ? 1.0f : last);
}
@@ -2301,7 +2315,7 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
for (a= 0; a < me->totvert; a++, mvert++)
copy_v3_v3(mvert->co, vertCos[a]);
- mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+ mesh_calc_normals_mapping(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL);
}
/* apply new coords on active key block */
@@ -2534,7 +2548,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
/* Modifiers could depend on mesh normals, so we should update them/
Note, then if sculpting happens on locked key, normals should be re-calculated
after applying coords from keyblock on base mesh */
- mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+ mesh_calc_normals(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL);
} else if (ss->kb)
sculpt_update_keyblock(ob);
}
@@ -2678,7 +2692,7 @@ static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss)
}
}
-void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, int need_fmap)
+void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, int need_pmap)
{
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
SculptSession *ss = ob->sculpt;
@@ -2692,23 +2706,28 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, int need_
if(mmd) {
ss->multires = mmd;
ss->totvert = dm->getNumVerts(dm);
- ss->totface = dm->getNumFaces(dm);
+ ss->totpoly = dm->getNumPolys(dm);
ss->mvert= NULL;
- ss->mface= NULL;
+ ss->mpoly= NULL;
+ ss->mloop= NULL;
ss->face_normals= NULL;
}
else {
Mesh *me = get_mesh(ob);
ss->totvert = me->totvert;
- ss->totface = me->totface;
+ ss->totpoly = me->totpoly;
ss->mvert = me->mvert;
- ss->mface = me->mface;
+ ss->mpoly = me->mpoly;
+ ss->mloop = me->mloop;
ss->face_normals = NULL;
ss->multires = NULL;
}
+ /* BMESH ONLY --- at some point we should move sculpt code to use polygons only - but for now it needs tessfaces */
+ BKE_mesh_tessface_ensure(ob->data);
+
ss->pbvh = dm->getPBVH(ob, dm);
- ss->fmap = (need_fmap && dm->getFaceMap)? dm->getFaceMap(ob, dm): NULL;
+ ss->pmap = (need_pmap && dm->getPolyMap)? dm->getPolyMap(ob, dm): NULL;
if(ss->modifiers_active) {
if(!ss->orig_cos) {
@@ -2920,8 +2939,8 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio
if(brush->flag & BRUSH_ANCHORED) {
if(ss->face_normals) {
float *fn = ss->face_normals;
- cache->face_norms= MEM_mallocN(sizeof(float) * 3 * ss->totface, "Sculpt face norms");
- for(i = 0; i < ss->totface; ++i, fn += 3)
+ cache->face_norms= MEM_mallocN(sizeof(float) * 3 * ss->totpoly, "Sculpt face norms");
+ for(i = 0; i < ss->totpoly; ++i, fn += 3)
copy_v3_v3(cache->face_norms[i], fn);
}
@@ -3331,7 +3350,7 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
if(ss->face_normals) {
float *fn = ss->face_normals;
- for(i = 0; i < ss->totface; ++i, fn += 3)
+ for(i = 0; i < ss->totpoly; ++i, fn += 3)
copy_v3_v3(fn, cache->face_norms[i]);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index a69d5b2ee56..94ec0d17bb9 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -62,7 +62,7 @@ struct Brush *sculptmode_brush(void);
void sculpt(Sculpt *sd);
int sculpt_poll(struct bContext *C);
-void sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob, int need_fmap);
+void sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob, int need_pmap);
/* Deformed mesh sculpt */
void free_sculptsession_deformMats(struct SculptSession *ss);
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 4c54a5891b1..b1f009522fa 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -196,8 +196,8 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
tag_update= ((Mesh*)ob->data)->id.us > 1;
if(ss->modifiers_active) {
- Mesh *me= ob->data;
- mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+ Mesh *mesh= ob->data;
+ mesh_calc_normals_mapping(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL, NULL, 0, NULL, NULL);
free_sculptsession_deformMats(ss);
tag_update|= 1;
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index bf8cb58a2f5..ce07beae674 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -50,6 +50,7 @@
#include "BKE_depsgraph.h"
#include "BKE_mesh.h"
#include "BKE_customdata.h"
+#include "BKE_tessmesh.h"
#include "ED_screen.h"
#include "ED_image.h"
@@ -155,7 +156,7 @@ typedef struct Temp_UvData{
-void HC_relaxation_iteration_uv(EditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio){
+void HC_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio){
Temp_UVData *tmp_uvdata;
float diff[2];
int i;
@@ -208,11 +209,15 @@ void HC_relaxation_iteration_uv(EditMesh *em, UvSculptData *sculptdata, float mo
sculptdata->uv[i].uv[1] = (1.0-strength)*sculptdata->uv[i].uv[1] + strength*(tmp_uvdata[i].p[1] - 0.5f*(tmp_uvdata[i].b[1] + tmp_uvdata[i].sum_b[1]/tmp_uvdata[i].ncounter));
for(element = sculptdata->uv[i].element; element; element = element->next){
- MTFace *mt;
+ MLoopUV *luv;
+ BMLoop *l;
+
if(element->separate && element != sculptdata->uv[i].element)
break;
- mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE);
- copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[i].uv);
+
+ l = BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex);
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(luv->uv, sculptdata->uv[i].uv);
}
}
}
@@ -222,7 +227,7 @@ void HC_relaxation_iteration_uv(EditMesh *em, UvSculptData *sculptdata, float mo
return;
}
-static void laplacian_relaxation_iteration_uv(EditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio)
+static void laplacian_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio)
{
Temp_UVData *tmp_uvdata;
float diff[2];
@@ -268,11 +273,15 @@ static void laplacian_relaxation_iteration_uv(EditMesh *em, UvSculptData *sculpt
sculptdata->uv[i].uv[1] = (1.0-strength)*sculptdata->uv[i].uv[1] + strength*tmp_uvdata[i].p[1];
for(element = sculptdata->uv[i].element; element; element = element->next){
- MTFace *mt;
+ MLoopUV *luv;
+ BMLoop *l;
+
if(element->separate && element != sculptdata->uv[i].element)
break;
- mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE);
- copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[i].uv);
+
+ l = BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex);
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(luv->uv, sculptdata->uv[i].uv);
}
}
}
@@ -288,7 +297,7 @@ static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, wmEvent *event,
float co[2], radius, radius_root;
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
- EditMesh *em = BKE_mesh_get_editmesh(obedit->data);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
unsigned int tool;
UvSculptData *sculptdata = (UvSculptData *)op->customdata;
SpaceImage *sima;
@@ -340,11 +349,15 @@ static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, wmEvent *event,
sculptdata->uv[i].uv[1] -= strength*diff[1]*0.001;
for(element = sculptdata->uv[i].element; element; element = element->next){
- MTFace *mt;
+ MLoopUV *luv;
+ BMLoop *l;
+
if(element->separate && element != sculptdata->uv[i].element)
break;
- mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE);
- copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[i].uv);
+
+ l = BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex);
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(luv->uv, sculptdata->uv[i].uv);
}
}
}
@@ -378,16 +391,18 @@ static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, wmEvent *event,
sculptdata->uv[uvindex].uv[1] = sculptdata->initial_stroke->initialSelection[i].initial_uv[1] + strength*diff[1];
for(element = sculptdata->uv[uvindex].element; element; element = element->next){
- MTFace *mt;
+ MLoopUV *luv;
+ BMLoop *l;
+
if(element->separate && element != sculptdata->uv[uvindex].element)
break;
- mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE);
- copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[uvindex].uv);
+
+ l = BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex);
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(luv->uv, sculptdata->uv[uvindex].uv);
}
}
}
-
- BKE_mesh_end_editmesh(obedit->data, em);
}
@@ -399,7 +414,7 @@ static void uv_sculpt_stroke_exit(bContext *C, wmOperator *op)
}
if(data->elementMap)
{
- EM_free_uv_element_map(data->elementMap);
+ EDBM_free_uv_element_map(data->elementMap);
}
if(data->uv){
MEM_freeN(data->uv);
@@ -418,7 +433,7 @@ static void uv_sculpt_stroke_exit(bContext *C, wmOperator *op)
op->customdata = NULL;
}
-static int get_uv_element_offset_from_face(UvElementMap *map, EditFace *efa, int index, int island_index, int doIslands){
+static int get_uv_element_offset_from_face(UvElementMap *map, BMFace *efa, int index, int island_index, int doIslands){
UvElement *element = ED_get_uv_element(map, efa, index);
if(!element || (doIslands && element->island != island_index)){
return -1;
@@ -451,7 +466,8 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent
Object *obedit = CTX_data_edit_object(C);
ToolSettings *ts = scene->toolsettings;
UvSculptData *data = MEM_callocN(sizeof(*data), "UV Smooth Brush Data");
- EditMesh *em = BKE_mesh_get_editmesh(obedit->data);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
op->customdata = data;
@@ -459,11 +475,15 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent
int counter = 0, i;
ARegion *ar= CTX_wm_region(C);
float co[2];
- EditFace *efa;
+ BMFace *efa;
+ MLoopUV *luv;
+ BMLoop *l;
+ BMIter iter, liter;
+
UvEdge *edges;
GHash *edgeHash;
GHashIterator* ghi;
- MTFace *mt;
+
int do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS);
int island_index = 0;
/* Holds, for each UvElement in elementMap, a pointer to its unique uv.*/
@@ -476,15 +496,15 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent
if(do_island_optimization){
/* We will need island information */
if(ts->uv_flag & UV_SYNC_SELECTION){
- data->elementMap = EM_make_uv_element_map(em, 0, 1);
+ data->elementMap = EDBM_make_uv_element_map(em, 0, 1);
}else{
- data->elementMap = EM_make_uv_element_map(em, 1, 1);
+ data->elementMap = EDBM_make_uv_element_map(em, 1, 1);
}
}else {
if(ts->uv_flag & UV_SYNC_SELECTION){
- data->elementMap = EM_make_uv_element_map(em, 0, 0);
+ data->elementMap = EDBM_make_uv_element_map(em, 0, 0);
}else{
- data->elementMap = EM_make_uv_element_map(em, 1, 0);
+ data->elementMap = EDBM_make_uv_element_map(em, 1, 0);
}
}
@@ -503,7 +523,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent
Image *ima= CTX_data_edit_image(C);
uv_find_nearest_vert(scene, ima, em, co, NULL, &hit);
- element = ED_get_uv_element(data->elementMap, hit.efa, hit.uv);
+ element = ED_get_uv_element(data->elementMap, hit.efa, hit.lindex);
island_index = element->island;
}
@@ -540,7 +560,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent
/* So that we can use this as index for the UvElements */
counter = -1;
/* initialize the unique UVs */
- for(i = 0; i < em->totvert; i++){
+ for(i = 0; i < bm->totvert; i++){
UvElement *element = data->elementMap->vert[i];
for(; element; element = element->next){
if(element->separate){
@@ -550,23 +570,28 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent
;
continue;
}
+
efa = element->face;
- mt = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ l = BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex);
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
counter++;
data->uv[counter].element = element;
data->uv[counter].flag = 0;
- data->uv[counter].uv = mt->uv[element->tfindex];
+ data->uv[counter].uv = luv->uv;
}
/* pointer arithmetic to the rescue, as always :)*/
uniqueUv[element - data->elementMap->buf] = counter;
}
}
+
/* Now, on to generate our uv connectivity data */
- for(efa = em->faces.first, counter = 0; efa; efa = efa->next){
- int nverts = efa->v4 ? 4 : 3;
- for(i = 0; i < nverts; i++){
+ counter = 0;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ int nverts = efa->len;
+ i = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
int offset1, itmp1 = get_uv_element_offset_from_face(data->elementMap, efa, i, island_index, do_island_optimization);
int offset2, itmp2 = get_uv_element_offset_from_face(data->elementMap, efa, (i+1)%nverts, island_index, do_island_optimization);
@@ -598,8 +623,10 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent
BLI_ghash_insert(edgeHash, &edges[counter], &edges[counter].flag);
}
counter++;
+ i++;
}
}
+
MEM_freeN(uniqueUv);
/* Allocate connectivity data, we allocate edges once */
@@ -639,7 +666,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent
}
/* Allocate initial selection for grab tool */
- if(data->tool){
+ if(data->tool == UV_SCULPT_TOOL_GRAB){
float radius, radius_root;
UvSculptData *sculptdata = (UvSculptData *)op->customdata;
SpaceImage *sima;
diff --git a/source/blender/editors/space_api/CMakeLists.txt b/source/blender/editors/space_api/CMakeLists.txt
index 6f2a0385231..611322fc1ab 100644
--- a/source/blender/editors/space_api/CMakeLists.txt
+++ b/source/blender/editors/space_api/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenkernel
../../blenlib
../../blenloader
+ ../../bmesh
../../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_buttons/SConscript b/source/blender/editors/space_buttons/SConscript
index 740353bc1f0..7bc588c627c 100644
--- a/source/blender/editors/space_buttons/SConscript
+++ b/source/blender/editors/space_buttons/SConscript
@@ -5,7 +5,7 @@ sources = env.Glob('*.c')
incs = '../include ../../blenfont ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
-incs += ' ../../makesrna ../../render/extern/include ../../blenloader'
+incs += ' ../../bmesh ../../makesrna ../../render/extern/include ../../blenloader'
defs = []
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 5d0f294b06a..a77e6dccbb8 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -879,6 +879,7 @@ static void proxy_startjob(void *pjv, short *stop, short *do_update, float *prog
IMB_anim_index_rebuild(clip->anim, tc_flag, size_flag, quality, stop, do_update, progress);
if(!build_undistort_count) {
+ BKE_movieclip_reload(clip);
return;
}
else {
@@ -905,6 +906,8 @@ static void proxy_startjob(void *pjv, short *stop, short *do_update, float *prog
if(distortion)
BKE_tracking_distortion_destroy(distortion);
+
+ BKE_movieclip_reload(clip);
}
static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt
index 15c90fb701e..3975a5f56f3 100644
--- a/source/blender/editors/space_image/CMakeLists.txt
+++ b/source/blender/editors/space_image/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
../../blenlib
../../blenloader
../../imbuf
+ ../../bmesh
../../makesdna
../../makesrna
../../render/extern/include
diff --git a/source/blender/editors/space_image/SConscript b/source/blender/editors/space_image/SConscript
index 27696e35701..cdd2133d0f5 100644
--- a/source/blender/editors/space_image/SConscript
+++ b/source/blender/editors/space_image/SConscript
@@ -5,7 +5,7 @@ sources = env.Glob('*.c')
incs = '../include ../../blenfont ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
-incs += ' ../../render/extern/include ../../makesrna ../../blenloader'
+incs += ' ../../bmesh ../../render/extern/include ../../makesrna ../../blenloader'
defs = []
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 8063dc6c902..dd988c94dc9 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -52,6 +52,7 @@
#include "BKE_mesh.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_tessmesh.h"
#include "IMB_imbuf_types.h"
@@ -275,12 +276,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);
+ struct 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;
}
@@ -294,12 +294,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);
+ struct 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;
}
@@ -587,12 +586,12 @@ 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);
+ struct BMEditMesh *em= me->edit_btmesh;
int sloppy= 1; /* partially selected face is ok */
if(scene_use_new_shading_nodes(scene)) {
/* new shading system, get image from material */
- EditFace *efa= EM_get_actFace(em, sloppy);
+ BMFace *efa = BM_active_face_get(em->bm, sloppy);
if(efa) {
Image *node_ima;
@@ -604,12 +603,12 @@ static void image_refresh(const bContext *C, ScrArea *UNUSED(sa))
}
else {
/* old shading system, we set texface */
- MTFace *tf;
+ MTexPoly *tf;
- if(em && EM_texFaceCheck(em)) {
+ if(em && EDBM_texFaceCheck(em)) {
sima->image= NULL;
- tf = EM_get_active_mtface(em, NULL, NULL, sloppy);
+ tf = EDBM_get_active_mtexpoly(em, NULL, TRUE); /* partially selected face is ok */
if(tf) {
/* don't need to check for pin here, see above */
@@ -620,8 +619,6 @@ static void image_refresh(const bContext *C, ScrArea *UNUSED(sa))
}
}
}
-
- BKE_mesh_end_editmesh(obedit->data, em);
}
}
diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt
index 4c1c13c1092..7cf5b1fc3fb 100644
--- a/source/blender/editors/space_info/CMakeLists.txt
+++ b/source/blender/editors/space_info/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
../../blenlib
../../blenloader
../../imbuf
+ ../../bmesh
../../makesdna
../../makesrna
../../windowmanager
diff --git a/source/blender/editors/space_info/SConscript b/source/blender/editors/space_info/SConscript
index 697ee4319b8..746edadccc2 100644
--- a/source/blender/editors/space_info/SConscript
+++ b/source/blender/editors/space_info/SConscript
@@ -4,7 +4,7 @@ Import ('env')
sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../makesrna ../../imbuf ../../blenfont'
-incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include ../../blenloader'
+incs += ' ../../bmesh ../../windowmanager #/intern/guardedalloc #/extern/glew/include ../../blenloader'
defs = []
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 52e6a8808ae..38d99c084b3 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -47,6 +47,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"
@@ -78,7 +79,7 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
if(dm) {
totvert = dm->getNumVerts(dm);
totedge = dm->getNumEdges(dm);
- totface = dm->getNumFaces(dm);
+ totface = dm->getNumPolys(dm);
stats->totvert += totvert*totob;
stats->totedge += totedge*totob;
@@ -139,26 +140,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_node/SConscript b/source/blender/editors/space_node/SConscript
index 6b72fd066e0..ec4ed971a76 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'] == 'linux':
cflags='-pthread'
incs += ' ../../../extern/binreloc/include'
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index f1ef35936fa..e78bad62ba5 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenkernel
../../blenlib
../../blenloader
+ ../../bmesh
../../gpu
../../imbuf
../../makesdna
diff --git a/source/blender/editors/space_view3d/SConscript b/source/blender/editors/space_view3d/SConscript
index 84ba8d1fe86..53bd7828b63 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/gameengine/BlenderRoutines'
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index 62c12500aa8..09a4a9eb749 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -32,6 +32,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_edgehash.h"
@@ -46,6 +47,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_windowmanager_types.h"
#include "BKE_DerivedMesh.h"
#include "BKE_effect.h"
@@ -53,6 +55,7 @@
#include "BKE_material.h"
#include "BKE_paint.h"
#include "BKE_property.h"
+#include "BKE_tessmesh.h"
#include "BKE_scene.h"
#include "BIF_gl.h"
@@ -77,7 +80,7 @@ typedef struct drawMeshFaceSelect_userData {
} drawMeshFaceSelect_userData;
typedef struct drawEMTFMapped_userData {
- EditMesh *em;
+ BMEditMesh *em;
short has_mcol;
short has_mtface;
MFace *mf;
@@ -112,25 +115,23 @@ static void get_marked_edge_info__orFlags(EdgeHash *eh, int v0, int v1, int flag
static EdgeHash *get_tface_mesh_marked_edge_info(Mesh *me)
{
EdgeHash *eh = BLI_edgehash_new();
- MFace *mf;
- int i;
+ MPoly *mp;
+ MLoop *ml;
+ MLoop *ml_next;
+ int i, j;
- for(i=0; i<me->totface; i++) {
- mf = &me->mface[i];
+ for(i=0; i<me->totpoly; i++) {
+ mp = &me->mpoly[i];
- if(!(mf->flag & ME_HIDE)) {
+ if (!(mp->flag & ME_HIDE)) {
unsigned int flags = eEdge_Visible;
- if(mf->flag & ME_FACE_SEL) flags |= eEdge_Select;
-
- get_marked_edge_info__orFlags(eh, mf->v1, mf->v2, flags);
- get_marked_edge_info__orFlags(eh, mf->v2, mf->v3, flags);
+ if (mp->flag & ME_FACE_SEL) flags |= eEdge_Select;
- if(mf->v4) {
- get_marked_edge_info__orFlags(eh, mf->v3, mf->v4, flags);
- get_marked_edge_info__orFlags(eh, mf->v4, mf->v1, flags);
+ ml = me->mloop + mp->loopstart;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ ml_next = ME_POLY_LOOP_NEXT(me->mloop, mp, j);
+ get_marked_edge_info__orFlags(eh, ml->v, ml_next->v, flags);
}
- else
- get_marked_edge_info__orFlags(eh, mf->v3, mf->v1, flags);
}
}
@@ -169,7 +170,7 @@ static int draw_mesh_face_select__drawFaceOptsInv(void *userData, int index)
{
Mesh *me = (Mesh*)userData;
- MFace *mface = &me->mface[index];
+ MPoly *mface = &me->mpoly[index];
if(!(mface->flag&ME_HIDE) && !(mface->flag&ME_FACE_SEL))
return 2; /* Don't set color */
else
@@ -443,16 +444,16 @@ static int draw_tface__set_draw(MTFace *tface, int has_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);
+ MTFace *tface = DM_get_poly_data_layer(dm, CD_MTFACE);
+ 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++) {
Material *ma= give_current_material(Gtexdraw.ob, mface[i].mat_nr+1);
if (ma && (ma->game.flag&GEMAT_INVISIBLE)) {
@@ -514,42 +515,62 @@ static void add_tface_color_layer(DerivedMesh *dm)
}
}
}
- CustomData_add_layer( &dm->faceData, CD_TEXTURE_MCOL, CD_ASSIGN, finalCol, dm->numFaceData );
+ CustomData_add_layer( &dm->faceData, CD_TEXTURE_MCOL, CD_ASSIGN, finalCol, dm->numTessFaceData );
}
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];
- const int matnr = mface->mat_nr;
- if (mface->flag & ME_HIDE) return 0;
- return draw_tface__set_draw(tface, (me->mcol != NULL), matnr);
+ Mesh *me = (Mesh *)userData;
+
+ /* array checked for NULL before calling */
+ MPoly *mpoly = &me->mpoly[index];
+
+ BLI_assert(index >= 0 && index < me->totpoly);
+
+ if (mpoly->flag & ME_HIDE) {
+ return 0;
+ }
+ else {
+ MTexPoly *tpoly = (me->mtpoly) ? &me->mtpoly[index] : NULL;
+ MTFace mtf= {{{0}}};
+ int matnr = mpoly->mat_nr;
+
+ if (tpoly) {
+ ME_MTEXFACE_CPY(&mtf, tpoly);
+ }
+
+ return draw_tface__set_draw(&mtf, (me->mloopcol != NULL), matnr);
+ }
}
static int draw_em_tf_mapped__set_draw(void *userData, int index)
{
drawEMTFMapped_userData *data = userData;
- EditMesh *em = data->em;
- EditFace *efa= EM_get_face_for_index(index);
- MTFace *tface;
- int matnr;
+ BMEditMesh *em = data->em;
+ BMFace *efa= EDBM_get_face_for_index(em, index);
- if (efa->h)
+ if (efa==NULL || BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
return 0;
+ }
+ else {
+ MTFace mtf= {{{0}}};
+ int matnr = efa->mat_nr;
- tface = data->has_mtface ? CustomData_em_get(&em->fdata, efa->data, CD_MTFACE) : NULL;
- matnr = efa->mat_nr;
+ if (data->has_mtface) {
+ MTexPoly *tpoly = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ ME_MTEXFACE_CPY(&mtf, tpoly);
+ }
- return draw_tface__set_draw_legacy(tface, data->has_mcol, matnr);
+ return draw_tface__set_draw_legacy(&mtf, data->has_mcol, matnr);
+ }
}
static int wpaint__setSolidDrawOptions_material(void *userData, int index, int *drawSmooth_r)
{
Mesh *me = (Mesh*)userData;
- if (me->mat && me->mface) {
- Material *ma= me->mat[me->mface[index].mat_nr];
+ if (me->mat && me->mpoly) {
+ Material *ma= me->mat[me->mpoly[index].mat_nr];
if (ma && (ma->game.flag & GEMAT_INVISIBLE)) {
return 0;
}
@@ -563,8 +584,8 @@ static int wpaint__setSolidDrawOptions_material(void *userData, int index, int *
static int wpaint__setSolidDrawOptions_facemask(void *userData, int index, int *drawSmooth_r)
{
Mesh *me = (Mesh*)userData;
- MFace *mface = &me->mface[index];
- if (mface->flag & ME_HIDE) return 0;
+ MPoly *mp = &me->mpoly[index];
+ if (mp->flag & ME_HIDE) return 0;
*drawSmooth_r = 1;
return 1;
}
@@ -573,15 +594,24 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
{
Mesh *me = ob->data;
DerivedMesh *ddm;
- MFace *mf, *mface= me->mface;
- MTFace *tface= me->mtface;
- MCol *mcol= me->mcol; /* why does mcol exist? */
+ MPoly *mp, *mface = me->mpoly;
+ MTexPoly *mtpoly = me->mtpoly;
+ MLoopUV *mloopuv = me->mloopuv;
+ MLoopUV *luv;
+ MLoopCol *mloopcol = me->mloopcol; /* why does mcol exist? */
+ MLoopCol *lcol;
+
bProperty *prop = get_ob_property(ob, "Text");
GPUVertexAttribs gattribs;
- int a, totface= me->totface;
+ int a, totpoly = me->totpoly;
+
+ /* fake values to pass to GPU_render_text() */
+ MCol tmp_mcol[4] = {{0}};
+ MCol *tmp_mcol_pt = mloopcol ? tmp_mcol : NULL;
+ MTFace tmp_tf = {{{0}}};
/* don't draw without tfaces */
- if(!tface)
+ if(!mtpoly || !mloopuv)
return;
/* don't draw when editing */
@@ -593,17 +623,23 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
ddm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
- for(a=0, mf=mface; a<totface; a++, tface++, mf++) {
- short matnr= mf->mat_nr;
- int mf_smooth= mf->flag & ME_SMOOTH;
+ for(a=0, mp=mface; a<totpoly ; a++, mtpoly++, mp++) {
+ short matnr= mp->mat_nr;
+ int mf_smooth= mp->flag & ME_SMOOTH;
Material *mat = me->mat[matnr];
int mode= mat->game.flag;
- if (!(mode&GEMAT_INVISIBLE) && (mode&GEMAT_TEXT)) {
+ if (!(mode&GEMAT_INVISIBLE) && (mode&GEMAT_TEXT) && mp->totloop >= 3) {
+ /* get the polygon as a tri/quad */
+ int mp_vi[4];
float v1[3], v2[3], v3[3], v4[3];
char string[MAX_PROPSTRING];
int characters, i, glattrib= -1, badtex= 0;
+
+ /* TEXFACE */
+ ME_MTEXFACE_CPY(&tmp_tf, mtpoly);
+
if(glsl) {
GPU_enable_material(matnr+1, &gattribs);
@@ -615,17 +651,49 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
}
}
else {
- badtex = set_draw_settings_cached(0, tface, mat, Gtexdraw);
+ badtex = set_draw_settings_cached(0, &tmp_tf, mat, Gtexdraw);
if (badtex) {
- if (mcol) mcol+=4;
continue;
}
}
- ddm->getVertCo(ddm, mf->v1, v1);
- ddm->getVertCo(ddm, mf->v2, v2);
- ddm->getVertCo(ddm, mf->v3, v3);
- if (mf->v4) ddm->getVertCo(ddm, mf->v4, v4);
+ mp_vi[0] = me->mloop[mp->loopstart + 0].v;
+ mp_vi[1] = me->mloop[mp->loopstart + 1].v;
+ mp_vi[2] = me->mloop[mp->loopstart + 2].v;
+ mp_vi[3] = (mp->totloop >= 4) ? me->mloop[mp->loopstart + 3].v : 0;
+
+ /* UV */
+ luv = &mloopuv[mp->loopstart];
+ copy_v2_v2(tmp_tf.uv[0], luv->uv); luv++;
+ copy_v2_v2(tmp_tf.uv[1], luv->uv); luv++;
+ copy_v2_v2(tmp_tf.uv[2], luv->uv); luv++;
+ if (mp->totloop >= 4) {
+ copy_v2_v2(tmp_tf.uv[3], luv->uv);
+ }
+
+ /* COLOR */
+ if (mloopcol) {
+ unsigned int totloop_clamp = MIN2(4, mp->totloop);
+ unsigned int j;
+ lcol = &mloopcol[mp->loopstart];
+
+ for (j = 0; j <= totloop_clamp; j++, lcol++) {
+ tmp_mcol[j].a = lcol->a;
+ tmp_mcol[j].r = lcol->r;
+ tmp_mcol[j].g = lcol->g;
+ tmp_mcol[j].b = lcol->b;
+ }
+ }
+
+ /* LOCATION */
+ ddm->getVertCo(ddm, mp_vi[0], v1);
+ ddm->getVertCo(ddm, mp_vi[1], v2);
+ ddm->getVertCo(ddm, mp_vi[2], v3);;
+ if (mp->totloop >= 4) {
+ ddm->getVertCo(ddm, mp_vi[3], v4);
+ }
+
+
// The BM_FONT handling is in the gpu module, shared with the
// game engine, was duplicated previously
@@ -633,7 +701,7 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
set_property_valstr(prop, string);
characters = strlen(string);
- if(!BKE_image_get_ibuf(tface->tpage, NULL))
+ if(!BKE_image_get_ibuf(mtpoly->tpage, NULL))
characters = 0;
if (!mf_smooth) {
@@ -644,11 +712,8 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
glNormal3fv(nor);
}
- GPU_render_text(tface, mode, string, characters,
- (unsigned int*)mcol, v1, v2, v3, (mf->v4? v4: NULL), glattrib);
- }
- if (mcol) {
- mcol+=4;
+ GPU_render_text(&tmp_tf, mode, string, characters,
+ (unsigned int*)tmp_mcol_pt, v1, v2, v3, (mp->totloop >= 4 ? v4: NULL), glattrib);
}
}
@@ -697,11 +762,11 @@ void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
if(ob->mode & OB_MODE_EDIT) {
drawEMTFMapped_userData data;
- data.em= me->edit_mesh;
- data.has_mcol= CustomData_has_layer(&me->edit_mesh->fdata, CD_MCOL);
- data.has_mtface= CustomData_has_layer(&me->edit_mesh->fdata, CD_MTFACE);
- data.mf= DM_get_face_data_layer(dm, CD_MFACE);
- data.tf= DM_get_face_data_layer(dm, CD_MTFACE);
+ data.em= me->edit_btmesh;
+ data.has_mcol= CustomData_has_layer(&me->edit_btmesh->bm->ldata, CD_MLOOPCOL);
+ data.has_mtface= CustomData_has_layer(&me->edit_btmesh->bm->pdata, CD_MTEXPOLY);
+ data.mf= DM_get_tessface_data_layer(dm, CD_MFACE);
+ data.tf= DM_get_tessface_data_layer(dm, CD_MTFACE);
dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, compareDrawOptionsEm, &data);
}
@@ -709,7 +774,7 @@ void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
if(ob->mode & OB_MODE_WEIGHT_PAINT)
dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions_facemask, GPU_enable_material, NULL, me, 1);
else
- dm->drawMappedFacesTex(dm, me->mface ? draw_tface_mapped__set_draw : NULL, NULL, me);
+ dm->drawMappedFacesTex(dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, NULL, me);
}
else {
if(GPU_buffer_legacy(dm)) {
@@ -724,8 +789,8 @@ void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
if(!CustomData_has_layer(&dm->faceData,CD_TEXTURE_MCOL))
add_tface_color_layer(dm);
- userData.mf = DM_get_face_data_layer(dm, CD_MFACE);
- userData.tf = DM_get_face_data_layer(dm, CD_MTFACE);
+ userData.mf = DM_get_tessface_data_layer(dm, CD_MFACE);
+ userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
dm->drawFacesTex(dm, draw_tface__set_draw, compareDrawOptions, &userData);
}
@@ -834,17 +899,19 @@ static int tex_mat_set_face_mesh_cb(void *userData, int index)
/* faceselect mode face hiding */
TexMatCallback *data= (TexMatCallback*)userData;
Mesh *me = (Mesh*)data->me;
- MFace *mface = &me->mface[index];
+ MPoly *mp = &me->mpoly[index];
- return !(mface->flag & ME_HIDE);
+ return !(mp->flag & ME_HIDE);
}
-static int tex_mat_set_face_editmesh_cb(void *UNUSED(userData), int index)
+static int tex_mat_set_face_editmesh_cb(void *userData, int index)
{
/* editmode face hiding */
- EditFace *efa= EM_get_face_for_index(index);
+ TexMatCallback *data= (TexMatCallback*)userData;
+ Mesh *me = (Mesh*)data->me;
+ BMFace *efa= EDBM_get_face_for_index(me->edit_btmesh, index);
- return !(efa->h);
+ return !BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
}
void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, DerivedMesh *dm, int draw_flags)
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 8fc2f17fae4..7ce88ee9b48 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -47,6 +47,7 @@
#include "DNA_world_types.h"
#include "DNA_armature_types.h"
+#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_editVert.h"
@@ -79,6 +80,8 @@
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
+#include "BKE_tessmesh.h"
+
#include "smoke_API.h"
#include "IMB_imbuf.h"
@@ -119,42 +122,51 @@ typedef enum eWireDrawMode {
/* user data structures for derived mesh callbacks */
typedef struct foreachScreenVert_userData {
- void (*func)(void *userData, EditVert *eve, int x, int y, int index);
+ void (*func)(void *userData, BMVert *eve, int x, int y, int index);
void *userData;
ViewContext vc;
eV3DClipTest clipVerts;
} foreachScreenVert_userData;
typedef struct foreachScreenEdge_userData {
- void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index);
+ void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index);
void *userData;
ViewContext vc;
eV3DClipTest clipVerts;
} foreachScreenEdge_userData;
typedef struct foreachScreenFace_userData {
- void (*func)(void *userData, EditFace *efa, int x, int y, int index);
+ void (*func)(void *userData, BMFace *efa, int x, int y, int index);
void *userData;
ViewContext vc;
} foreachScreenFace_userData;
typedef struct drawDMVerts_userData {
+ BMEditMesh *em; /* BMESH BRANCH ONLY */
+
int sel;
- EditVert *eve_act;
+ BMVert *eve_act;
} drawDMVerts_userData;
typedef struct drawDMEdgesSel_userData {
+ BMEditMesh *em; /* BMESH BRANCH ONLY */
+
unsigned char *baseCol, *selCol, *actCol;
- EditEdge *eed_act;
+ BMEdge *eed_act;
} drawDMEdgesSel_userData;
typedef struct drawDMFacesSel_userData {
unsigned char *cols[4];
- EditFace *efa_act;
+
+ DerivedMesh *dm; /* BMESH BRANCH ONLY */
+ BMEditMesh *em; /* BMESH BRANCH ONLY */
+
+ BMFace *efa_act;
int *orig_index;
} drawDMFacesSel_userData;
typedef struct drawDMNormal_userData {
+ BMEditMesh *em;
float normalsize;
} drawDMNormal_userData;
@@ -228,8 +240,10 @@ static void view3d_project_short_clip(ARegion *ar, const float vec[3], short adr
}
}
+/* BMESH NOTE: this function is unused in bmesh only */
+
/* only use while object drawing */
-static void view3d_project_short_noclip(ARegion *ar, const float vec[3], short adr[2])
+static void UNUSED_FUNCTION(view3d_project_short_noclip)(ARegion *ar, const float vec[3], short adr[2])
{
RegionView3D *rv3d= ar->regiondata;
float fx, fy, vec4[4];
@@ -1990,15 +2004,17 @@ static void drawlattice(Scene *scene, View3D *v3d, Object *ob)
static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
{
foreachScreenVert_userData *data = userData;
- EditVert *eve = EM_get_vert_for_index(index);
+ BMVert *eve = EDBM_get_vert_for_index(data->vc.em, index);
- if (eve->h==0) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
short s[2]= {IS_CLIPPED, 0};
if (data->clipVerts != V3D_CLIP_TEST_OFF) {
view3d_project_short_clip(data->vc.ar, co, s, 1);
} else {
- view3d_project_short_noclip(data->vc.ar, co, s);
+ float co2[2];
+ mul_v3_m4v3(co2, data->vc.obedit->obmat, co);
+ project_short_noclip(data->vc.ar, co2, s);
}
if (s[0]!=IS_CLIPPED)
@@ -2008,11 +2024,11 @@ 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 (*func)(void *userData, BMVert *eve, int x, int y, int index),
void *userData, eV3DClipTest clipVerts)
{
foreachScreenVert_userData data;
- DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
+ DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
data.vc= *vc;
data.func = func;
@@ -2022,9 +2038,9 @@ void mesh_foreachScreenVert(
if(clipVerts != V3D_CLIP_TEST_OFF)
ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
- EM_init_index_arrays(vc->em, 1, 0, 0);
+ EDBM_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);
}
@@ -2066,17 +2082,23 @@ static int is_co_in_region(ARegion *ar, const short co[2])
static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0co, float *v1co)
{
foreachScreenEdge_userData *data = userData;
- EditEdge *eed = EM_get_edge_for_index(index);
- short s[2][2];
+ BMEdge *eed = EDBM_get_edge_for_index(data->vc.em, index);
+
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ short s[2][2];
- if (eed->h==0) {
if (data->clipVerts == V3D_CLIP_TEST_RV3D_CLIPPING) {
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]);
+ float v1_co[3], v2_co[3];
+
+ mul_v3_m4v3(v1_co, data->vc.obedit->obmat, v0co);
+ mul_v3_m4v3(v2_co, data->vc.obedit->obmat, v1co);
+
+ project_short_noclip(data->vc.ar, v1_co, s[0]);
+ project_short_noclip(data->vc.ar, v2_co, s[1]);
if (data->clipVerts == V3D_CLIP_TEST_REGION) {
if ( !is_co_in_region(data->vc.ar, s[0]) &&
@@ -2093,11 +2115,11 @@ 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 (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index),
void *userData, eV3DClipTest clipVerts)
{
foreachScreenEdge_userData data;
- DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
+ DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
data.vc= *vc;
data.func = func;
@@ -2107,9 +2129,9 @@ void mesh_foreachScreenEdge(
if(clipVerts != V3D_CLIP_TEST_OFF)
ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
- EM_init_index_arrays(vc->em, 0, 1, 0);
+ EDBM_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);
}
@@ -2117,11 +2139,14 @@ void mesh_foreachScreenEdge(
static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *cent, float *UNUSED(no))
{
foreachScreenFace_userData *data = userData;
- EditFace *efa = EM_get_face_for_index(index);
- short s[2];
+ BMFace *efa = EDBM_get_face_for_index(data->vc.em, index);
+
+ if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ float cent2[3];
+ short s[2];
- if (efa && efa->h==0 && efa->fgonf!=EM_FGON) {
- view3d_project_short_clip(data->vc.ar, cent, s, 1);
+ mul_v3_m4v3(cent2, data->vc.obedit->obmat, cent);
+ project_short(data->vc.ar, cent2, s);
if (s[0] != IS_CLIPPED) {
data->func(data->userData, efa, s[0], s[1], index);
@@ -2131,11 +2156,11 @@ static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *ce
void mesh_foreachScreenFace(
ViewContext *vc,
- void (*func)(void *userData, EditFace *efa, int x, int y, int index),
+ void (*func)(void *userData, BMFace *efa, int x, int y, int index),
void *userData)
{
foreachScreenFace_userData data;
- DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
+ DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
data.vc= *vc;
data.func = func;
@@ -2144,9 +2169,9 @@ void mesh_foreachScreenFace(
//if(clipVerts)
ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
- EM_init_index_arrays(vc->em, 0, 0, 1);
+ EDBM_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);
}
@@ -2217,19 +2242,20 @@ void nurbs_foreachScreenVert(
static void draw_dm_face_normals__mapFunc(void *userData, int index, float *cent, float *no)
{
drawDMNormal_userData *data = userData;
- EditFace *efa = EM_get_face_for_index(index);
+ BMFace *efa = EDBM_get_face_for_index(data->em, index);
- if (efa->h==0 && efa->fgonf!=EM_FGON) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
glVertex3fv(cent);
glVertex3f(cent[0] + no[0] * data->normalsize,
cent[1] + no[1] * data->normalsize,
cent[2] + no[2] * data->normalsize);
}
}
-static void draw_dm_face_normals(Scene *scene, DerivedMesh *dm)
+static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
{
drawDMNormal_userData data;
+ data.em = em;
data.normalsize = scene->toolsettings->normalsize;
glBegin(GL_LINES);
@@ -2239,26 +2265,28 @@ static void draw_dm_face_normals(Scene *scene, DerivedMesh *dm)
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);
-
- if (efa->h==0 && efa->fgonf!=EM_FGON && (efa->f&SELECT)==sel) {
+ BMFace *efa = EDBM_get_face_for_index(((void **)userData)[0], index);
+ int sel = *(((int **)userData)[1]);
+
+ if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BM_elem_flag_test(efa, BM_ELEM_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)
{
drawDMNormal_userData *data = userData;
- EditVert *eve = EM_get_vert_for_index(index);
+ BMVert *eve = EDBM_get_vert_for_index(data->em, index);
- if (eve->h==0) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
glVertex3fv(co);
if (no_f) {
@@ -2273,10 +2301,11 @@ 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)
{
drawDMNormal_userData data;
+ data.em = em;
data.normalsize = scene->toolsettings->normalsize;
glBegin(GL_LINES);
@@ -2284,13 +2313,13 @@ static void draw_dm_vert_normals(Scene *scene, DerivedMesh *dm)
glEnd();
}
- /* Draw verts with color set based on selection */
+/* 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))
{
drawDMVerts_userData * data = userData;
- EditVert *eve = EM_get_vert_for_index(index);
+ BMVert *eve = EDBM_get_vert_for_index(data->em, index);
- if (eve->h==0 && (eve->f&SELECT)==data->sel) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_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);
@@ -2312,11 +2341,12 @@ 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)
{
drawDMVerts_userData data;
data.sel = sel;
data.eve_act = eve_act;
+ data.em = em;
bglBegin(GL_POINTS);
dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
@@ -2326,16 +2356,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;
drawDMEdgesSel_userData * data = userData;
unsigned char *col;
- if (eed->h==0) {
+ eed = EDBM_get_edge_for_index(data->em, index);
+
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
if (eed==data->eed_act) {
glColor4ubv(data->actCol);
} else {
- if (eed->f&SELECT) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
col = data->selCol;
} else {
col = data->baseCol;
@@ -2350,38 +2382,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)
{
drawDMEdgesSel_userData 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_elem_flag_test(EDBM_get_edge_for_index(userData, index), BM_ELEM_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_elem_flag_test(EDBM_get_edge_for_index(((void**)userData)[0], index), BM_ELEM_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_elem_flag_test(eed->v1, BM_ELEM_SELECT))?2:1];
+ unsigned char *col1 = cols[(BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))?2:1];
glColor4ub( col0[0] + (col1[0]-col0[0])*t,
col0[1] + (col1[1]-col0[1])*t,
@@ -2389,48 +2423,48 @@ 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;
+ void *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)
{
- EditEdge *eed = EM_get_edge_for_index(index);
+ BMEdge *eed = EDBM_get_edge_for_index(userData, index);
- return (eed->h==0 && eed->seam);
+ return !BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SEAM);
}
-static void draw_dm_edges_seams(DerivedMesh *dm)
+
+static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
{
- dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, NULL);
+ dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em);
}
/* 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_elem_flag_test(eed, BM_ELEM_HIDDEN) && !BM_elem_flag_test(eed, BM_ELEM_SMOOTH);
}
-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);
}
/* Draw only Freestyle feature edges */
-static int draw_dm_edges_freestyle__setDrawOptions(void *UNUSED(userData), int index)
+static int draw_dm_edges_freestyle__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->freestyle);
+ return !BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_FREESTYLE);
}
-static void draw_dm_edges_freestyle(DerivedMesh *dm)
+static void draw_dm_edges_freestyle(BMEditMesh *em, DerivedMesh *dm)
{
- dm->drawMappedEdges(dm, draw_dm_edges_freestyle__setDrawOptions, NULL);
+ dm->drawMappedEdges(dm, draw_dm_edges_freestyle__setDrawOptions, em);
}
/* Draw faces with color set based on selection
@@ -2438,15 +2472,18 @@ static void draw_dm_edges_freestyle(DerivedMesh *dm)
static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *UNUSED(drawSmooth_r))
{
drawDMFacesSel_userData * data = userData;
- EditFace *efa = EM_get_face_for_index(index);
+ BMFace *efa = EDBM_get_face_for_index(data->em, index);
unsigned char *col;
- if (efa->h==0) {
+ if (!efa)
+ return 0;
+
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
if (efa == data->efa_act) {
glColor4ubv(data->cols[3]);
return 2; /* stipple */
} else {
- col = data->cols[(efa->f & SELECT) ? 1 : (efa->flag & ME_FREESTYLE_FACE) ? 2 : 0];
+ col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT)?1:BM_elem_flag_test(efa, BM_ELEM_FREESTYLE)?2:0];
if (col[3]==0) return 0;
glColor4ubv(col);
return 1;
@@ -2457,16 +2494,18 @@ static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *UNU
static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
{
+
drawDMFacesSel_userData *data = userData;
- EditFace *efa;
- EditFace *next_efa;
+ BMFace *efa;
+ BMFace *next_efa;
+
unsigned char *col, *next_col;
if(!data->orig_index)
return 0;
- efa= EM_get_face_for_index(data->orig_index[index]);
- next_efa= EM_get_face_for_index(data->orig_index[next_index]);
+ efa= EDBM_get_face_for_index(data->em, data->orig_index[index]);
+ next_efa= EDBM_get_face_for_index(data->em, data->orig_index[next_index]);
if(efa == next_efa)
return 1;
@@ -2474,8 +2513,8 @@ static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int
if(efa == data->efa_act || next_efa == data->efa_act)
return 0;
- col = data->cols[(efa->f & SELECT) ? 1 : (efa->flag & ME_FREESTYLE_FACE) ? 2 : 0];
- next_col = data->cols[(next_efa->f & SELECT) ? 1 : (next_efa->flag & ME_FREESTYLE_FACE) ? 2 : 0];
+ col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT)?1:BM_elem_flag_test(efa, BM_ELEM_FREESTYLE)?2:0];
+ next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT)?1:BM_elem_flag_test(next_efa, BM_ELEM_FREESTYLE)?2:0];
if(col[3]==0 || next_col[3]==0)
return 0;
@@ -2484,70 +2523,88 @@ static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int
}
/* also draws the active face */
-static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *markCol, unsigned char *actCol, EditFace *efa_act)
+static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
+ unsigned char *selCol, unsigned char *markCol, unsigned char *actCol, BMFace *efa_act)
{
drawDMFacesSel_userData data;
+ data.dm= dm;
data.cols[0] = baseCol;
+ data.em = em;
data.cols[1] = selCol;
data.cols[2] = markCol;
data.cols[3] = actCol;
data.efa_act = efa_act;
- data.orig_index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+ data.orig_index = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions, &data, 0);
}
-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.0f) {
- UI_ThemeColorBlend(TH_WIRE, TH_EDGE_CREASE, eed->crease);
+ BMEditMesh *em = userData;
+ BMEdge *eed = EDBM_get_edge_for_index(userData, index);
+ float *crease = eed ? (float *)CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE) : NULL;
+
+ if (!crease)
+ return 0;
+
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && *crease!=0.0f) {
+ 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 = (float *)CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_BWEIGHT);
- if (eed->h==0 && eed->bweight != 0.0f) {
- UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->bweight);
+ if (!bweight)
+ return 0;
+
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && *bweight!=0.0f) {
+ 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.0f) {
- UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, eve->bweight);
+ BMEditMesh *em = userData;
+ BMVert *eve = EDBM_get_vert_for_index(userData, index);
+ float *bweight = (float *)CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_BWEIGHT);
+
+ if (!bweight)
+ return;
+
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && *bweight!=0.0f) {
+ 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);
}
}
@@ -2561,8 +2618,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;
@@ -2599,13 +2656,13 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
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) {
@@ -2619,9 +2676,9 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
glPointSize(1.0);
}
-static void draw_em_fancy_edges(Scene *scene, View3D *v3d,
+static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
Mesh *me, DerivedMesh *cageDM, short sel_only,
- EditEdge *eed_act)
+ BMEdge *eed_act)
{
ToolSettings *ts= scene->toolsettings;
int pass;
@@ -2654,21 +2711,21 @@ static void draw_em_fancy_edges(Scene *scene, View3D *v3d,
}
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);
}
}
@@ -2679,13 +2736,10 @@ static void draw_em_fancy_edges(Scene *scene, View3D *v3d,
}
}
-static void draw_em_measure_stats(View3D *v3d, Object *ob, EditMesh *em, UnitSettings *unit)
+static void draw_em_measure_stats(View3D *v3d, Object *ob, BMEditMesh *em, UnitSettings *unit)
{
Mesh *me= ob->data;
- EditEdge *eed;
- EditFace *efa;
- float v1[3], v2[3], v3[3], v4[3], vmid[3];
- float fvec[3];
+ float v1[3], v2[3], v3[3], vmid[3], fvec[3];
char numstr[32]; /* Stores the measurement display text here */
const char *conv_float; /* Use a float conversion matching the grid size */
unsigned char col[4]= {0, 0, 0, 255}; /* color of the text to draw */
@@ -2695,6 +2749,9 @@ static void draw_em_measure_stats(View3D *v3d, Object *ob, EditMesh *em, UnitSet
const int do_global= v3d->flag & V3D_GLOBAL_STATS;
const int do_moving= G.moving;
+ BMIter iter;
+ int i;
+
/* make the precision of the pronted value proportionate to the gridsize */
if (grid < 0.01f) conv_float= "%.6g";
@@ -2704,11 +2761,16 @@ static void draw_em_measure_stats(View3D *v3d, Object *ob, EditMesh *em, UnitSet
else conv_float= "%.2g";
if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
+ BMEdge *eed;
+
UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
- for(eed= em->edges.first; eed; eed= eed->next) {
- /* draw non fgon edges, or selected edges, or edges next to selected verts while draging */
- if((eed->h != EM_FGON) && ((eed->f & SELECT) || (do_moving && ((eed->v1->f & SELECT) || (eed->v2->f & SELECT)) ))) {
+ eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for(; eed; eed=BM_iter_step(&iter)) {
+ /* draw selected edges, or edges next to selected verts while draging */
+ if(BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
+ (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) || BM_elem_flag_test(eed->v2, BM_ELEM_SELECT) ))) {
+
copy_v3_v3(v1, eed->v1->co);
copy_v3_v3(v2, eed->v2->co);
@@ -2733,96 +2795,92 @@ static void draw_em_measure_stats(View3D *v3d, Object *ob, EditMesh *em, UnitSet
}
if(me->drawflag & ME_DRAWEXTRA_FACEAREA) {
-// XXX extern int faceselectedOR(EditFace *efa, int flag); // editmesh.h shouldn't be in this file... ok for now?
+ /* would be nice to use BM_face_area_calc, but that is for 2d faces
+ so instead add up tessalation triangle areas */
+ BMFace *f;
+ int n;
+
+#define DRAW_EM_MEASURE_STATS_FACEAREA() \
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { \
+ mul_v3_fl(vmid, 1.0/n); \
+ if(unit->system) \
+ bUnit_AsString(numstr, sizeof(numstr), area*unit->scale_length, \
+ 3, unit->system, B_UNIT_LENGTH, do_split, FALSE); \
+ else \
+ BLI_snprintf(numstr, sizeof(numstr), conv_float, area); \
+ view3d_cached_text_draw_add(vmid, numstr, 0, V3D_CACHE_TEXT_ASCII, col); \
+ }
+
UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
- for(efa= em->faces.first; efa; efa= efa->next) {
- if((efa->f & SELECT)) { // XXX || (do_moving && faceselectedOR(efa, SELECT)) ) {
- copy_v3_v3(v1, efa->v1->co);
- copy_v3_v3(v2, efa->v2->co);
- copy_v3_v3(v3, efa->v3->co);
- if (efa->v4) {
- copy_v3_v3(v4, efa->v4->co);
- }
- if(do_global) {
- mul_mat3_m4_v3(ob->obmat, v1);
- mul_mat3_m4_v3(ob->obmat, v2);
- mul_mat3_m4_v3(ob->obmat, v3);
- if (efa->v4) mul_mat3_m4_v3(ob->obmat, v4);
- }
-
- if (efa->v4)
- area= area_quad_v3(v1, v2, v3, v4);
- else
- area = area_tri_v3(v1, v2, v3);
-
- if(unit->system) {
- // XXX should be B_UNIT_AREA
- bUnit_AsString(numstr, sizeof(numstr), area * unit->scale_length, 3,
- unit->system, B_UNIT_LENGTH, do_split, FALSE);
- }
- else {
- sprintf(numstr, conv_float, area);
- }
-
- view3d_cached_text_draw_add(efa->cent, numstr, 0, V3D_CACHE_TEXT_ASCII, col);
+ f = NULL;
+ area = 0.0;
+ zero_v3(vmid);
+ n = 0;
+ for(i = 0; i < em->tottri; i++) {
+ BMLoop **l = em->looptris[i];
+ if(f && l[0]->f != f) {
+ DRAW_EM_MEASURE_STATS_FACEAREA();
+ zero_v3(vmid);
+ area = 0.0;
+ n = 0;
+ }
+
+ f = l[0]->f;
+ copy_v3_v3(v1, l[0]->v->co);
+ copy_v3_v3(v2, l[1]->v->co);
+ copy_v3_v3(v3, l[2]->v->co);
+ if(do_global) {
+ mul_mat3_m4_v3(ob->obmat, v1);
+ mul_mat3_m4_v3(ob->obmat, v2);
+ mul_mat3_m4_v3(ob->obmat, v3);
}
+ area += area_tri_v3(v1, v2, v3);
+ add_v3_v3(vmid, v1);
+ add_v3_v3(vmid, v2);
+ add_v3_v3(vmid, v3);
+ n += 3;
}
+
+ if(f){
+ DRAW_EM_MEASURE_STATS_FACEAREA();
+ }
+#undef DRAW_EM_MEASURE_STATS_FACEAREA
}
if(me->drawflag & ME_DRAWEXTRA_FACEANG) {
- EditEdge *e1, *e2, *e3, *e4;
+ BMFace *efa;
+
UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
- for(efa= em->faces.first; efa; efa= efa->next) {
- copy_v3_v3(v1, efa->v1->co);
- copy_v3_v3(v2, efa->v2->co);
- copy_v3_v3(v3, efa->v3->co);
- if(efa->v4) {
- copy_v3_v3(v4, efa->v4->co);
- }
- else {
- copy_v3_v3(v4, v3);
- }
- if(do_global) {
- mul_mat3_m4_v3(ob->obmat, v1);
- mul_mat3_m4_v3(ob->obmat, v2);
- mul_mat3_m4_v3(ob->obmat, v3);
- mul_mat3_m4_v3(ob->obmat, v4); /* intentionally executed even for tri's */
- }
-
- e1= efa->e1;
- e2= efa->e2;
- e3= efa->e3;
- if(efa->e4) e4= efa->e4; else e4= e3;
-
- /* Calculate the angles */
-
- if( (e4->f & e1->f & SELECT) || (do_moving && (efa->v1->f & SELECT)) ) {
- /* Vec 1 */
- sprintf(numstr,"%.3g", RAD2DEGF(angle_v3v3v3(v4, v1, v2)));
- interp_v3_v3v3(fvec, efa->cent, efa->v1->co, 0.8f);
- view3d_cached_text_draw_add(fvec, numstr, 0, V3D_CACHE_TEXT_ASCII, col);
- }
- if( (e1->f & e2->f & SELECT) || (do_moving && (efa->v2->f & SELECT)) ) {
- /* Vec 2 */
- sprintf(numstr,"%.3g", RAD2DEGF(angle_v3v3v3(v1, v2, v3)));
- interp_v3_v3v3(fvec, efa->cent, efa->v2->co, 0.8f);
- view3d_cached_text_draw_add(fvec, numstr, 0, V3D_CACHE_TEXT_ASCII, col);
- }
- if( (e2->f & e3->f & SELECT) || (do_moving && (efa->v3->f & SELECT)) ) {
- /* Vec 3 */
- if(efa->v4)
- sprintf(numstr,"%.3g", RAD2DEGF(angle_v3v3v3(v2, v3, v4)));
- else
- sprintf(numstr,"%.3g", RAD2DEGF(angle_v3v3v3(v2, v3, v1)));
- interp_v3_v3v3(fvec, efa->cent, efa->v3->co, 0.8f);
- view3d_cached_text_draw_add(fvec, numstr, 0, V3D_CACHE_TEXT_ASCII, col);
- }
- /* Vec 4 */
- if(efa->v4) {
- if( (e3->f & e4->f & SELECT) || (do_moving && (efa->v4->f & SELECT)) ) {
- sprintf(numstr,"%.3g", RAD2DEGF(angle_v3v3v3(v3, v4, v1)));
- interp_v3_v3v3(fvec, efa->cent, efa->v4->co, 0.8f);
+
+
+ for(efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ efa; efa=BM_iter_step(&iter)) {
+ BMIter liter;
+ BMLoop *loop;
+
+ BM_face_center_bounds_calc(em->bm, efa, vmid);
+
+ for(loop = BM_iter_new(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
+ loop; loop = BM_iter_step(&liter)) {
+
+ float v1[3], v2[3], v3[3];
+
+ copy_v3_v3(v1, loop->prev->v->co);
+ copy_v3_v3(v2, loop->v->co);
+ copy_v3_v3(v3, loop->next->v->co);
+
+ if(do_global){
+ mul_mat3_m4_v3(ob->obmat, v1);
+ mul_mat3_m4_v3(ob->obmat, v2);
+ mul_mat3_m4_v3(ob->obmat, v3);
+ }
+
+ if ( (BM_elem_flag_test(efa, BM_ELEM_SELECT)) ||
+ (do_moving && BM_elem_flag_test(loop->v, BM_ELEM_SELECT)))
+ {
+ BLI_snprintf(numstr, sizeof(numstr), "%.3g", RAD2DEGF(angle_v3v3v3(v1, v2, v3)));
+ interp_v3_v3v3(fvec, vmid, v2, 0.8f);
view3d_cached_text_draw_add(fvec, numstr, 0, V3D_CACHE_TEXT_ASCII, col);
}
}
@@ -2830,55 +2888,64 @@ static void draw_em_measure_stats(View3D *v3d, Object *ob, EditMesh *em, UnitSet
}
}
-static void draw_em_indices(EditMesh *em)
+static void draw_em_indices(BMEditMesh *em)
{
- EditEdge *e;
- EditFace *f;
- EditVert *v;
+ BMEdge *e;
+ BMFace *f;
+ BMVert *v;
int i;
char numstr[32];
float pos[3];
unsigned char col[4];
- /* For now, reuse appropriate theme colors from stats text colors */
+ BMIter iter;
+ BMesh *bm= em->bm;
+ /* For now, reuse appropriate theme colors from stats text colors */
+ i= 0;
if (em->selectmode & SCE_SELECT_VERTEX) {
UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
- for (v = em->verts.first, i = 0; v; v = v->next, i++) {
- if (v->f & SELECT) {
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
sprintf(numstr, "%d", i);
view3d_cached_text_draw_add(v->co, numstr, 0, V3D_CACHE_TEXT_ASCII, col);
}
+ i++;
}
}
if (em->selectmode & SCE_SELECT_EDGE) {
+ i= 0;
UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
- for (e = em->edges.first, i = 0; e; e = e->next, i++) {
- if (e->f & SELECT) {
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
sprintf(numstr, "%d", i);
mid_v3_v3v3(pos, e->v1->co, e->v2->co);
view3d_cached_text_draw_add(pos, numstr, 0, V3D_CACHE_TEXT_ASCII, col);
}
+ i++;
}
}
if (em->selectmode & SCE_SELECT_FACE) {
+ i= 0;
UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
- for (f = em->faces.first, i = 0; f; f = f->next, i++) {
- if (f->f & SELECT) {
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ BM_face_center_mean_calc(bm, f, pos);
sprintf(numstr, "%d", i);
- view3d_cached_text_draw_add(f->cent, numstr, 0, V3D_CACHE_TEXT_ASCII, col);
+ view3d_cached_text_draw_add(pos, numstr, 0, V3D_CACHE_TEXT_ASCII, col);
}
+ i++;
}
}
}
-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_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
GPU_enable_material(efa->mat_nr+1, NULL);
return 1;
}
@@ -2886,34 +2953,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_elem_flag_test(efa, BM_ELEM_HIDDEN);
}
static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
- Object *ob, EditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt)
+ 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 = BM_active_face_get(em->bm, FALSE); /* 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;
- } else if ( ese->type == EDITVERT ) {
- eve_act = (EditVert *)ese->data;
+ /*if (ese->type == BM_FACE ) {
+ efa_act = (BMFace *)ese->data;
+ } else */ if ( ese->htype == BM_EDGE ) {
+ eed_act = (BMEdge *)ese->data;
+ } else if ( ese->htype == BM_VERT ) {
+ 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)) {
@@ -2937,7 +3005,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
glEnable(GL_LIGHTING);
glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
- finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_enable_material, NULL, NULL, 0);
+ finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_enable_material, NULL, me->edit_btmesh, 0);
glFrontFace(GL_CCW);
glDisable(GL_LIGHTING);
@@ -2975,7 +3043,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
if (!(me->drawflag & ME_DRAW_FREESTYLE_FACE))
col3[3] = 0;
- draw_dm_faces_sel(cageDM, col1, col2, col3, col4, efa_act);
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
glDisable(GL_BLEND);
glDepthMask(1); // restore write in zbuffer
@@ -2990,7 +3058,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
glEnable(GL_BLEND);
glDepthMask(0); // disable write in zbuffer, needed for nice transp
- draw_dm_faces_sel(cageDM, col1, col2, col3, col4, efa_act);
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
glDisable(GL_BLEND);
glDepthMask(1); // restore write in zbuffer
@@ -3002,14 +3070,14 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
/* 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);
@@ -3019,7 +3087,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
UI_ThemeColor(TH_EDGE_SHARP);
glLineWidth(2);
- draw_dm_edges_sharp(cageDM);
+ draw_dm_edges_sharp(em, cageDM);
glColor3ub(0,0,0);
glLineWidth(1);
@@ -3029,31 +3097,31 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
UI_ThemeColor(TH_FREESTYLE_EDGE_MARK);
glLineWidth(2);
- draw_dm_edges_freestyle(cageDM);
+ draw_dm_edges_freestyle(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);
}
- 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) {
- 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_DRAWEXTRA_EDGELEN|ME_DRAWEXTRA_FACEAREA|ME_DRAWEXTRA_FACEANG)) &&
@@ -3074,7 +3142,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
GPU_disable_material();
}
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
}
/* Mesh drawing routines */
@@ -3126,7 +3194,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
/* Check to draw dynamic paint colors (or weights from WeightVG modifiers).
* Note: Last "preview-active" modifier in stack will win! */
- if(DM_get_face_data_layer(dm, CD_WEIGHT_MCOL) && modifiers_isPreview(ob))
+ if(DM_get_tessface_data_layer(dm, CD_WEIGHT_MCOL) && modifiers_isPreview(ob))
draw_flags |= DRAW_MODIFIERS_PREVIEW;
/* Unwanted combination */
@@ -3139,7 +3207,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? */
glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
@@ -3197,7 +3265,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
/* weight paint in solid mode, special case. focus on making the weights clear
* rather than the shading, this is also forced in wire view */
GPU_enable_material(0, NULL);
- dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, GPU_enable_material, NULL, me->mface, 1);
+ dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, GPU_enable_material, NULL, me->mpoly, 1);
bglPolygonOffset(rv3d->dist, 1.0);
glDepthMask(0); // disable write in zbuffer, selected edge wires show better
@@ -3322,14 +3390,14 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
- dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, GPU_enable_material, NULL, me->mface, 1);
+ dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, GPU_enable_material, NULL, me->mpoly, 1);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHTING);
GPU_disable_material();
}
else if(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_TEXTURE_PAINT)) {
- if(me->mcol)
+ if(me->mloopcol)
dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, GPU_enable_material, NULL, NULL, 1);
else {
glColor3f(1.0f, 1.0f, 1.0f);
@@ -3416,7 +3484,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_after= 0, drawlinked= 0, retval= 0, glsl, check_alpha, i;
/* If we are drawing shadows and any of the materials don't cast a shadow,
@@ -3440,9 +3508,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) {
@@ -3460,7 +3528,7 @@ static int draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
}
else {
/* don't create boundbox here with mesh_get_bb(), the derived system will make it, puts deformed bb's OK */
- if(me->totface<=4 || ED_view3d_boundbox_clip(rv3d, ob->obmat, (ob->bb)? ob->bb: me->bb)) {
+ if(me->totpoly <= 4 || ED_view3d_boundbox_clip(rv3d, ob->obmat, (ob->bb)? ob->bb: me->bb)) {
glsl = draw_glsl_material(scene, ob, v3d, dt);
check_alpha = check_alpha_pass(base);
@@ -3729,7 +3797,7 @@ static int drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d, B
return 1;
}
- if(dt>OB_WIRE && dm->getNumFaces(dm)) {
+ if(dt>OB_WIRE && dm->getNumTessFaces(dm)) {
int glsl = draw_glsl_material(scene, ob, v3d, dt);
GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
@@ -6073,7 +6141,7 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base)
int hasfaces= 0;
if (dm) {
- hasfaces= dm->getNumFaces(dm);
+ hasfaces= dm->getNumTessFaces(dm);
} else {
hasfaces= displist_has_faces(&ob->disp);
}
@@ -7004,44 +7072,51 @@ static void bbs_obmode_mesh_verts(Object *ob, DerivedMesh *dm, int offset)
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_elem_flag_test(eve, BM_ELEM_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_elem_flag_test(eed, BM_ELEM_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) {
+ BMFace *efa = EDBM_get_face_for_index(((void**)userData)[0], index);
+
+ if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ if (((void**)userData)[1]) {
WM_set_framebuffer_index_color(index+1);
}
return 1;
@@ -7050,11 +7125,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_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
WM_set_framebuffer_index_color(index+1);
bglVertex3fv(cent);
@@ -7062,24 +7137,26 @@ 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,
+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, GPU_enable_material, NULL, (void*)(intptr_t) 1, 0);
+ ptrs[1] = (void*)(intptr_t) 1;
+ dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, GPU_enable_material, NULL, ptrs, 0);
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, GPU_enable_material, NULL, (void*) 0, 0);
+ dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, GPU_enable_material, NULL, ptrs, 0);
}
}
@@ -7093,7 +7170,7 @@ static int bbs_mesh_solid_hide__setDrawOpts(void *userData, int index, int *UNUS
{
Mesh *me = userData;
- if (!(me->mface[index].flag&ME_HIDE)) {
+ if (!(me->mpoly[index].flag&ME_HIDE)) {
WM_set_framebuffer_index_color(index+1);
return 1;
} else {
@@ -7106,7 +7183,7 @@ static int bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index, int *UNU
{
Mesh *me = userData;
- if (!(me->mface[index].flag & ME_HIDE)) {
+ if (!(me->mpoly[index].flag & ME_HIDE)) {
return 1;
} else {
return 0;
@@ -7140,36 +7217,36 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
case OB_MESH:
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 {
Mesh *me= ob->data;
@@ -7184,7 +7261,7 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
bbs_obmode_mesh_verts(ob, dm, 1);
- em_vertoffs = me->totvert+1;
+ bm_vertoffs = me->totvert+1;
dm->release(dm);
}
else {
@@ -7213,7 +7290,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/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index 1ed8e44a26b..61b4260450b 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -38,12 +38,12 @@
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
+#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_editVert.h"
#include "BLI_edgehash.h"
#include "BLI_rand.h"
-#include "BLI_utildefines.h"
#include "BKE_curve.h"
#include "BKE_constraint.h" // for the get_constraint_target function
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 5238fd30ae6..98301e63705 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -58,6 +58,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_screen.h"
+#include "BKE_tessmesh.h"
#include "BKE_deform.h"
#include "BKE_object.h"
@@ -153,32 +154,36 @@ 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_elem_flag_test(eve, BM_ELEM_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_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ float *f;
+
totedge++;
- median[3]+= eed->crease;
- median[6]+= eed->bweight;
+ f = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_CREASE);
+ median[3]+= f ? *f : 0.0f;
+
+ f = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_BWEIGHT);
+ median[6]+= 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(&bm->vdata, evedef->head.data, CD_MDEFORMVERT);
if(tot==1 && dvert && dvert->totweight) {
bDeformGroup *dg;
int i, max=1, init=1;
@@ -202,8 +207,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;
@@ -409,31 +412,35 @@ 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;
+ BMesh *bm = em->bm;
+ BMVert *eve;
+ BMIter iter;
- /* allow for some rounding error becasue of matrix transform */
if(len_v3(median) > 0.000001f) {
- EditVert *eve;
- 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_elem_flag_test(eve, BM_ELEM_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.0f : (ve_median[3] >= 1.0f ? 1.0f : 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, bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ float *crease = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_CREASE);
+ if (!crease) break;
+
+ *crease= fixed_crease;
}
}
}
@@ -450,10 +457,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.0f, 1.0f);
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ float *crease = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_CREASE);
+
+ if (!crease) break;
+
+ *crease *= sca;
+ CLAMP(*crease, 0.0f, 1.0f);
}
}
}
@@ -461,33 +472,39 @@ 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.0f, 1.0f);
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ float *crease = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_CREASE);
+ if (!crease) break;
+
+ *crease = 1.0f - ((1.0f - *crease) * sca);
+ CLAMP(*crease, 0.0f, 1.0f);
}
}
}
}
}
- if (median[6] != 0.0f) {
- EditEdge *eed;
- const float fixed_bweight= (ve_median[6] <= 0.0f ? 0.0f : (ve_median[6] >= 1.0f ? 1.0f : FLT_MAX));
+ if(median[6] != 0.0f) {
+ BMEdge *eed;
+ const float fixed_bweight = (ve_median[6] <= 0.0f ? 0.0f : (ve_median[6] >= 1.0f ? 1.0f : FLT_MAX));
if(fixed_bweight != FLT_MAX) {
/* simple case */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- eed->bweight= fixed_bweight;
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ float *bweight = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_BWEIGHT);
+ if(!bweight) break;
+
+ *bweight = fixed_bweight;
}
}
}
else {
/* scale crease to target median */
- float median_new= ve_median[6];
- float median_orig= ve_median[6] - median[6]; /* previous median value */
+ float median_new = ve_median[6];
+ float median_orig = ve_median[6] - median[6]; /* previous median value */
/* incase of floating point error */
CLAMP(median_orig, 0.0f, 1.0f);
@@ -495,29 +512,35 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
if(median_new < median_orig) {
/* scale down */
- const float sca= median_new / median_orig;
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- eed->bweight *= sca;
- CLAMP(eed->bweight, 0.0f, 1.0f);
+ const float sca = median_new / median_orig;
+
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ float *bweight = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_BWEIGHT);
+ if(!bweight) break;
+
+ *bweight *= sca;
+ CLAMP(*bweight, 0.0f, 1.0f);
}
}
}
else {
/* scale up */
- const float sca= (1.0f - median_new) / (1.0f - median_orig);
+ 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->bweight = 1.0f - ((1.0f - eed->bweight) * sca);
- CLAMP(eed->bweight, 0.0f, 1.0f);
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ float *bweight = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_BWEIGHT);
+ if(!bweight) break;
+
+ *bweight = 1.0f - ((1.0f - *bweight) * sca);
+ CLAMP(*bweight, 0.0f, 1.0f);
}
}
}
}
}
- BKE_mesh_end_editmesh(me, em);
+ EDBM_RecalcNormals(em);
}
else if(ob->type==OB_CURVE || ob->type==OB_SURF) {
Curve *cu= ob->data;
@@ -594,37 +617,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->htype == 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 */
@@ -646,7 +667,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);
@@ -659,7 +680,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);
@@ -669,14 +690,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_elem_flag_test(eve, BM_ELEM_SELECT) && eve != eve_act) {
+ dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
if(dvert) {
defvert_copy(dvert, dvert_act);
@@ -685,13 +707,15 @@ static void vgroup_copy_active_to_sel(Object *ob)
}
}
+
+ index++;
}
}
}
static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
{
- EditVert *eve_act;
+ BMVert *eve_act;
MDeformVert *dv_act;
act_vert_def(ob, &eve_act, &dv_act);
@@ -701,8 +725,9 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const 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 *dv;
MDeformWeight *dw;
float weight_act;
@@ -712,26 +737,25 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
if(dw == NULL)
return;
-
+
weight_act= dw->weight;
- for (eve= em->verts.first; eve; eve= eve->next, index++) {
- if (eve->f & SELECT && eve != eve_act) {
- dv= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
- if(dv) {
- dw= defvert_find_index(dv, def_nr);
- if (dw) {
- dw->weight= weight_act;
+ eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for (index=0; eve; eve=BM_iter_step(&iter), index++) {
+ if(BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve != eve_act) {
+ dv= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
+ dw= defvert_find_index(dv, def_nr);
+ if (dw) {
+ dw->weight= weight_act;
- if (me->editflag & ME_EDIT_MIRROR_X) {
- editvert_mirror_update(ob, eve, -1, index);
- }
+ if (me->editflag & ME_EDIT_MIRROR_X) {
+ editvert_mirror_update(ob, eve, -1, index);
}
}
}
}
- if (me->editflag & ME_EDIT_MIRROR_X) {
+ if(me->editflag & ME_EDIT_MIRROR_X) {
editvert_mirror_update(ob, eve_act, -1, -1);
}
}
@@ -739,7 +763,7 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const 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);
@@ -787,7 +811,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);
@@ -802,7 +826,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 *dv;
act_vert_def(ob, &eve, &dv);
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 4f46a746b9e..c73d8e14f05 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1584,7 +1584,7 @@ static void draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d)
/* calc window coord */
initgrabz(rv3d, 0.0, 0.0, 0.0);
ED_view3d_win_to_delta(ar, mval_f, vec);
- fac= MAX3( fabs(vec[0]), fabs(vec[1]), fabs(vec[1]) );
+ fac= maxf(fabsf(vec[0]), maxf(fabsf(vec[1]), fabsf(vec[2]))); /* largest abs axis */
fac= 1.0f/fac;
asp= ( (float)ibuf->y)/(float)ibuf->x;
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 1df0b3a8a4e..0a942a42540 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -55,6 +55,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"
@@ -336,12 +337,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 */
@@ -362,7 +363,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");
}
@@ -371,12 +372,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");
}
@@ -384,14 +385,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");
}
@@ -424,9 +424,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 */
@@ -451,7 +448,7 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
uiBlockSetHandleFunc(block, do_view3d_header_buttons, NULL);
if(obedit && (obedit->type == OB_MESH)) {
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
uiLayout *row;
row= uiLayoutRow(layout, 1);
@@ -459,8 +456,6 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL, 0,0,UI_UNIT_X,UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0, "Vertex select mode");
uiDefIconButBitS(block, TOG, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL, 0,0,UI_UNIT_X,UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0, "Edge select mode");
uiDefIconButBitS(block, TOG, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL, 0,0,UI_UNIT_X,UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0, "Face select mode");
-
- BKE_mesh_end_editmesh(obedit->data, em);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index f98149d2485..ec6d1bdbe87 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -61,6 +61,7 @@
#include "BKE_context.h"
#include "BKE_paint.h"
#include "BKE_armature.h"
+#include "BKE_tessmesh.h"
#include "BKE_movieclip.h"
#include "BKE_object.h"
#include "BKE_tracking.h"
@@ -164,43 +165,49 @@ void view3d_get_transformation(const ARegion *ar, RegionView3D *rv3d, Object *ob
/* local prototypes */
-static void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
+static 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 = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for ( ; eve; eve=BM_iter_step(&iter), index++) {
+ if(!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ if(EDBM_check_backbuf(index)) {
+ BM_vert_select_set(em->bm, eve, select);
}
}
}
}
-static void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
+static 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 = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BM_iter_step(&iter), index++) {
+ if(!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ if(EDBM_check_backbuf(index)) {
+ BM_edge_select_set(em->bm, eed, select);
}
}
}
}
-static void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
+static 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 = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BM_iter_step(&iter), index++) {
+ if(!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ if(EDBM_check_backbuf(index)) {
+ BM_face_select_set(em->bm, efa, select);
}
}
}
@@ -208,14 +215,14 @@ static void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
/* object mode, EM_ prefix is confusing here, rename? */
-static void EM_backbuf_checkAndSelectVerts_obmode(Mesh *me, int select)
+static void EDBM_backbuf_checkAndSelectVerts_obmode(Mesh *me, int select)
{
MVert *mv = me->mvert;
int a;
if (mv) {
for(a=1; a<=me->totvert; a++, mv++) {
- if(EM_check_backbuf(a)) {
+ if(EDBM_check_backbuf(a)) {
if(!(mv->flag & ME_HIDE)) {
mv->flag = select?(mv->flag|SELECT):(mv->flag&~SELECT);
}
@@ -224,15 +231,16 @@ static void EM_backbuf_checkAndSelectVerts_obmode(Mesh *me, int select)
}
}
/* object mode, EM_ prefix is confusing here, rename? */
-static void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
+
+static 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);
}
}
}
@@ -460,39 +468,39 @@ static void lasso_select_boundbox(rcti *rect, int 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))
{
LassoSelectUserData *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_elem_select_set(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)
{
LassoSelectUserData *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_elem_select_set(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_elem_select_set(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))
{
LassoSelectUserData *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_elem_select_set(data->vc->em->bm, efa, data->select);
}
}
@@ -506,7 +514,7 @@ static void do_lasso_select_mesh(ViewContext *vc, int 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;
@@ -517,17 +525,17 @@ static void do_lasso_select_mesh(ViewContext *vc, int mcords[][2], short moves,
data.pass = 0;
if (extend == 0 && select)
- EM_deselect_all(vc->em);
+ EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT);
/* for non zbuf projections, dont change the GL state */
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 {
mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, V3D_CLIP_TEST_RV3D_CLIPPING);
@@ -546,15 +554,15 @@ static void do_lasso_select_mesh(ViewContext *vc, int 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 {
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
@@ -832,14 +840,14 @@ static void do_lasso_select_paintvert(ViewContext *vc, int mcords[][2], short mo
if(extend==0 && select)
paintvert_deselect_all_visible(ob, SEL_DESELECT, FALSE); /* flush selection at the end */
- em_vertoffs= me->totvert+1; /* max index array */
+ bm_vertoffs= me->totvert+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_checkAndSelectVerts_obmode(me, select);
+ EDBM_backbuf_checkAndSelectVerts_obmode(me, select);
- EM_free_backbuf();
+ EDBM_free_backbuf();
paintvert_flush_flags(ob);
}
@@ -849,20 +857,20 @@ static void do_lasso_select_paintface(ViewContext *vc, int mcords[][2], short mo
Mesh *me= ob?ob->data:NULL;
rcti rect;
- if(me==NULL || me->totface==0)
+ if(me==NULL || me->totpoly==0)
return;
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);
}
@@ -1728,37 +1736,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))
{
BoxSelectUserData *data = userData;
if (BLI_in_rcti(data->rect, x, y)) {
- eve->f = data->select?(eve->f|1):(eve->f&~1);
+ BM_elem_select_set(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)
{
BoxSelectUserData *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_elem_select_set(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_elem_select_set(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))
{
BoxSelectUserData *data = userData;
if (BLI_in_rcti(data->rect, x, y)) {
- EM_select_face_fgon(data->vc->em, efa, data->select);
+ BM_elem_select_set(data->vc->em->bm, efa, data->select);
}
}
static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int extend)
@@ -1774,17 +1782,17 @@ 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_flag_disable_all(vc->em, BM_ELEM_SELECT);
/* for non zbuf projections, dont change the GL state */
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 {
mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, V3D_CLIP_TEST_RV3D_CLIPPING);
}
@@ -1803,15 +1811,15 @@ 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 {
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;
}
@@ -2045,7 +2053,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) {
@@ -2269,32 +2277,32 @@ typedef struct CircleSelectUserData {
float radius;
} CircleSelectUserData;
-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))
{
CircleSelectUserData *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_elem_select_set(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))
{
CircleSelectUserData *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_elem_select_set(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))
{
CircleSelectUserData *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_elem_select_set(data->vc->em->bm, efa, data->select);
}
}
@@ -2304,10 +2312,10 @@ static void mesh_circle_select(ViewContext *vc, int select, const int mval[2], f
int bbsel;
CircleSelectUserData data;
- bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0f));
+ 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;
@@ -2317,7 +2325,7 @@ static void mesh_circle_select(ViewContext *vc, int select, const int mval[2], f
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, V3D_CLIP_TEST_RV3D_CLIPPING);
}
@@ -2325,7 +2333,7 @@ static void mesh_circle_select(ViewContext *vc, int select, const int mval[2], f
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, V3D_CLIP_TEST_OFF);
}
@@ -2333,14 +2341,14 @@ static void mesh_circle_select(ViewContext *vc, int select, const int mval[2], f
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, const int mval[2], float rad)
@@ -2350,11 +2358,11 @@ static void paint_facesel_circle_select(ViewContext *vc, int select, const int m
/* int bbsel; */ /* UNUSED */
if (me) {
- em_vertoffs= me->totface+1; /* max index array */
+ bm_vertoffs= me->totpoly+1; /* max index array */
- /* bbsel= */ /* UNUSED */ EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0f));
- EM_backbuf_checkAndSelectTFaces(me, select==LEFTMOUSE);
- EM_free_backbuf();
+ /* bbsel= */ /* UNUSED */ EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
+ EDBM_backbuf_checkAndSelectTFaces(me, select==LEFTMOUSE);
+ EDBM_free_backbuf();
}
}
@@ -2366,11 +2374,11 @@ static void paint_vertsel_circle_select(ViewContext *vc, int select, const int m
/* int bbsel; */ /* UNUSED */
/* CircleSelectUserData data = {NULL}; */ /* UNUSED */
if (me) {
- em_vertoffs= me->totvert+1; /* max index array */
+ bm_vertoffs= me->totvert+1; /* max index array */
- /* bbsel= */ /* UNUSED */ EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0f));
- EM_backbuf_checkAndSelectVerts_obmode(me, select==LEFTMOUSE);
- EM_free_backbuf();
+ /* bbsel= */ /* UNUSED */ EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0f));
+ EDBM_backbuf_checkAndSelectVerts_obmode(me, select==LEFTMOUSE);
+ EDBM_free_backbuf();
paintvert_flush_flags(ob);
}
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index 3665b0b13c3..087ed8380d6 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -55,6 +55,8 @@
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_object.h"
+#include "BKE_tessmesh.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_scene.h"
#include "BKE_tracking.h"
@@ -80,12 +82,15 @@ extern float originmat[3][3]; /* XXX object.c */
typedef struct TransVert {
float *loc;
- float oldloc[3], fac;
+ float oldloc[3], maploc[3], fac;
float *val, oldval;
int flag;
float *nor;
} TransVert;
+ /* SELECT == (1 << 0) */
+#define TX_VERT_USE_MAPLOC (1 << 1)
+
static TransVert *transvmain=NULL;
static int tottrans= 0;
@@ -97,7 +102,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_mesh_normals_update(me->edit_btmesh->bm); // does face centers too
}
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
Curve *cu= obedit->data;
@@ -188,6 +193,19 @@ static void special_transvert_update(Object *obedit)
}
}
+static void set_mapped_co(void *vuserdata, int index, float *co, float *UNUSED(no), short *UNUSED(no_s))
+{
+ void ** userdata = vuserdata;
+ BMEditMesh *em = userdata[0];
+ TransVert *tv = userdata[1];
+ BMVert *eve = EDBM_get_vert_for_index(em, index);
+
+ if (BM_elem_index_get(eve) != -1 && !(tv[BM_elem_index_get(eve)].flag & TX_VERT_USE_MAPLOC)) {
+ copy_v3_v3(tv[BM_elem_index_get(eve)].maploc, co);
+ tv[BM_elem_index_get(eve)].flag |= TX_VERT_USE_MAPLOC;
+ }
+}
+
/* copied from editobject.c, needs to be replaced with new transform code still */
/* mode flags: */
#define TM_ALL_JOINTS 1 /* all joints (for bones only) */
@@ -199,7 +217,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;
@@ -211,53 +229,91 @@ 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;
+ void *userdata[2] = {em, NULL};
+ /*int proptrans= 0; */ /*UNUSED*/
+ /* abuses vertex index all over, set, just set dirty here,
+ * perhaps this could use its own array instead? - campbell */
+
// 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;
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ BM_elem_index_set(eve, 1); /* set_dirty! */
tottrans++;
}
- else eve->f1= 0;
+ else BM_elem_index_set(eve, 0); /* set_dirty! */
}
}
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;
+ BMEdge *eed;
+
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
+ BM_elem_index_set(eve, 0); /* set_dirty! */
+
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if(!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ BM_elem_index_set(eed->v1, 1); /* set_dirty! */
+ BM_elem_index_set(eed->v2, 1); /* set_dirty! */
+ }
}
- for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
+
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
+ if(BM_elem_index_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)
+ BM_elem_index_set(eve, 0); /* set_dirty! */
+
+ BM_ITER(efa, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if(!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BMIter liter;
+ BMLoop *l;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) {
+ BM_elem_index_set(l->v, 1); /* set_dirty! */
+ }
}
}
- for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
+
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
+ if(BM_elem_index_get(eve)) tottrans++;
}
+ /* for any of the 3 loops above which all dirty the indicies */
+ bm->elem_index_dirty |= BM_VERT;
/* 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) {
+
+ a = 0;
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(BM_elem_index_get(eve)) {
+ BM_elem_index_set(eve, a); /* set_dirty! */
copy_v3_v3(tv->oldloc, eve->co);
tv->loc= eve->co;
if(eve->no[0] != 0.0f || eve->no[1] != 0.0f ||eve->no[2] != 0.0f)
tv->nor= eve->no; // note this is a hackish signal (ton)
- tv->flag= eve->f1 & SELECT;
+ tv->flag= BM_elem_index_get(eve) & SELECT;
tv++;
- }
+ a++;
+ } else BM_elem_index_set(eve, -1); /* set_dirty! */
}
+ /* set dirty already, above */
+
+ userdata[1] = transvmain;
+ }
+
+ if (transvmain && em->derivedCage) {
+ EDBM_init_index_arrays(em, 1, 0, 0);
+ em->derivedCage->foreachMappedVert(em->derivedCage, set_mapped_co, userdata);
+ EDBM_free_index_arrays(em);
}
}
else if (obedit->type==OB_ARMATURE){
@@ -927,10 +983,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);
@@ -1013,7 +1069,7 @@ int minmax_verts(Object *obedit, float *min, float *max)
tv= transvmain;
for(a=0; a<tottrans; a++, tv++) {
- copy_v3_v3(vec, tv->loc);
+ copy_v3_v3(vec, (tv->flag & TX_VERT_USE_MAPLOC) ? tv->maploc : tv->loc);
mul_m3_v3(bmat, vec);
add_v3_v3(vec, obedit->obmat[3]);
add_v3_v3(centroid, vec);
@@ -1025,4 +1081,3 @@ int minmax_verts(Object *obedit, float *min, float *max)
return 1;
}
-
diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c
index 0705d066f26..86a2abe7a74 100644
--- a/source/blender/editors/space_view3d/view3d_toolbar.c
+++ b/source/blender/editors/space_view3d/view3d_toolbar.c
@@ -268,3 +268,4 @@ void VIEW3D_OT_toolshelf(wmOperatorType *ot)
/* flags */
ot->flag= 0;
}
+
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 1a2e8932411..c05f9de691b 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -756,7 +756,6 @@ void ED_view3d_ob_project_mat_get(RegionView3D *rv3d, Object *ob, float pmat[4][
mult_m4_m4m4(pmat, rv3d->winmat, vmat);
}
-#if 0
/* Uses window coordinates (x,y) and depth component z to find a point in
modelspace */
void view3d_unproject(bglMats *mats, float out[3], const short x, const short y, const float z)
@@ -769,7 +768,6 @@ void view3d_unproject(bglMats *mats, float out[3], const short x, const short y,
out[1] = uy;
out[2] = uz;
}
-#endif
/* use view3d_get_object_project_mat to get projecting mat */
void ED_view3d_project_float(const ARegion *ar, const float vec[3], float adr[2], float mat[4][4])
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index a659afbbada..98461918151 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenkernel
../../blenlib
../../blenloader
+ ../../bmesh
../../makesdna
../../makesrna
../../windowmanager
diff --git a/source/blender/editors/transform/SConscript b/source/blender/editors/transform/SConscript
index f2d5baecfb3..0cf3875aa2e 100644
--- a/source/blender/editors/transform/SConscript
+++ b/source/blender/editors/transform/SConscript
@@ -6,6 +6,6 @@ sources = env.Glob('*.c')
incs = '../include ../../blenfont ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../render/extern/include'
-incs += ' ../../gpu ../../makesrna ../../blenloader'
+incs += ' ../../gpu ../../makesrna ../../blenloader ../../bmesh'
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 15bd14ce94c..862b68ea7e1 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -84,6 +84,8 @@
#include "BLI_editVert.h"
#include "BLI_ghash.h"
#include "BLI_linklist.h"
+#include "BLI_smallhash.h"
+#include "BLI_array.h"
#include "UI_resources.h"
@@ -93,6 +95,8 @@
#include "transform.h"
+#include <stdio.h>
+
static void drawTransformApply(const struct bContext *C, struct ARegion *ar, void *arg);
static int doEdgeSlide(TransInfo *t, float perc);
@@ -3489,7 +3493,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);
}
@@ -4283,506 +4288,467 @@ int BoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
}
/* ******************** Edge Slide *************** */
+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_elem_flag_test(e2, BM_ELEM_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_face_other_loop(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_edge_other_vert(olde, v)->co, v->co);
+ sub_v3_v3v3(f2, BM_edge_other_vert(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);
+ }
+
+ copy_v3_v3(vec, a);
+ return l;
+ } else {
+ sub_v3_v3v3(n, BM_edge_other_vert(l->e, v)->co, v->co);
+ add_v3_v3v3(a, a, n);
+ i += 1;
+ }
+
+ if (BM_face_other_loop(l->e, l->f, v)->e == nexte) {
+ if (i)
+ mul_v3_fl(a, 1.0f / (float)i);
+
+ copy_v3_v3(vec, a);
+ return BM_face_other_loop(l->e, l->f, v);
+ }
+
+ l = l->radial_next;
+ } while (l != firstl);
+
+ if (i)
+ mul_v3_fl(a, 1.0f / (float)i);
+
+ copy_v3_v3(vec, a);
+
+ return NULL;
+}
static int createSlideVerts(TransInfo *t)
{
Mesh *me = t->obedit->data;
- EditMesh *em = me->edit_mesh;
- EditFace *efa;
- EditEdge *eed,*first=NULL,*last=NULL, *temp = NULL;
- EditVert *ev, *nearest = NULL;
- LinkNode *edgelist = NULL, *vertlist=NULL, *look;
- GHash *vertgh;
+ 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;
- int i, j, numsel, numadded=0, timesthrough = 0, vertsel=0;
- /* UV correction vars */
- GHash **uvarray= NULL;
+ BMBVHTree *btree = BMBVH_NewBVH(em, 0, NULL, NULL);
+ SmallHash table;
SlideData *sld = MEM_callocN(sizeof(*sld), "sld");
- const int uvlay_tot= (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) ? CustomData_number_of_layers(&em->fdata, CD_MTFACE) : 0;
- int uvlay_idx;
- TransDataSlideUv *slideuvs=NULL, *suv=NULL, *suv_last=NULL;
- RegionView3D *v3d = t->ar ? t->ar->regiondata : NULL; /* background mode support */
+ View3D *v3d = t->sa ? t->sa->spacedata.first : NULL;
+ RegionView3D *rv3d = t->ar ? t->ar->regiondata : NULL; /* background mode support */
+ ARegion *ar = t->ar;
float projectMat[4][4];
- float start[3] = {0.0f, 0.0f, 0.0f}, end[3] = {0.0f, 0.0f, 0.0f};
- float vec[3];
- float totvec=0.0;
+ 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 {
- ED_view3d_ob_project_mat_get(v3d, t->obedit, projectMat);
+ ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
}
- 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;
- if(eed->f & SELECT) numsel++;
- }
-
- for(ev=em->verts.first;ev;ev=ev->next) {
- ev->f1 = 0;
- }
+ BLI_smallhash_init(&sld->vhash);
+ BLI_smallhash_init(&sld->origfaces);
+ BLI_smallhash_init(&table);
+
+ /*ensure valid selection*/
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ numsel = 0;
+ BM_ITER(e, &iter2, em->bm, BM_EDGES_OF_VERT, v) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ /*BMESH_TODO: this is probably very evil,
+ set v->e to a selected edge*/
+ v->e = e;
- //Make sure each edge only has 2 faces
- // make sure loop doesn't cross face
- for(efa=em->faces.first;efa;efa=efa->next) {
- int ct = 0;
- if(efa->e1->f & SELECT) {
- ct++;
- efa->e1->f1++;
- if(efa->e1->f1 > 2) {
- //BKE_report(op->reports, RPT_ERROR, "3+ face edge");
- MEM_freeN(sld);
- 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");
- MEM_freeN(sld);
- 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");
- MEM_freeN(sld);
- return 0;
+ numsel++;
+ }
}
- }
- 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");
- MEM_freeN(sld);
- return 0;
+
+ if (numsel == 0 || numsel > 2) {
+ return 0; //invalid edge selection
}
}
- // Make sure loop is not 2 edges of same face
- if(ct > 1) {
- //BKE_report(op->reports, RPT_ERROR, "Loop crosses itself");
- MEM_freeN(sld);
- return 0;
+ }
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ if (BM_edge_face_count(e) != 2)
+ return 0; //can only handle exactly 2 faces around each edge
}
}
- // Get # of selected verts
- for(ev=em->verts.first;ev;ev=ev->next) {
- if(ev->f & SELECT) vertsel++;
+ j = 0;
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ BLI_smallhash_insert(&table, (uintptr_t)v, SET_INT_IN_POINTER(j));
+ j += 1;
+ }
+ else {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ }
}
- // Test for multiple segments
- if(vertsel > numsel+1) {
- //BKE_report(op->reports, RPT_ERROR, "Please choose a single edge loop");
- MEM_freeN(sld);
+ if (!j)
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)) {
- // If this is the first edge added, just put it in
- if(!edgelist) {
- BLI_linklist_prepend(&edgelist,eed);
- numadded++;
- first = eed;
- last = eed;
- eed->f1 = SELECT;
- } else {
- if(editedge_getSharedVert(eed, last)) {
- BLI_linklist_append(&edgelist,eed);
- eed->f1 = SELECT;
- numadded++;
- last = eed;
- } else if(editedge_getSharedVert(eed, first)) {
- BLI_linklist_prepend(&edgelist,eed);
- eed->f1 = SELECT;
- numadded++;
- first = eed;
- }
- }
- }
- if(eed->next == NULL && numadded != numsel) {
- eed=em->edges.first;
- timesthrough++;
- }
+ 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 (BM_elem_flag_test(v, BM_ELEM_TAG))
+ break;
- // 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");
- MEM_freeN(sld);
- return 0;
}
- }
- // Put the verts in order in a linklist
- look = edgelist;
- while(look) {
- eed = look->link;
- if(!vertlist) {
- if(look->next) {
- temp = look->next->link;
+ if (!v)
+ break;
- //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;
- } else {
- 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;
- }
- }
- // for all the entries
- if(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;
- }
-
- // populate the SlideVerts
-
- vertgh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "createSlideVerts gh");
- look = vertlist;
- while(look) {
- i=0;
- j=0;
- ev = look->link;
- tempsv = (struct TransDataSlideVert*)MEM_mallocN(sizeof(struct TransDataSlideVert),"SlideVert");
- tempsv->up = NULL;
- tempsv->down = NULL;
- tempsv->origvert.co[0] = ev->co[0];
- tempsv->origvert.co[1] = ev->co[1];
- tempsv->origvert.co[2] = ev->co[2];
- tempsv->origvert.no[0] = ev->no[0];
- tempsv->origvert.no[1] = ev->no[1];
- 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++;
- if(eed->f & SELECT) {
- 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) {
- for(eed=em->edges.first;eed;eed=eed->next) {
- if(editedge_containsVert(eed, ev)) {
- if(!(eed->f & SELECT)) {
- if(!tempsv->up) {
- tempsv->up = eed;
- } else if (!(tempsv->down)) {
- 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) {
- for(eed=em->edges.first;eed;eed=eed->next) {
- if(editedge_containsVert(eed, ev) && eed->f & SELECT) {
- for(efa = em->faces.first;efa;efa=efa->next) {
- if(editface_containsEdge(efa, eed)) {
- if(editedge_containsVert(efa->e1, ev) && efa->e1 != eed) {
- if(!tempsv->up) {
- tempsv->up = efa->e1;
- } else if (!(tempsv->down)) {
- 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;
- }
- }
- if(editedge_containsVert(efa->e3, ev) && efa->e3 != eed) {
- if(!tempsv->up) {
- tempsv->up = efa->e3;
- } else if (!(tempsv->down)) {
- 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;
- }
- }
- }
+ 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;
}
- }
- 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_ghash_insert(vertgh,ev,tempsv);
- look = look->next;
- }
+ numsel += 1;
+
+ if (!BM_elem_flag_test(BM_edge_other_vert(e, v), BM_ELEM_TAG))
+ break;
- // make sure the UPs and DOWNs are 'faceloops'
- // Also find the nearest slidevert to the cursor
+ v = BM_edge_other_vert(e, v);
+ } while (e != first->e);
- look = vertlist;
- nearest = NULL;
- while(look) {
- tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link);
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
- if(!tempsv->up || !tempsv->down) {
- //BKE_report(op->reports, RPT_ERROR, "Missing rails");
- BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN);
- BLI_linklist_free(vertlist,NULL);
- BLI_linklist_free(edgelist,NULL);
- return 0;
- }
+ l1 = l2 = l = NULL;
+ l1 = e->l;
+ l2 = e->l->radial_next;
- if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
- if(!(tempsv->up->f & SELECT)) {
- tempsv->up->f |= SELECT;
- tempsv->up->f2 |= 16;
- } else {
- tempsv->up->f2 |= ~16;
- }
- if(!(tempsv->down->f & SELECT)) {
- tempsv->down->f |= SELECT;
- tempsv->down->f2 |= 16;
- } else {
- tempsv->down->f2 |= ~16;
- }
- }
+ l = BM_face_other_loop(l1->e, l1->f, v);
+ sub_v3_v3v3(vec, BM_edge_other_vert(l->e, v)->co, v->co);
- if(look->next != NULL) {
- TransDataSlideVert *sv;
-
- ev = (EditVert*)look->next->link;
- sv = BLI_ghash_lookup(vertgh, ev);
+ if (l2 != l1) {
+ l = BM_face_other_loop(l2->e, l2->f, v);
+ sub_v3_v3v3(vec2, BM_edge_other_vert(l->e, v)->co, v->co);
+ } else {
+ l2 = NULL;
+ }
- if(sv) {
- float co[3], co2[3], tvec[3];
+ /*iterate over the loop*/
+ first = v;
+ do {
+ TransDataSlideVert *sv = tempsv + j;
- ev = (EditVert*)look->link;
+ sv->v = v;
+ sv->origvert = *v;
+ copy_v3_v3(sv->upvec, vec);
+ if (l2)
+ copy_v3_v3(sv->downvec, vec2);
- if(!sharesFace(em, tempsv->up,sv->up)) {
- EditEdge *swap;
- swap = sv->up;
- sv->up = sv->down;
- sv->down = swap;
- }
-
- if (v3d) {
- ED_view3d_project_float(t->ar, tempsv->up->v1->co, co, projectMat);
- ED_view3d_project_float(t->ar, tempsv->up->v2->co, co2, projectMat);
- }
+ l = BM_face_other_loop(l1->e, l1->f, v);
+ sv->up = BM_edge_other_vert(l->e, v);
- if (ev == tempsv->up->v1) {
- sub_v3_v3v3(tvec, co, co2);
- } else {
- sub_v3_v3v3(tvec, co2, co);
- }
+ if (l2) {
+ l = BM_face_other_loop(l2->e, l2->f, v);
+ sv->down = BM_edge_other_vert(l->e, v);
+ }
- add_v3_v3(start, tvec);
+ v2=v, v = BM_edge_other_vert(e, v);
- if (v3d) {
- ED_view3d_project_float(t->ar, tempsv->down->v1->co, co, projectMat);
- ED_view3d_project_float(t->ar, tempsv->down->v2->co, co2, projectMat);
- }
+ e1 = e;
+ e = get_other_edge(bm, v, e);
+ if (!e) {
+ //v2=v, v = BM_edge_other_vert(l1->e, v);
- if (ev == tempsv->down->v1) {
- sub_v3_v3v3(tvec, co2, co);
- } else {
- sub_v3_v3v3(tvec, co, co2);
+ sv = tempsv + j + 1;
+ sv->v = v;
+ sv->origvert = *v;
+
+ l = BM_face_other_loop(l1->e, l1->f, v);
+ sv->up = BM_edge_other_vert(l->e, v);
+ sub_v3_v3v3(sv->upvec, BM_edge_other_vert(l->e, v)->co, v->co);
+
+ if (l2) {
+ l = BM_face_other_loop(l2->e, l2->f, v);
+ sv->down = BM_edge_other_vert(l->e, v);
+ sub_v3_v3v3(sv->downvec, BM_edge_other_vert(l->e, v)->co, v->co);
}
- add_v3_v3(end, tvec);
-
- totvec += 1.0f;
- nearest = (EditVert*)look->link;
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ BM_elem_flag_disable(v2, BM_ELEM_TAG);
+
+ 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;
- look = look->next;
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ BM_elem_flag_disable(v2, BM_ELEM_TAG);
+ } while (e != first->e && l1);
}
- add_v3_v3(start, end);
- mul_v3_fl(start, 0.5f*(1.0f/totvec));
- copy_v3_v3(vec, start);
- start[0] = t->mval[0];
- start[1] = t->mval[1];
- add_v3_v3v3(end, start, vec);
+ //EDBM_flag_disable_all(em, BM_ELEM_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_elem_flag_test(e, BM_ELEM_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_elem_flag_test(e2, BM_ELEM_SELECT))
+ continue;
+
+ if (!BMBVH_EdgeVisible(btree, e2, ar, v3d, t->obedit))
+ continue;
+
+ j = GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
+
+ if (tempsv[j].down) {
+ ED_view3d_project_float_v3(ar, tempsv[j].down->co, vec1, projectMat);
+ } else {
+ add_v3_v3v3(vec1, v->co, tempsv[j].downvec);
+ ED_view3d_project_float_v3(ar, vec1, vec1, projectMat);
+ }
+
+ if (tempsv[j].up) {
+ ED_view3d_project_float_v3(ar, tempsv[j].up->co, vec2, projectMat);
+ } else {
+ add_v3_v3v3(vec1, v->co, tempsv[j].upvec);
+ ED_view3d_project_float_v3(ar, vec2, vec2, projectMat);
+ }
- /* Ensure minimum screen distance, when looking top down on edge loops */
-#define EDGE_SLIDE_MIN 30
- if (len_squared_v2v2(start, end) < (EDGE_SLIDE_MIN * EDGE_SLIDE_MIN)) {
- if(ABS(start[0]-end[0]) + ABS(start[1]-end[1]) < 4.0f) {
- /* even more exceptional case, points are ontop of each other */
- end[0]= start[0];
- end[1]= start[1] + EDGE_SLIDE_MIN;
- }
- else {
- sub_v2_v2(end, start);
- normalize_v2(end);
- mul_v2_fl(end, EDGE_SLIDE_MIN);
- add_v2_v2(end, start);
+ 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);
+ }
+ }
+ }
}
}
-#undef EDGE_SLIDE_MIN
+
+ em->bm->ob = t->obedit;
+ bmesh_begin_edit(em->bm, BMO_OP_FLAG_UNTAN_MULTIRES);
+ /*create copies of faces for customdata projection*/
+ tempsv = sld->sv;
+ for (i=0; i<sld->totsv; i++, tempsv++) {
+ BMIter fiter, liter;
+ BMFace *f;
+ BMLoop *l;
+
+ BM_ITER(f, &fiter, em->bm, BM_FACES_OF_VERT, tempsv->v) {
+
+ if (!BLI_smallhash_haskey(&sld->origfaces, (uintptr_t)f)) {
+ BMFace *copyf = BM_face_copy(em->bm, f, 1, 1);
+
+ BM_elem_select_set(em->bm, copyf, FALSE);
+ BM_elem_flag_enable(copyf, BM_ELEM_HIDDEN);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, copyf) {
+ BM_elem_select_set(em->bm, l->v, FALSE);
+ BM_elem_flag_enable(l->v, BM_ELEM_HIDDEN);
+ BM_elem_select_set(em->bm, l->e, FALSE);
+ BM_elem_flag_enable(l->e, BM_ELEM_HIDDEN);
+ }
- sld->start[0] = (int) start[0];
- sld->start[1] = (int) start[1];
- sld->end[0] = (int) end[0];
- sld->end[1] = (int) end[1];
+ BLI_smallhash_insert(&sld->origfaces, (uintptr_t)f, copyf);
+ }
+ }
+
+ BLI_smallhash_insert(&sld->vhash, (uintptr_t)tempsv->v, tempsv);
+ }
+
+ sld->em = em;
- if (uvlay_tot) {
- int maxnum = 0;
+ /*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];
- uvarray = MEM_callocN( uvlay_tot * sizeof(GHash *), "SlideUVs Array");
- sld->totuv = uvlay_tot;
- suv_last = slideuvs = MEM_callocN( uvlay_tot * (numadded+1) * sizeof(TransDataSlideUv), "SlideUVs"); /* uvLayers * verts */
- suv = NULL;
+ sld->end[0] = t->mval[0] + end[0];
+ sld->end[1] = t->mval[1] + end[1];
+
+ sld->perc = 0.0f;
+
+ t->customData = sld;
+
+ BLI_smallhash_release(&table);
+ BMBVH_FreeBVH(btree);
+
+ return 1;
+}
- for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
+void projectSVData(TransInfo *t, int final)
+{
+ SlideData *sld = t->customData;
+ TransDataSlideVert *tempsv;
+ BMEditMesh *em = sld->em;
+ SmallHash visit;
+ int i;
+
+ if (!em)
+ return;
+
+ /* BMESH_TODO, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)
+ * currently all vertex data is interpolated which is nice mostly
+ * except for shape keys where you dont want to modify UVs for eg.
+ * current BMesh code doesnt make it easy to pick which data we interpolate
+ * - campbell */
- uvarray[uvlay_idx] = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "createSlideVerts2 gh");
+ BLI_smallhash_init(&visit);
+
+ for (i=0, tempsv=sld->sv; i<sld->totsv; i++, tempsv++) {
+ BMIter fiter;
+ BMFace *f;
+
+ BM_ITER(f, &fiter, em->bm, BM_FACES_OF_VERT, tempsv->v) {
+ BMIter liter2;
+ BMFace *copyf, *copyf2;
+ BMLoop *l2;
+ int sel, hide, do_vdata;
+
+ if (BLI_smallhash_haskey(&visit, (uintptr_t)f))
+ continue;
+
+ BLI_smallhash_insert(&visit, (uintptr_t)f, NULL);
+
+ /*the face attributes of the copied face will get
+ copied over, so its necessary to save the selection
+ and hidden state*/
+ sel = BM_elem_flag_test(f, BM_ELEM_SELECT);
+ hide = BM_elem_flag_test(f, BM_ELEM_HIDDEN);
+
+ copyf2 = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)f);
+
+ /*project onto copied projection face*/
+ BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_FACE, f) {
+ copyf = copyf2;
+ do_vdata = l2->v==tempsv->v;
+
+ if (BM_elem_flag_test(l2->e, BM_ELEM_SELECT) || BM_elem_flag_test(l2->prev->e, BM_ELEM_SELECT)) {
+ BMLoop *l3 = l2;
+
+ do_vdata = 1;
+
+ if (!BM_elem_flag_test(l2->e, BM_ELEM_SELECT))
+ l3 = l3->prev;
+
+ if (sld->perc < 0.0 && BM_vert_in_face(l3->radial_next->f, tempsv->down)) {
+ copyf = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)l3->radial_next->f);
+ } else if (sld->perc > 0.0 && BM_vert_in_face(l3->radial_next->f, tempsv->up)) {
+ copyf = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)l3->radial_next->f);
+ }
+ if (!copyf)
+ continue; /* shouldn't happen, but protection */
+ }
+
+ BM_loop_interp_from_face(em->bm, l2, copyf, do_vdata, FALSE);
- for(ev=em->verts.first;ev;ev=ev->next) {
- ev->tmp.l = 0;
- }
- look = vertlist;
- 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 (fabsf(suv->origuv[0]-uv_new[0]) > 0.0001f || fabsf(suv->origuv[1]-uv_new[1]) > 0.0001f) {
- ev->tmp.l = -1; /* Tag as invalid */
- BLI_linklist_free(suv->fuv_list,NULL);
- suv->fuv_list = NULL;
- BLI_ghash_remove(uvarray[uvlay_idx],ev, NULL, NULL);
- suv = NULL;
- break;
- }
- } else {
- ev->tmp.l = 1;
- suv = suv_last;
-
- suv->fuv_list = NULL;
- 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) {
- ev_up = editedge_getOtherVert(tempsv->up,ev);
- if (efa->v1==ev_up) suv->uv_up = tf->uv[0];
- else if (efa->v2==ev_up) suv->uv_up = tf->uv[1];
- else if (efa->v3==ev_up) suv->uv_up = tf->uv[2];
- else if (efa->v4 && efa->v4==ev_up) suv->uv_up = tf->uv[3];
- }
- if (!suv->uv_down) { /* if the first face was apart of the up edge, it cant be apart of the down edge */
- ev_down = editedge_getOtherVert(tempsv->down,ev);
- if (efa->v1==ev_down) suv->uv_down = tf->uv[0];
- else if (efa->v2==ev_down) suv->uv_down = tf->uv[1];
- 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);
- }
- }
+ if (final) {
+ BM_loop_interp_multires(em->bm, l2, copyf);
+ if (copyf2 != copyf) {
+ BM_loop_interp_multires(em->bm, l2, copyf2);
}
}
- look = look->next;
}
- } /* end uv map loop */
- } /* end uvlay_tot */
-
- sld->uvhash = uvarray;
- sld->slideuv = slideuvs;
- sld->vhash = vertgh;
- sld->nearest = nearest;
- sld->vertlist = vertlist;
- sld->edgelist = edgelist;
- sld->suv_last = suv_last;
- sld->uvlay_tot = uvlay_tot;
-
- // we should have enough info now to slide
-
- t->customData = sld;
-
- return 1;
+
+ /*make sure face-attributes are correct (e.g. MTexPoly)*/
+ BM_elem_attrs_copy(em->bm, em->bm, copyf2, f);
+
+ /*restore selection and hidden flags*/
+ BM_elem_select_set(em->bm, f, sel);
+ BM_elem_hide_set(em->bm, f, hide);
+ }
+ }
+
+ BLI_smallhash_release(&visit);
}
void freeSlideVerts(TransInfo *t)
{
- TransDataSlideUv *suv;
SlideData *sld = t->customData;
- Mesh *me = t->obedit->data;
- int uvlay_idx;
-
+ SmallHashIter hiter;
+ BMFace *copyf;
+
+#if 0 /*BMESH_TODO*/
if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
TransDataSlideVert *tempsv;
LinkNode *look = sld->vertlist;
@@ -4796,31 +4762,38 @@ void freeSlideVerts(TransInfo *t)
look = look->next;
}
}
-
- //BLI_ghash_free(edgesgh, freeGHash, NULL);
- BLI_ghash_free(sld->vhash, NULL, (GHashValFreeFP)MEM_freeN);
- BLI_linklist_free(sld->vertlist, NULL);
- BLI_linklist_free(sld->edgelist, NULL);
-
- if (sld->uvlay_tot) {
- for (uvlay_idx=0; uvlay_idx<sld->uvlay_tot; uvlay_idx++) {
- BLI_ghash_free(sld->uvhash[uvlay_idx], NULL, NULL);
- }
-
- suv = sld->suv_last-1;
- while (suv >= sld->slideuv) {
- if (suv->fuv_list) {
- BLI_linklist_free(suv->fuv_list,NULL);
- }
- suv--;
- }
-
- MEM_freeN(sld->slideuv);
- MEM_freeN(sld->uvhash);
+#endif
+
+ if (!sld)
+ return;
+
+ /*handle multires reprojection, done
+ on transform completion since it's
+ really slow -joeedh*/
+ if (t->state != TRANS_CANCEL) {
+ projectSVData(t, 1);
+ } else {
+ sld->perc = 0.0;
+ projectSVData(t, 0);
}
+
+ copyf = BLI_smallhash_iternew(&sld->origfaces, &hiter, NULL);
+ for (; copyf; copyf=BLI_smallhash_iternext(&hiter, NULL)) {
+ BM_face_verts_kill(sld->em->bm, copyf);
+ }
+
+ sld->em->bm->ob = t->obedit;
+ bmesh_end_edit(sld->em->bm, BMO_OP_FLAG_UNTAN_MULTIRES);
+ BLI_smallhash_release(&sld->vhash);
+ BLI_smallhash_release(&sld->origfaces);
+
+ MEM_freeN(sld->sv);
MEM_freeN(sld);
+
t->customData = NULL;
+
+ recalcData(t);
}
void initEdgeSlide(TransInfo *t)
@@ -4860,108 +4833,28 @@ void initEdgeSlide(TransInfo *t)
static int doEdgeSlide(TransInfo *t, float perc)
{
SlideData *sld = t->customData;
- EditVert *ev, *nearest = sld->nearest;
- EditVert *centerVert, *upVert, *downVert;
- LinkNode *vertlist=sld->vertlist, *look;
- GHash *vertgh = sld->vhash;
- TransDataSlideVert *tempsv;
- float len;
- int prop=1, flip=0;
- /* UV correction vars */
- GHash **uvarray= sld->uvhash;
- const int uvlay_tot= sld->uvlay_tot;
- int uvlay_idx;
- TransDataSlideUv *suv;
- float uv_tmp[2];
- LinkNode *fuv_link;
-
- tempsv = BLI_ghash_lookup(vertgh,nearest);
-
- centerVert = editedge_getSharedVert(tempsv->up, tempsv->down);
- upVert = editedge_getOtherVert(tempsv->up, centerVert);
- downVert = editedge_getOtherVert(tempsv->down, centerVert);
-
- len = MIN2(perc, len_v3v3(upVert->co,downVert->co));
- len = MAX2(len, 0);
-
- //Adjust Edgeloop
- if(prop) {
- 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 (uvlay_tot) {
- 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) {
- interp_v2_v2v2(uv_tmp, suv->origuv, (perc>=0)?suv->uv_up:suv->uv_down, fabs(perc));
- fuv_link = suv->fuv_list;
- while (fuv_link) {
- copy_v2_v2(((float *)fuv_link->link), uv_tmp);
- fuv_link = fuv_link->next;
- }
- }
- }
- }
+ TransDataSlideVert *svlist = sld->sv, *sv;
+ float vec[3];
+ int i;
- look = look->next;
+ sld->perc = perc;
+
+ sv = svlist;
+ for (i=0; i<sld->totsv; i++, sv++) {
+ if (perc > 0.0f) {
+ copy_v3_v3(vec, sv->upvec);
+ mul_v3_fl(vec, perc);
+ add_v3_v3v3(sv->v->co, sv->origvert.co, vec);
}
- }
- else {
- //Non prop code
- look = vertlist;
- while(look) {
- float newlen, edgelen;
- ev = look->link;
- tempsv = BLI_ghash_lookup(vertgh,ev);
- edgelen = len_v3v3(editedge_getOtherVert(tempsv->up,ev)->co,editedge_getOtherVert(tempsv->down,ev)->co);
- newlen = (edgelen != 0.0f)? (len / edgelen): 0.0f;
- if(newlen > 1.0f) {newlen = 1.0;}
- if(newlen < 0.0f) {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 (uvlay_tot) {
- /* dont do anything if no UVs */
- 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) {
- interp_v2_v2v2(uv_tmp, suv->uv_down, suv->uv_up, fabs(newlen));
- fuv_link = suv->fuv_list;
- while (fuv_link) {
- copy_v2_v2(((float *)fuv_link->link), uv_tmp);
- fuv_link = fuv_link->next;
- }
- }
- }
- }
- } else{
- interp_v3_v3v3(ev->co, editedge_getOtherVert(tempsv->up,ev)->co, editedge_getOtherVert(tempsv->down,ev)->co, fabs(newlen));
-
- if (uvlay_tot) {
- /* dont do anything if no UVs */
- 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) {
- interp_v2_v2v2(uv_tmp, suv->uv_up, suv->uv_down, fabs(newlen));
- fuv_link = suv->fuv_list;
- while (fuv_link) {
- copy_v2_v2(((float *)fuv_link->link), uv_tmp);
- fuv_link = fuv_link->next;
- }
- }
- }
- }
- }
- look = look->next;
+ else {
+ copy_v3_v3(vec, sv->downvec);
+ mul_v3_fl(vec, -perc);
+ add_v3_v3v3(sv->v->co, sv->origvert.co, vec);
}
-
}
-
+
+ projectSVData(t, 0);
+
return 1;
}
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 4c4c2f67d82..13f7d279da9 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -39,6 +39,8 @@
#include "DNA_listBase.h"
#include "BLI_editVert.h"
+#include "BLI_smallhash.h"
+#include "BKE_tessmesh.h"
/* ************************** Types ***************************** */
@@ -64,6 +66,7 @@ struct wmEvent;
struct wmTimer;
struct ARegion;
struct ReportList;
+struct SmallHash;
typedef struct TransSnapPoint {
struct TransSnapPoint *next,*prev;
@@ -182,25 +185,34 @@ struct LinkNode;
struct EditEdge;
struct EditVert;
struct GHash;
-typedef struct TransDataSlideUv {
- float origuv[2];
- float *uv_up, *uv_down;
- //float *fuv[4];
- struct LinkNode *fuv_list;
-} 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;
+
+ struct SmallHash vhash;
+ struct SmallHash origfaces;
+
+ /*
TransDataSlideUv *slideuv, *suv_last;
int totuv, uvlay_tot;
struct GHash *vhash, **uvhash;
struct EditVert *nearest;
struct LinkNode *edgelist, *vertlist;
+ */
int start[2], end[2];
+ struct BMEditMesh *em;
+ float perc;
} SlideData;
typedef struct TransData {
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index fe244fbdafa..5158f2beada 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -73,6 +73,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"
#include "BKE_tracking.h"
@@ -103,13 +104,16 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_editVert.h"
+#include "BLI_array.h"
#include "BLI_utildefines.h"
+#include "BLI_smallhash.h"
#include "RNA_access.h"
extern ListBase editelems;
#include "transform.h"
+#include "bmesh.h"
#include "BLO_sys_types.h" // for intptr_t support
@@ -298,16 +302,17 @@ static void createTransTexspace(TransInfo *t)
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++;
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) countsel++;
if (propmode) count++;
}
}
@@ -327,14 +332,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_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_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_elem_flag_test(eed, BM_ELEM_SELECT))
td->flag= TD_SELECTED;
else
td->flag= 0;
@@ -345,12 +353,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++;
@@ -409,7 +417,7 @@ static short apply_targetless_ik(Object *ob)
}
for(;segcount;segcount--) {
Bone *bone;
- float rmat[4][4], tmat[4][4], imat[4][4];
+ float rmat[4][4]/*, tmat[4][4], imat[4][4]*/;
/* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK */
/* we put in channel the entire result of rmat= (channel * constraint * IK) */
@@ -420,6 +428,8 @@ static short apply_targetless_ik(Object *ob)
bone= parchan->bone;
bone->flag |= BONE_TRANSFORM; /* ensures it gets an auto key inserted */
+ /* XXX Old code. Will remove it later. */
+#if 0
if(parchan->parent) {
Bone *parbone= parchan->parent->bone;
float offs_bone[4][4];
@@ -462,6 +472,8 @@ static short apply_targetless_ik(Object *ob)
}
/* result matrix */
mult_m4_m4m4(rmat, imat, parchan->pose_mat);
+#endif
+ armature_mat_pose_to_bone(parchan, parchan->pose_mat, rmat);
/* apply and decompose, doesn't work for constraints or non-uniform scale well */
{
@@ -1854,126 +1866,123 @@ void flushTransParticles(TransInfo *t)
/* proportional distance based on connectivity */
#define THRESHOLDFACTOR (1.0f-0.0001f)
-static int connectivity_edge(float mtx[][3], EditVert *v1, EditVert *v2)
+/*I did this wrong, it should be a breadth-first search
+ but instead it's a depth-first search, fudged
+ to report shortest distances. I have no idea how fast
+ or slow this is.*/
+static void editmesh_set_connectivity_distance(BMEditMesh *em, float mtx[][3], float *dists)
{
- float edge_vec[3];
- float edge_len;
- int done = 0;
-
- /* note: hidden verts are not being checked for, this assumes
- * flushing of hidden faces & edges is working right */
-
- if (v1->f2 + v2->f2 == 4)
- return 0;
+ BMVert **queue = NULL;
+ float *dqueue = NULL;
+ int *tots = MEM_callocN(sizeof(int)*em->bm->totvert, "tots editmesh_set_connectivity_distance");
+ BLI_array_declare(queue);
+ BLI_array_declare(dqueue);
+ SmallHash svisit, *visit=&svisit;
+ BMVert *v;
+ BMIter viter;
+ int i, start;
- sub_v3_v3v3(edge_vec, v1->co, v2->co);
- mul_m3_v3(mtx, edge_vec);
-
- edge_len = len_v3(edge_vec);
-
- if (v1->f2) {
- if (v2->f2) {
- if (v2->tmp.fp + edge_len < THRESHOLDFACTOR * v1->tmp.fp) {
- v1->tmp.fp = v2->tmp.fp + edge_len;
- done = 1;
- } else if (v1->tmp.fp + edge_len < THRESHOLDFACTOR * v2->tmp.fp) {
- v2->tmp.fp = v1->tmp.fp + edge_len;
- done = 1;
- }
- }
- else {
- v2->f2 = 1;
- v2->tmp.fp = v1->tmp.fp + edge_len;
- done = 1;
- }
- }
- else if (v2->f2) {
- v1->f2 = 1;
- v1->tmp.fp = v2->tmp.fp + edge_len;
- done = 1;
- }
+ fill_vn_fl(dists, em->bm->totvert, FLT_MAX);
- return done;
-}
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-static void editmesh_set_connectivity_distance(EditMesh *em, float mtx[][3])
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
- int done= 1;
-
- /* f2 flag is used for 'selection' */
- /* tmp.l is offset on scratch array */
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->h==0) {
- eve->tmp.fp = 0;
-
- if(eve->f & SELECT) {
- eve->f2= 2;
- }
- else {
- eve->f2 = 0;
- }
- }
- }
+ BLI_smallhash_init(visit);
+ BM_ITER(v, &viter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)==0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN))
+ continue;
+
+
+ BLI_smallhash_insert(visit, (uintptr_t)v, NULL);
+ BLI_array_append(queue, v);
+ BLI_array_append(dqueue, 0.0f);
+ dists[BM_elem_index_get(v)] = 0.0f;
+ }
+
+ start = 0;
+ while (start < BLI_array_count(queue)) {
+ BMIter eiter;
+ BMEdge *e;
+ BMVert *v3, *v2;
+ float d, vec[3];
+
+ v2 = queue[start];
+ d = dqueue[start];
+
+ BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v2) {
+ float d2;
+ v3 = BM_edge_other_vert(e, v2);
+
+ if (BM_elem_flag_test(v3, BM_ELEM_SELECT) || BM_elem_flag_test(v3, BM_ELEM_HIDDEN))
+ continue;
+
+ sub_v3_v3v3(vec, v2->co, v3->co);
+ mul_m3_v3(mtx, vec);
+
+ d2 = d + len_v3(vec);
+
+ if (dists[BM_elem_index_get(v3)] != FLT_MAX)
+ dists[BM_elem_index_get(v3)] = MIN2(d2, dists[BM_elem_index_get(v3)]);
+ else
+ dists[BM_elem_index_get(v3)] = d2;
+
+ tots[BM_elem_index_get(v3)] = 1;
- /* Floodfill routine */
- /*
- At worst this is n*n of complexity where n is number of edges
- Best case would be n if the list is ordered perfectly.
- Estimate is n log n in average (so not too bad)
- */
- while(done) {
- done= 0;
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0) {
- done |= connectivity_edge(mtx, eed->v1, eed->v2);
- }
+ if (BLI_smallhash_haskey(visit, (uintptr_t)v3))
+ continue;
+
+ BLI_smallhash_insert(visit, (uintptr_t)v3, NULL);
+
+ BLI_array_append(queue, v3);
+ BLI_array_append(dqueue, d2);
}
+
+ start++;
+ }
- /* do internal edges for quads */
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (efa->v4 && efa->h==0) {
- done |= connectivity_edge(mtx, efa->v1, efa->v3);
- done |= connectivity_edge(mtx, efa->v2, efa->v4);
- }
- }
+ BLI_smallhash_release(visit);
+
+ for (i=0; i<em->bm->totvert; i++) {
+ if (tots[i])
+ dists[i] /= (float)tots[i];
}
+
+ BLI_array_free(queue);
+ BLI_array_free(dqueue);
+ MEM_freeN(tots);
}
/* 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 cent_r[3], BMesh *bm, BMVert *eve)
+
{
- EditFace *efa;
+ BMFace *efa;
+ BMIter iter;
- 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) {
- copy_v3_v3(cent, efa->cent);
+ BM_ITER(efa, &iter, bm, BM_FACES_OF_VERT, eve) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_face_center_mean_calc(bm, efa, cent_r);
+ break;
+ }
}
}
-static void get_edge_center(float *cent, EditMesh *em, EditVert *eve)
+static void get_edge_center(float cent_r[3], BMesh *bm, BMVert *eve)
{
- EditEdge *eed;
+ BMEdge *eed;
+ BMIter iter;
- for(eed= em->edges.first; eed; eed= eed->next)
- if(eed->f & SELECT)
- if(eed->v1==eve || eed->v2==eve)
- break;
- if(eed) {
- mid_v3_v3v3(cent, eed->v1->co, eed->v2->co);
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_VERT, eve) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ mid_v3_v3v3(cent_r, eed->v1->co, eed->v2->co);
+ break;
+ }
}
}
/* 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)
+static void VertsToTransData(TransInfo *t, TransData *td, BMEditMesh *em, BMVert *eve, float *bweight)
{
td->flag = 0;
//if(key)
@@ -1982,11 +1991,12 @@ static void VertsToTransData(TransInfo *t, TransData *td, EditMesh *em, EditVert
td->loc = eve->co;
copy_v3_v3(td->center, td->loc);
+
if(t->around==V3D_LOCAL) {
if(em->selectmode & SCE_SELECT_FACE)
- get_face_center(td->center, em, eve);
+ get_face_center(td->center, em->bm, eve);
else if(em->selectmode & SCE_SELECT_EDGE)
- get_edge_center(td->center, em, eve);
+ get_edge_center(td->center, em->bm, eve);
}
copy_v3_v3(td->iloc, td->loc);
@@ -2003,8 +2013,8 @@ static void VertsToTransData(TransInfo *t, TransData *td, EditMesh *em, EditVert
td->val = NULL;
td->extra = NULL;
if (t->mode == TFM_BWEIGHT) {
- td->val = &(eve->bweight);
- td->ival = eve->bweight;
+ td->val = bweight;
+ td->ival = bweight ? *(bweight) : 1.0f;
}
}
@@ -2012,18 +2022,23 @@ 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;
+ 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;
+ float *dists=NULL;
int count=0, countsel=0, a, totleft;
int propmode = (t->flag & T_PROP_EDIT) ? (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) : 0;
int mirror = 0;
+ char *selstate = NULL;
short selectmode = ts->selectmode;
if (t->flag & T_MIRROR)
{
+ EDBM_CacheMirrorVerts(em, TRUE);
mirror = 1;
}
@@ -2032,55 +2047,89 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
selectmode = SCE_SELECT_EDGE;
}
+ /* BMESH_TODO, writing into the index values is BAD!, means we cant
+ * use the values for vertex mirror - campbell */
+
// 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;
- else
- eve->f1= 0;
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ BM_elem_flag_enable(eve, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_disable(eve, BM_ELEM_TAG);
+ }
}
}
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 = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for( ; eve; eve=BM_iter_step(&iter)) BM_elem_flag_disable(eve, BM_ELEM_TAG);
+
+ eed = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL);
+ for( ; eed; eed=BM_iter_step(&iter)) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ BM_elem_flag_enable(eed->v1, BM_ELEM_TAG);
+ BM_elem_flag_enable(eed->v2, BM_ELEM_TAG);
+ }
}
}
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 = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for( ; eve; eve=BM_iter_step(&iter)) BM_elem_flag_disable(eve, BM_ELEM_TAG);
+
+ efa = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, NULL);
+ for( ; efa; efa=BM_iter_step(&iter)) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BMIter liter;
+ BMLoop *l;
+
+ l = BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BM_iter_step(&liter)) {
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
}
}
}
- /* 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*/
+ selstate = MEM_callocN(sizeof(*selstate) * bm->totvert, __func__);
+ eve = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for(a=0; eve; eve=BM_iter_step(&iter), a++) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ if (BM_elem_flag_test(eve, BM_ELEM_TAG)) {
+ selstate[a] = 1;
+ countsel++;
+ }
if(propmode) count++;
}
}
- /* note: in prop mode we need at least 1 selected */
- if (countsel==0) return;
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel == 0) {
+ goto cleanup;
+ }
/* check active */
- if (em->selected.last) {
- EditSelection *ese = em->selected.last;
- if ( ese->type == EDITVERT ) {
- eve_act = (EditVert *)ese->data;
+ if (em->bm->selected.last) {
+ BMEditSelection *ese = em->bm->selected.last;
+ if (ese->htype == BM_VERT) {
+ eve_act = (BMVert *)ese->data;
}
}
- if(propmode) t->total = count;
+ if(propmode) {
+ t->total = count;
+
+ /* allocating scratch arrays */
+ if (propmode & T_PROP_CONNECTED)
+ dists = MEM_mallocN(em->bm->totvert * sizeof(float), "scratch nears");
+ }
else t->total = countsel;
tob= t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Mesh EditMode)");
@@ -2089,7 +2138,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
invert_m3_m3(smtx, mtx);
if(propmode & T_PROP_CONNECTED) {
- editmesh_set_connectivity_distance(em, mtx);
+ editmesh_set_connectivity_distance(em, mtx, dists);
}
/* detect CrazySpace [tm] */
@@ -2097,7 +2146,7 @@ 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
@@ -2105,7 +2154,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
if(totleft > 0) {
mappedcos= crazyspace_get_mapped_editverts(t->scene, t->obedit);
quats= MEM_mallocN( (t->total)*sizeof(float)*4, "crazy quats");
- crazyspace_set_quats_editmesh(em, (float*)defcos, mappedcos, quats);
+ crazyspace_set_quats_editmesh(em, (float*)defcos, mappedcos, quats); /* BMESH_TODO, abuses vertex index, should use an int array */
if(mappedcos)
MEM_freeN(mappedcos);
}
@@ -2117,8 +2166,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 = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for(a=0; eve; eve=BM_iter_step(&iter), a++) {
+ if(!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && selstate[a] && eve->co[0]!=0.0f) {
if(eve->co[0]<0.0f)
{
t->mirror = -1;
@@ -2129,34 +2179,36 @@ 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 = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for(a=0; eve; eve=BM_iter_step(&iter), a++) {
+ if(!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ if(propmode || selstate[a]) {
+ float *bweight = CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_BWEIGHT);
+
+ VertsToTransData(t, tob, em, eve, bweight);
/* 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) {
- if (eve->f2) {
- tob->dist= eve->tmp.fp;
- }
- else {
+ if (propmode & T_PROP_CONNECTED) {
+ tob->dist = dists[a];
+ } else {
tob->flag |= TD_NOTCONNECTED;
tob->dist = MAXFLOAT;
}
}
/* CrazySpace */
- if(defmats || (quats && eve->tmp.p)) {
- float mat[3][3], imat[3][3], qmat[3][3];
+ if(defmats || (quats && BM_elem_index_get(eve) != -1)) {
+ float mat[3][3], qmat[3][3], imat[3][3];
/* use both or either quat and defmat correction */
- if(quats && eve->tmp.f) {
- quat_to_mat3( qmat,eve->tmp.p);
+ if(quats && BM_elem_index_get(eve) != -1) {
+ quat_to_mat3(qmat, quats + 4*BM_elem_index_get(eve));
if(defmats)
mul_serie_m3(mat, mtx, qmat, defmats[a],
@@ -2179,8 +2231,8 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
/* Mirror? */
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;
}
}
@@ -2200,12 +2252,22 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
}
}
}
-
+
+cleanup:
/* crazy space free */
if(quats)
MEM_freeN(quats);
if(defmats)
MEM_freeN(defmats);
+ if (dists)
+ MEM_freeN(dists);
+
+ MEM_freeN(selstate);
+
+ if (t->flag & T_MIRROR) {
+ EDBM_EndMirrorCache(em);
+ mirror = 1;
+ }
}
/* *** NODE EDITOR *** */
@@ -2383,30 +2445,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)) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ continue;
+ }
+
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ 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++;
}
}
@@ -2425,20 +2490,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 (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ 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));
}
}
@@ -4817,7 +4879,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);
}
}
}
@@ -5067,7 +5129,7 @@ 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');
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 3c019c1680f..4073081ffc2 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -71,6 +71,7 @@
#include "BKE_mesh.h"
#include "BKE_nla.h"
#include "BKE_context.h"
+#include "BKE_tessmesh.h"
#include "BKE_tracking.h"
#include "ED_anim_api.h"
@@ -236,10 +237,10 @@ 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++) {
@@ -374,7 +375,6 @@ static void recalcData_actedit(TransInfo *t)
BLI_freelistN(&anim_data);
}
}
-
/* helper for recalcData() - for Graph Editor transforms */
static void recalcData_graphedit(TransInfo *t)
{
@@ -714,7 +714,7 @@ static void recalcData_view3d(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) {
/* apply clipping after so we never project past the clip plane [#25423] */
@@ -722,11 +722,12 @@ static void recalcData_view3d(TransInfo *t)
clipMirrorModifier(t, t->obedit);
}
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;
@@ -1537,12 +1538,12 @@ void calculateCenter(TransInfo *t)
/* EDIT MODE ACTIVE EDITMODE ELEMENT */
if (t->obedit) {
- if(t->obedit->type == OB_MESH) {
- EditSelection ese;
- EditMesh *em = BKE_mesh_get_editmesh(t->obedit->data);
+ if (t->obedit && t->obedit->type == OB_MESH) {
+ BMEditSelection ese;
+ BMEditMesh *em = ((Mesh*)t->obedit->data)->edit_btmesh;
- if (EM_get_actSelection(em, &ese)) {
- EM_editselection_center(t->center, &ese);
+ if (EDBM_get_actSelection(em, &ese)) {
+ EDBM_editselection_center(em, t->center, &ese);
calculateCenter2D(t);
break;
}
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index 5578ea754df..f95856b2373 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -60,6 +60,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"
@@ -298,72 +299,63 @@ 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;
+ BMEditSelection ese;
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 {
+ }
+ else {
+ BMesh *bm = em->bm;
+ BMVert *eve;
+
+ BMIter iter;
+
/* do vertices/edges/faces for center depending on selection
mode. note we can't use just vertex selection flag because
it is not flush down on changes */
if(ts->selectmode & SCE_SELECT_VERTEX) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
- totsel++;
- calc_tw_center(scene, eve->co);
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ if(BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ totsel++;
+ calc_tw_center(scene, eve->co);
+ }
}
}
}
else if(ts->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)) {
- if(!eed->v1->f1) {
- eed->v1->f1= 1;
- totsel++;
- calc_tw_center(scene, eed->v1->co);
- }
- if(!eed->v2->f1) {
- eed->v2->f1= 1;
- totsel++;
- calc_tw_center(scene, eed->v2->co);
+ BMIter itersub;
+ BMEdge *eed;
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ /* check the vertex has a selected edge, only add it once */
+ BM_ITER(eed, &itersub, bm, BM_EDGES_OF_VERT, eve) {
+ if(BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ totsel++;
+ calc_tw_center(scene, eve->co);
+ break;
+ }
}
}
}
}
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)) {
- if(!efa->v1->f1) {
- efa->v1->f1= 1;
- totsel++;
- calc_tw_center(scene, efa->v1->co);
- }
- if(!efa->v2->f1) {
- efa->v2->f1= 1;
- totsel++;
- calc_tw_center(scene, efa->v2->co);
- }
- if(!efa->v3->f1) {
- efa->v3->f1= 1;
- totsel++;
- calc_tw_center(scene, efa->v3->co);
- }
- if(efa->v4 && !efa->v4->f1) {
- efa->v4->f1= 1;
- totsel++;
- calc_tw_center(scene, efa->v4->co);
+ BMIter itersub;
+ BMFace *efa;
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ /* check the vertex has a selected face, only add it once */
+ BM_ITER(efa, &itersub, bm, BM_FACES_OF_VERT, eve) {
+ if(BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ totsel++;
+ calc_tw_center(scene, eve->co);
+ break;
+ }
}
}
}
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 8a9249f78e5..19dbf8b713e 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -41,6 +41,7 @@
#include "BKE_armature.h"
#include "BKE_curve.h"
#include "BKE_context.h"
+#include "BKE_tessmesh.h"
#include "BKE_report.h"
#include "BLI_math.h"
@@ -583,56 +584,57 @@ 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)
+ switch (ese.htype)
{
- 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)
- {
- add_v3_v3(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_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ add_v3_v3(normal, efa->no);
+ sub_v3_v3v3(vec,
+ BM_FACE_FIRST_LOOP(efa)->v->co,
+ BM_FACE_FIRST_LOOP(efa)->next->v->co);
add_v3_v3(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_elem_flag_test(eve, BM_ELEM_SELECT)) {
if (v1 == NULL) {
v1 = eve;
}
@@ -651,12 +653,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_elem_flag_test(eed, BM_ELEM_SELECT)) {
sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
break;
}
@@ -665,12 +668,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_elem_flag_test(eed, BM_ELEM_SELECT)) {
/* use average vert normals as plane and edge vector as normal */
copy_v3_v3(plane, eed->v1->no);
add_v3_v3(plane, eed->v2->no);
@@ -680,13 +684,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_elem_flag_test(eve, BM_ELEM_SELECT)) {
if (v1 == NULL) {
v1 = eve;
}
@@ -702,24 +706,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_elem_flag_test(eve, BM_ELEM_SELECT)) {
copy_v3_v3(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_elem_flag_test(eve, BM_ELEM_SELECT)) {
add_v3_v3(normal, eve->no);
}
}
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index d079bd41c10..183ade56cf0 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -68,6 +68,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"
@@ -1352,13 +1354,13 @@ 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],
+static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[][4],
const float ray_start[3], const float ray_normal[3], const float mval[2],
float r_loc[3], float r_no[3], int *r_dist, float *r_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];
@@ -1426,19 +1428,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 */
@@ -1460,11 +1462,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_elem_flag_test(efa, BM_ELEM_HIDDEN))
{
test = 0;
+ } else if (efa) {
+ BMIter iter;
+ BMLoop *l;
+
+ l = BM_iter_new(&iter, em->bm, BM_LOOPS_OF_FACE, efa);
+ for ( ; l; l=BM_iter_step(&iter)) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_SELECT)) {
+ test = 0;
+ break;
+ }
+ }
}
}
}
@@ -1492,7 +1505,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;
@@ -1507,11 +1520,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 */
@@ -1533,9 +1546,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_elem_flag_test(eve, BM_ELEM_HIDDEN) || BM_elem_flag_test(eve, BM_ELEM_SELECT)))
{
test = 0;
}
@@ -1551,7 +1564,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;
}
@@ -1567,11 +1580,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 */
@@ -1593,9 +1606,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_elem_flag_test(eed, BM_ELEM_HIDDEN) ||
+ BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)))
{
test = 0;
}
@@ -1611,7 +1626,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;
}
@@ -1630,14 +1645,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
{
@@ -1793,7 +1808,7 @@ static int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4],
{
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];
@@ -1823,7 +1838,7 @@ static int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4],
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++) {
@@ -1919,6 +1934,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;
@@ -1940,6 +1956,7 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L
retval = retval || val;
dm->release(dm);
+#endif
}
}
@@ -1947,7 +1964,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;
@@ -1959,8 +1976,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 7a6ccdff08f..eb0286716f3 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenkernel
../../blenlib
../../blenloader
+ ../../bmesh
../../makesdna
../../makesrna
../../windowmanager
diff --git a/source/blender/editors/util/SConscript b/source/blender/editors/util/SConscript
index cfbc735eb5c..16501c59551 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','player'], priority=[330,210] )
diff --git a/source/blender/editors/util/crazyspace.c b/source/blender/editors/util/crazyspace.c
index 9ee4a875e24..ae4f99414bd 100644
--- a/source/blender/editors/util/crazyspace.c
+++ b/source/blender/editors/util/crazyspace.c
@@ -41,6 +41,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"
@@ -106,18 +107,18 @@ float *crazyspace_get_mapped_editverts(Scene *scene, Object *obedit)
Mesh *me= obedit->data;
DerivedMesh *dm;
float *vertexcos;
- int nverts= me->edit_mesh->totvert;
+ int nverts= me->edit_btmesh->bm->totvert;
short *flags;
MappedUserData userData;
/* 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, 0);
}
/* 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_callocN(3*sizeof(float)*nverts, "vertexcos map");
flags= MEM_callocN(sizeof(short)*nverts, "vertexcos flags");
@@ -136,10 +137,59 @@ 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;
+ BMVert *v;
+ BMIter iter, liter;
+ BMLoop *l;
+ float *v1, *v2, *v3, *co1, *co2, *co3;
+ int *vert_table = MEM_callocN(sizeof(int)*em->bm->totvert, "vert_table");
+ int index = 0;
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(v, BM_ELEM_SELECT) || BM_elem_flag_test(v, BM_ELEM_HIDDEN))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_VERT, v) {
+ BMLoop *l2 = BM_face_other_loop(l->e, l->f, v);
+
+ /* retrieve mapped coordinates */
+ v1= mappedcos + 3*BM_elem_index_get(l->v);
+ v2= mappedcos + 3*BM_elem_index_get(BM_edge_other_vert(l2->e, l->v));
+ v3= mappedcos + 3*BM_elem_index_get(BM_edge_other_vert(l->e, l->v));
+
+ co1= (origcos)? origcos + 3*BM_elem_index_get(l->v) : l->v->co;
+ co2= (origcos)? origcos + 3*BM_elem_index_get(BM_edge_other_vert(l2->e, l->v)) : BM_edge_other_vert(l2->e, l->v)->co;
+ co3= (origcos)? origcos + 3*BM_elem_index_get(BM_edge_other_vert(l->e, l->v)) : BM_edge_other_vert(l->e, l->v)->co;
+
+ set_crazy_vertex_quat(quats, v1, v2, v3, co1, co2, co3);
+ quats+= 4;
+
+ vert_table[BM_elem_index_get(l->v)] = index+1;
+
+ index++;
+ break; /*just do one corner*/
+ }
+ }
+
+ index = 0;
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (vert_table[index] != 0)
+ BM_elem_index_set(v, vert_table[index]-1); /* set_dirty! */
+ else
+ BM_elem_index_set(v, -1); /* set_dirty! */
+
+ index++;
+ }
+ em->bm->elem_index_dirty |= BM_VERT;
+
+ MEM_freeN(vert_table);
+#if 0
+ BMEditVert *eve, *prev;
+ BMEditFace *efa;
+ BMIter iter;
float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4;
intptr_t index= 0;
@@ -204,9 +254,11 @@ 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
}
+/* BMESH_TODO - use MPolys over MFace's */
+
void crazyspace_set_quats_mesh(Mesh *me, float *origcos, float *mappedcos, float *quats)
{
int i;
@@ -267,7 +319,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;
@@ -286,13 +339,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++)
@@ -307,7 +360,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 a40c6cfa42f..7f301123ab8 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -108,10 +108,10 @@ void ED_editors_exit(bContext *C)
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) {
diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c
index 34dffc11d94..4776cf0af53 100644
--- a/source/blender/editors/util/editmode_undo.c
+++ b/source/blender/editors/util/editmode_undo.c
@@ -96,8 +96,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;
@@ -107,10 +107,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);
}
}
@@ -118,8 +118,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;
@@ -168,7 +168,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;
@@ -248,7 +248,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) {
@@ -256,7 +256,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 {
@@ -264,7 +264,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);
}
@@ -272,7 +272,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(C);
}
DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index 4fb9f916df7..56a835beeb8 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -48,6 +48,8 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_screen.h"
+#include "BKE_tessmesh.h" /* BMESH_EM_UNDO_RECALC_TESSFACE_WORKAROUND */
+
#include "ED_armature.h"
#include "ED_particle.h"
@@ -86,6 +88,19 @@ void ED_undo_push(bContext *C, const char *str)
printf("undo push %s\n", str);
if(obedit) {
+
+#ifdef BMESH_EM_UNDO_RECALC_TESSFACE_WORKAROUND
+ /* undo is causing tessface recalc, so without we need to do explicitly */
+
+ if (U.undosteps == 0) {
+ if (obedit->type == OB_MESH) {
+ Mesh *me= obedit->data;
+ BMEdit_RecalcTesselation(me->edit_btmesh);
+ }
+ }
+
+#endif /* BMESH_EM_UNDO_RECALC_TESSFACE_WORKAROUND */
+
if (U.undosteps == 0) return;
if(obedit->type==OB_MESH)
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt
index a747c2ac6bd..1c69e569aa6 100644
--- a/source/blender/editors/uvedit/CMakeLists.txt
+++ b/source/blender/editors/uvedit/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenkernel
../../blenlib
../../blenloader
+ ../../bmesh
../../makesdna
../../makesrna
../../windowmanager
diff --git a/source/blender/editors/uvedit/SConscript b/source/blender/editors/uvedit/SConscript
index 2523de005d0..d236b18a8fd 100644
--- a/source/blender/editors/uvedit/SConscript
+++ b/source/blender/editors/uvedit/SConscript
@@ -5,6 +5,6 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
-incs += ' ../../makesrna #/intern/opennl/extern ../../gpu ../../blenloader'
+incs += ' ../../bmesh ../../makesrna #/intern/opennl/extern ../../gpu ../../blenloader'
env.BlenderLib ( 'bf_editors_uvedit', sources, Split(incs), [], libtype=['core'], priority=[45] )
diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c
index a6712bf8efa..9759ab447f6 100644
--- a/source/blender/editors/uvedit/uvedit_buttons.c
+++ b/source/blender/editors/uvedit/uvedit_buttons.c
@@ -47,6 +47,7 @@
#include "BKE_customdata.h"
#include "BKE_mesh.h"
#include "BKE_screen.h"
+#include "BKE_tessmesh.h"
#include "ED_image.h"
#include "ED_uvedit.h"
@@ -61,32 +62,20 @@
/* UV Utilities */
-static int uvedit_center(Scene *scene, EditMesh *em, Image *ima, float center[2])
+static int uvedit_center(Scene *scene, BMEditMesh *em, Image *UNUSED(ima), float center[2])
{
- EditFace *efa;
- MTFace *tf;
- int tot= 0;
-
+ BMFace *f;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ int tot = 0.0;
+
zero_v2(center);
-
- 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)) {
- add_v2_v2(center, tf->uv[0]);
- tot++;
- }
- if(uvedit_uv_selected(scene, efa, tf, 1)) {
- add_v2_v2(center, tf->uv[1]);
- tot++;
- }
- if(uvedit_uv_selected(scene, efa, tf, 2)) {
- add_v2_v2(center, tf->uv[2]);
- tot++;
- }
- if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
- add_v2_v2(center, tf->uv[3]);
+ 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 (uvedit_uv_selected(em, scene, l)) {
+ add_v2_v2(center, luv->uv);
tot++;
}
}
@@ -100,23 +89,19 @@ static int uvedit_center(Scene *scene, EditMesh *em, Image *ima, float center[2]
return tot;
}
-static void uvedit_translate(Scene *scene, EditMesh *em, Image *ima, float delta[2])
+static void uvedit_translate(Scene *scene, BMEditMesh *em, Image *UNUSED(ima), float delta[2])
{
- EditFace *efa;
- MTFace *tf;
-
- 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))
- add_v2_v2(tf->uv[0], delta);
- if(uvedit_uv_selected(scene, efa, tf, 1))
- add_v2_v2(tf->uv[1], delta);
- if(uvedit_uv_selected(scene, efa, tf, 2))
- add_v2_v2(tf->uv[2], delta);
- if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
- add_v2_v2(tf->uv[3], delta);
+ BMFace *f;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ 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 (uvedit_uv_selected(em, scene, l)) {
+ add_v2_v2(luv->uv, delta);
+ }
}
}
}
@@ -131,13 +116,13 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block)
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
Image *ima= sima->image;
+ BMEditMesh *em;
float center[2];
int imx, imy, step, digits;
- EditMesh *em;
ED_space_image_size(sima, &imx, &imy);
- em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ em= ((Mesh *)obedit->data)->edit_btmesh;
if(uvedit_center(scene, em, ima, center)) {
copy_v2_v2(uvedit_old_center, center);
@@ -161,8 +146,6 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block)
uiDefButF(block, NUM, B_UVEDIT_VERTEX, "Y:", 165, 10, 145, 19, &uvedit_old_center[1], -10*imy, 10.0*imy, step, digits, "");
uiBlockEndAlign(block);
}
-
- BKE_mesh_end_editmesh(obedit->data, em);
}
static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
@@ -171,14 +154,14 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
Image *ima= sima->image;
- EditMesh *em;
+ BMEditMesh *em;
float center[2], delta[2];
int imx, imy;
if(event != B_UVEDIT_VERTEX)
return;
- em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ em= ((Mesh *)obedit->data)->edit_btmesh;
ED_space_image_size(sima, &imx, &imy);
uvedit_center(scene, em, ima, center);
@@ -194,8 +177,6 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
uvedit_translate(scene, em, ima, delta);
- BKE_mesh_end_editmesh(obedit->data, em);
-
WM_event_add_notifier(C, NC_IMAGE, sima->image);
}
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index 6ced91f0d01..ca8f1e4fb97 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -31,7 +31,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"
@@ -44,7 +48,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"
@@ -121,34 +127,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;
@@ -157,13 +162,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) {
@@ -171,21 +182,36 @@ 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);
+ BLI_array_growitems(tf_uv, efa->len);
+ BLI_array_growitems(tf_uvorig, efa->len);
+
+ 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);
+
+ copy_v2_v2(tf_uvorig[i], luv->uv);
+
+ i++;
+ }
- totarea += EM_face_area(efa);
+ poly_copy_aspect(tf_uvorig, tf_uv, aspx, aspy, efa->len);
+
+ totarea += BM_face_area_calc(em->bm, efa);
//totuvarea += tf_area(tf, efa->v4!=0);
- totuvarea += uv_area(tf_uv, efa->v4 != NULL);
+ totuvarea += poly_uv_area(tf_uv, efa->len);
if(uvedit_face_visible(scene, ima, efa, tf)) {
- efa->tmp.p = tf;
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
else {
if(tf == activetf)
activetf= NULL;
- efa->tmp.p = NULL;
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
}
}
@@ -193,24 +219,40 @@ 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(BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ 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(BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ area = BM_face_area_calc(em->bm, efa) / totarea;
+
+ BLI_array_empty(tf_uv);
+ BLI_array_empty(tf_uvorig);
+ BLI_array_growitems(tf_uv, efa->len);
+ BLI_array_growitems(tf_uvorig, efa->len);
+
+ 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);
+
+ copy_v2_v2(tf_uvorig[i], luv->uv);
+
+ 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 != NULL) / totuvarea;
+ uvarea = poly_uv_area(tf_uv, efa->len) / totuvarea;
if(area < FLT_EPSILON || uvarea < FLT_EPSILON)
areadiff = 1.0f;
@@ -222,11 +264,11 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac
weight_to_rgb(col, areadiff);
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();
}
}
@@ -235,6 +277,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 */
@@ -245,7 +288,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;
@@ -376,6 +419,8 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac
glShadeModel(GL_FLAT);
break;
+
+#endif
}
}
}
@@ -397,17 +442,19 @@ static void draw_uvs_other(Scene *scene, Object *obedit, Image *curimage)
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();
}
}
@@ -427,17 +474,19 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob)
glColor3ub(112, 112, 112);
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();
}
}
@@ -449,19 +498,23 @@ 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;
Image *ima= sima->image;
- StitchPreviewer *stitch_preview = uv_get_stitch_previewer();
- em= BKE_mesh_get_editmesh(me);
- activetf= EM_get_active_mtface(em, &efa_act, NULL, 0); /* will be set to NULL if hidden */
+ StitchPreviewer *stitch_preview = uv_get_stitch_previewer();
+ em= me->edit_btmesh;
+ activetf= EDBM_get_active_mtexpoly(em, &efa_act, FALSE); /* will be set to NULL if hidden */
+ activef = BM_active_face_get(em->bm, FALSE);
ts= scene->toolsettings;
drawfaces= draw_uvs_face_check(scene);
@@ -483,7 +536,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 */
@@ -508,45 +561,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 */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ 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;
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
}
}
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;
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
else {
if(tf == activetf)
activetf= NULL;
- efa->tmp.p = NULL;
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
}
}
@@ -554,7 +608,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);
@@ -562,11 +616,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);
@@ -583,39 +637,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 (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ 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);
}
}
@@ -625,34 +678,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 (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ 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 */
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ 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();
}
glLineWidth(1);
@@ -660,89 +711,62 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
glColor4ubv((unsigned char *)col2);
if(me->drawflag & ME_DRAWEDGES) {
- int lastsel= 0, sel;
+ int sel, lastsel = -1;
UI_GetThemeColor4ubv(TH_VERTEX_SELECT, col1);
if(interpedges) {
glShadeModel(GL_SMOOTH);
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= (MTFace *)efa->tmp.p; /* visible faces cached */
-
- 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;
- 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();
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ continue;
+
+ glBegin(GL_LINE_LOOP);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ sel = (uvedit_uv_selected(em, scene, l)? 1 : 0);
+ glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2);
+
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ glVertex2fv(luv->uv);
}
+ glEnd();
}
glShadeModel(GL_FLAT);
}
else {
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf= (MTFace *)efa->tmp.p; /* visible faces cached */
-
- 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;
- 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]);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ continue;
+
+ glBegin(GL_LINES);
+ 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[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);
}
+ 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 (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ 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();
}
}
@@ -766,11 +790,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 (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ 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);
}
}
@@ -780,11 +805,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 (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ 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);
}
}
@@ -800,18 +826,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 (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ 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();
@@ -822,18 +844,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 (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ 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();
@@ -843,18 +862,15 @@ 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 (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ 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();
@@ -872,9 +888,6 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
glVertexPointer(2, GL_FLOAT, 0, stitch_preview->static_tris);
glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_static_tris*3);
- glVertexPointer(2, GL_FLOAT, 0, stitch_preview->static_quads);
- glDrawArrays(GL_QUADS, 0, stitch_preview->num_static_quads*4);
-
glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_tris);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
UI_ThemeColor4(TH_STITCH_PREVIEW_FACE);
@@ -885,18 +898,6 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
/*UI_ThemeColor4(TH_STITCH_PREVIEW_VERT);
glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_tris*3);*/
-
- glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_quads);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- UI_ThemeColor4(TH_STITCH_PREVIEW_FACE);
- glDrawArrays(GL_QUADS, 0, stitch_preview->num_quads*4);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- UI_ThemeColor4(TH_STITCH_PREVIEW_EDGE);
- glDrawArrays(GL_QUADS, 0, stitch_preview->num_quads*4);
- glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
- /*UI_ThemeColor4(TH_STITCH_PREVIEW_VERT);
- glDrawArrays(GL_QUADS, 0, stitch_preview->num_quads*4);*/
-
glDisable(GL_BLEND);
/* draw vert preview */
@@ -914,7 +915,6 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
}
glPointSize(1.0);
- BKE_mesh_end_editmesh(obedit->data, em);
}
void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedit, Object *obact)
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index a5b4173cc67..6566a79e467 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -34,6 +34,7 @@
struct EditFace;
struct EditMesh;
+struct MTexPoly;
struct Image;
struct MTFace;
struct Object;
@@ -41,59 +42,65 @@ struct Scene;
struct SpaceImage;
struct UvElementMap;
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]);
+
/* find nearest */
typedef struct NearestHit {
- struct EditFace *efa;
- struct MTFace *tf;
-
- int vert, uv;
- int edge, vert2;
+ struct BMFace *efa;
+ struct MTexPoly *tf;
+ struct BMLoop *l, *nextl;
+ struct MLoopUV *luv, *nextluv;
+ int lindex; //index of loop within face
+ int vert1, vert2; //index in mesh of edge vertices
} NearestHit;
-void uv_find_nearest_vert(struct Scene *scene, struct Image *ima, struct EditMesh *em, float co[2], float penalty[2], struct NearestHit *hit);
-void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct EditMesh *em, float co[2], struct NearestHit *hit);
+void uv_find_nearest_vert(struct Scene *scene, struct Image *ima, struct BMEditMesh *em, float co[2], float penalty[2], struct NearestHit *hit);
+void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct BMEditMesh *em, float co[2], struct NearestHit *hit);
/* utility tool functions */
-struct UvElement *ED_get_uv_element(struct UvElementMap *map, struct EditFace *efa, int index);
+struct UvElement *ED_get_uv_element(struct UvElementMap *map, struct BMFace *efa, int index);
void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit);
/* smart stitch */
/* object that stores display data for previewing before accepting stitching */
typedef struct StitchPreviewer {
- /* OpenGL requires different calls for Triangles and Quads.
- * here we'll store the quads of the mesh */
- float *preview_quads;
- /* ...and here we'll store the triangles*/
+ /* here we'll store the preview triangles of the mesh */
float *preview_tris;
/* preview data. These will be either the previewed vertices or edges depending on stitch mode settings */
float *preview_stitchable;
float *preview_unstitchable;
/* here we'll store the number of triangles and quads to be drawn */
unsigned int num_tris;
- unsigned int num_quads;
unsigned int num_stitchable;
unsigned int num_unstitchable;
- /* store static island Quads */
- float *static_quads;
/* ...and here we'll store the triangles*/
float *static_tris;
unsigned int num_static_tris;
- unsigned int num_static_quads;
} StitchPreviewer;
StitchPreviewer *uv_get_stitch_previewer(void);
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 5f836ec4ca7..0df2a70302a 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -33,6 +33,7 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
+#include <string.h>
#include "MEM_guardedalloc.h"
@@ -40,11 +41,14 @@
#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_node_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"
@@ -58,6 +62,7 @@
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_tessmesh.h"
#include "ED_image.h"
#include "ED_mesh.h"
@@ -77,19 +82,23 @@
#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)
+ return 0;
+
+ 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;
}
@@ -157,9 +166,10 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i
void ED_uvedit_assign_image(Main *bmain, 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... */
@@ -170,16 +180,15 @@ void ED_uvedit_assign_image(Main *bmain, Scene *scene, Object *obedit, Image *im
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;
}
if(scene_use_new_shading_nodes(scene)) {
/* new shading system, assign image in material */
int sloppy= 1;
- EditFace *efa= EM_get_actFace(em, sloppy);
+ BMFace *efa= BM_active_face_get(em->bm, sloppy);
if(efa)
ED_object_assign_active_image(bmain, obedit, efa->mat_nr, ima);
@@ -188,14 +197,15 @@ void ED_uvedit_assign_image(Main *bmain, Scene *scene, Object *obedit, Image *im
/* old shading system, assign image to selected faces */
/* ensure we have a uv map */
- 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_data_layer_add(em->bm, &em->bm->pdata, CD_MTEXPOLY);
+ BM_data_layer_add(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) {
@@ -204,8 +214,9 @@ void ED_uvedit_assign_image(Main *bmain, Scene *scene, Object *obedit, Image *im
if(ima->id.us==0) id_us_plus(&ima->id);
else id_lib_extern(&ima->id);
}
- else
+ else {
tf->tpage= NULL;
+ }
update = 1;
}
@@ -216,16 +227,16 @@ void ED_uvedit_assign_image(Main *bmain, Scene *scene, Object *obedit, Image *im
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))
@@ -238,17 +249,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_elem_flag_test(efa, BM_ELEM_HIDDEN) && BM_elem_flag_test(efa, BM_ELEM_SELECT))
tf->tile= curtile; /* set tile index */
}
DAG_id_tag_update(obedit->data, 0);
- BKE_mesh_end_editmesh(obedit->data, em);
return 1;
}
@@ -273,18 +283,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_elem_flag_test(efa, BM_ELEM_HIDDEN)==0);
else
- return (efa->h==0 && (efa->f & SELECT));
+ return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)==0 && BM_elem_flag_test(efa, BM_ELEM_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)
@@ -293,131 +302,199 @@ 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_elem_flag_test(efa, BM_ELEM_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_elem_select_set(em->bm, efa, TRUE);
+ 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);
+ if(ts->uv_flag & UV_SYNC_SELECTION) {
+ BM_elem_select_set(em->bm, efa, FALSE);
+ }
+ 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));
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ return BM_elem_flag_test(l->f, BM_ELEM_SELECT);
+ }
+ else if (ts->selectmode == SCE_SELECT_EDGE) {
+ return BM_elem_flag_test(l->e, BM_ELEM_SELECT);
+ }
+ else {
+ return BM_elem_flag_test(l->v, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(l->next->v, BM_ELEM_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_elem_select_set(em->bm, l->f, TRUE);
else if(ts->selectmode & SCE_SELECT_EDGE)
- EM_select_edge((*(&efa->e1 + i)), 1);
+ BM_elem_select_set(em->bm, l->e, TRUE);
else {
- (efa->v1 + i)->f |= SELECT;
- (efa->v1 + (i+1)%nvert)->f |= SELECT;
+ BM_elem_select_set(em->bm, l->e->v1, TRUE);
+ BM_elem_select_set(em->bm, l->e->v2, TRUE);
}
}
- 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_elem_select_set(em->bm, l->f, FALSE);
else if(ts->selectmode & SCE_SELECT_EDGE)
- EM_select_edge((*(&efa->e1 + i)), 0);
+ BM_elem_select_set(em->bm, l->e, FALSE);
else {
- (efa->v1 + i)->f &= ~SELECT;
- (efa->v1 + (i+1)%nvert)->f &= ~SELECT;
+ BM_elem_select_set(em->bm, l->e->v1, FALSE);
+ BM_elem_select_set(em->bm, l->e->v2, FALSE);
}
}
- 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_elem_flag_test(l->f, BM_ELEM_SELECT);
else
- return (*(&efa->v1 + i))->f & SELECT;
+ return BM_elem_flag_test(l->v, BM_ELEM_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_elem_select_set(em->bm, l->f, TRUE);
else
- (*(&efa->v1 + i))->f |= SELECT;
+ BM_elem_select_set(em->bm, l->v, TRUE);
+ }
+ 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_elem_select_set(em->bm, l->f, FALSE);
else
- (*(&efa->v1 + i))->f &= ~SELECT;
+ BM_elem_select_set(em->bm, l->v, FALSE);
+ }
+ 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);
}
/*********************** live unwrap utilities ***********************/
@@ -432,6 +509,22 @@ void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
}
/*********************** geometric utilities ***********************/
+void poly_uv_center(BMEditMesh *em, BMFace *f, float cent[2])
+{
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ zero_v2(cent);
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ add_v2_v2(cent, luv->uv);
+ }
+
+ mul_v2_fl(cent, 1.0f / (float)f->len);
+}
+
void uv_center(float uv[][2], float cent[2], int quad)
{
@@ -453,6 +546,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;
@@ -470,56 +585,66 @@ 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 ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[3])
{
- 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;
unsigned int sel= 0;
zero_v3(co);
-
- 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)) { add_v3_v3(co, tf->uv[0]); sel++; }
- if(uvedit_uv_selected(scene, efa, tf, 1)) { add_v3_v3(co, tf->uv[1]); sel++; }
- if(uvedit_uv_selected(scene, efa, tf, 2)) { add_v3_v3(co, tf->uv[2]); sel++; }
- if(efa->v4 && (uvedit_uv_selected(scene, efa, tf, 3))) { add_v3_v3(co, tf->uv[3]); sel++; }
+ 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 (uvedit_uv_selected(em, scene, l)) {
+ add_v2_v2(co, luv->uv);
+ sel++;
+ }
}
}
mul_v3_fl(co, 1.0f/(float)sel);
- BKE_mesh_end_editmesh(obedit->data, em);
return (sel != 0);
}
static int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent, char mode)
{
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
float min[2], max[2];
int change= 0;
@@ -539,99 +664,133 @@ static int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent,
}
if(change) {
- BKE_mesh_end_editmesh(obedit->data, em);
return 1;
}
- BKE_mesh_end_editmesh(obedit->data, em);
return 0;
}
/************************** find nearest ****************************/
-void uv_find_nearest_edge(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
+void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
{
- MTFace *tf;
- EditFace *efa;
- EditVert *eve;
+ MTexPoly *tf;
+ BMFace *efa;
+ BMLoop *l;
+ 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;
+ BM_mesh_elem_index_ensure(em->bm, BM_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)) {
- 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 = l->next;
+ hit->luv = luv;
+ hit->nextluv = nextluv;
+ hit->lindex = i;
+ hit->vert1 = BM_elem_index_get(hit->l->v);
+ hit->vert2 = BM_elem_index_get(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*/
+ uv_find_nearest_edge(scene, ima, em, co, hit);
+ hit->l = hit->nextl = NULL;
+ hit->luv = hit->nextluv = NULL;
- for(i=0; i<nverts; i++) {
- add_v2_v2(cent, tf->uv[i]);
- }
+ 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]);
+ add_v2_v2(cent, luv->uv);
+ }
- 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 UNUSED(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];
@@ -647,86 +806,99 @@ static int nearest_uv_between(MTFace *tf, int nverts, int id, float co[2], float
return (c1*c2 >= 0.0f);
}
-void uv_find_nearest_vert(Scene *scene, Image *ima, EditMesh *em, float co[2], float penalty[2], NearestHit *hit)
+void uv_find_nearest_vert(Scene *scene, Image *ima, BMEditMesh *em,
+ float co[2], float penalty[2], NearestHit *hit)
{
- EditFace *efa;
- EditVert *eve;
- MTFace *tf;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ MLoopUV *luv;
float mindist, dist;
- int i, nverts;
+ int i;
+
+ /*this will fill in hit.vert1 and hit.vert2*/
+ uv_find_nearest_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);
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
- if(uvedit_face_visible(scene, ima, efa, tf)) {
- nverts= efa->v4? 4: 3;
-
- for(i=0; i<nverts; i++) {
- if(penalty && uvedit_uv_selected(scene, efa, tf, i))
- dist= fabsf(co[0]-tf->uv[i][0])+penalty[0] + fabsf(co[1]-tf->uv[i][1]) + penalty[1];
- else
- dist= fabsf(co[0]-tf->uv[i][0]) + fabsf(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 = 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 = BM_elem_index_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++) {
- if(uvedit_uv_selected(scene, efa, tf, i))
- continue;
-
- 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;
}
@@ -748,25 +920,34 @@ 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 = BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, a);
+ first= EDBM_get_uv_map_vert(vmap, BM_elem_index_get(l->v));
for(iterv=first; iterv; iterv=iterv->next) {
if(iterv->separate)
first= iterv;
- if(iterv->f == efa->tmp.l)
+ if(iterv->f == BM_elem_index_get(efa))
return first;
}
return NULL;
}
-UvElement *ED_get_uv_element(UvElementMap *map, EditFace *efa, int index)
+/* BMESH_TODO - in some cases we already know the loop so looking up the index isnt needed */
+
+UvElement *ED_get_uv_element(UvElementMap *map, BMFace *efa, int index)
{
- UvElement *element = map->vert[(*(&efa->v1 + index))->tmp.l];
+ BMLoop *l;
+ UvElement *element;
+
+ l = BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, index);
+
+ element = map->vert[BM_elem_index_get(l->v)];
for(; element; element = element->next)
if(element->face == efa)
@@ -775,10 +956,10 @@ UvElement *ED_get_uv_element(UvElementMap *map, EditFace *efa, int index)
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 */
@@ -792,8 +973,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_elem_flag_test(em->bm, efa, EFA_F1_FLAG))
return 0;
tot++;
@@ -817,8 +998,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_elem_flag_enable(em->bm, efa, EFA_F1_FLAG);
break;
}
}
@@ -827,41 +1008,45 @@ 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;
+ 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;
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
- 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);
}
+
+ BMO_elem_flag_disable(em->bm, efa, EFA_F1_FLAG);
- efa->tmp.l= count;
- efa->f1= 0;
+ BM_elem_index_set(efa, count); /* set_inline */
+
+ count++;
}
-
+ em->bm->elem_index_dirty &= ~BM_FACE;
+
/* 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;
@@ -872,21 +1057,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_elem_flag_test(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_elem_flag_enable(em->bm, efa, EFA_F1_FLAG);
uv_vertex_loop_flag(iterv1);
uv_vertex_loop_flag(iterv2);
@@ -899,16 +1088,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))
+ if(uvedit_uv_selected(em, scene, hit->l))
select= 0;
else
select= 1;
@@ -916,83 +1103,109 @@ 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 i, nverts, stacksize= 0, *stack;
unsigned int a;
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+1), "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;
+
+ j++;
+ }
- efa = EM_get_face_for_index(a);
+ 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, BM_elem_index_get(l->v));
startv= vlist;
@@ -1012,50 +1225,108 @@ 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) {
+ 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;
+ }
+ a++;
}
}
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) {
+ if (!flag[a]) {
+ 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);
+
+ if (luv->flag & MLOOPUV_VERTSEL)
break;
}
+
+ if (l)
+ 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]) {
+ 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]) {
+ 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);
+}
+
+/* WATCH IT: this returns first selected UV,
+ * not ideal in many cases since there could be multiple */
+static float *uv_sel_co_from_eve(Scene *scene, Image *ima, BMEditMesh *em, BMVert *eve)
+{
+ BMIter liter;
+ BMLoop *l;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_VERT, eve) {
+ MTexPoly *tf = CustomData_bmesh_get(&em->bm->pdata, l->f->head.data, CD_MTEXPOLY);
+
+ if (!uvedit_face_visible(scene, ima, l->f, tf))
+ continue;
+
+ if (uvedit_uv_selected(em, scene, l)) {
+ MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ return luv->uv;
+ }
+ }
+
+ return NULL;
}
/* ******************** align operator **************** */
@@ -1066,32 +1337,35 @@ static void weld_align_uv(bContext *C, int tool)
Scene *scene;
Object *obedit;
Image *ima;
- EditMesh *em;
- EditFace *efa;
- MTFace *tf;
+ BMEditMesh *em;
+ 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);
sima= CTX_wm_space_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);
+ BMFace *efa;
+ BMLoop *l;
- 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)
+ 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)
+ }
}
}
@@ -1101,170 +1375,173 @@ 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];
+ BMFace *efa;
+ BMLoop *l;
+
+ 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];
+ BMFace *efa;
+ BMLoop *l;
+
+ 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];
+ }
+
}
}
}
if(tool == 's' || tool == 't' || tool == 'u') {
- /* pass 1&2 variables */
- int i, j;
- int starttmpl= -1, connectedtostarttmpl= -1, startcorner;
- int endtmpl= -1, connectedtoendtmpl= -1, endcorner;
- MTFace *startface, *endface;
- int itmpl, jtmpl;
- EditVert *eve;
- int pass; /* first 2 passes find endpoints, 3rd pass moves middle points, 4th pass is fail-on-face-selected */
- EditFace *startefa, *endefa= NULL; /* endefa shouldnt need to be initialized but just incase */
-
- /* pass 3 variables */
- float startx, starty, firstm, firstb, midx, midy;
- float endx, endy, secondm, secondb, midmovedx, midmovedy;
- float IsVertical_check= -1;
- float IsHorizontal_check= -1;
-
- for(i= 0, eve= em->verts.first; eve; eve= eve->next, i++) /* give each point a unique name */
- eve->tmp.l= i;
- for(pass= 1; pass <= 3; pass++) { /* do this for each endpoint */
- if(pass == 3){ /* calculate */
- startx= startface->uv[startcorner][0];
- starty= startface->uv[startcorner][1];
- endx= endface->uv[endcorner][0];
- endy= endface->uv[endcorner][1];
- firstm= (endy-starty)/(endx-startx);
- firstb= starty-(firstm*startx);
- secondm= -1.0f/firstm;
- if(startx == endx) IsVertical_check= startx;
- if(starty == endy) IsHorizontal_check= starty;
- }
- for(efa= em->faces.first; efa; efa= efa->next) { /* for each face */
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); /* get face */
- if(uvedit_face_visible(scene, ima, efa, tf)) { /* if you can see it */
- if(uvedit_face_selected(scene, efa, tf)) { /* if the face is selected, get out now! */
- pass= 4;
- break;
- }
- for(i= 0; (i < 3 || (i == 3 && efa->v4)); i++) { /* for each point of the face */
- itmpl= (*(&efa->v1 + i))->tmp.l; /* get unique name for points */
- if(pass == 3) { /* move */
- if(uvedit_uv_selected(scene, efa, tf, i)) {
- if(!(itmpl == starttmpl || itmpl == endtmpl)) {
- if(IsVertical_check != -1) tf->uv[i][0]= IsVertical_check;
- if(IsHorizontal_check != -1) tf->uv[i][1]= IsHorizontal_check;
- if((IsVertical_check == -1) && (IsHorizontal_check == -1)) {
- midx= tf->uv[i][0];
- midy= tf->uv[i][1];
- if(tool == 's') {
- secondb= midy-(secondm*midx);
- midmovedx= (secondb-firstb)/(firstm-secondm);
- midmovedy= (secondm*midmovedx)+secondb;
- tf->uv[i][0]= midmovedx;
- tf->uv[i][1]= midmovedy;
- }
- else if(tool == 't') {
- tf->uv[i][0]= (midy-firstb)/firstm; /* midmovedx */
- }
- else if(tool == 'u') {
- tf->uv[i][1]= (firstm*midx)+firstb; /* midmovedy */
- }
- }
- }
- }
+ BMEdge *eed;
+ BMLoop *l;
+ BMVert *eve;
+ BMVert *eve_start;
+ BMIter iter, liter, eiter;
+
+ /* clear tag */
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BM_elem_flag_disable(eve, BM_ELEM_TAG);
+ }
+
+ /* tag verts with a selected UV */
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_VERT, eve) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, l->f->head.data, CD_MTEXPOLY);
+
+ if (!uvedit_face_visible(scene, ima, l->f, tf))
+ continue;
+
+ if (uvedit_uv_selected(em, scene, l)) {
+ BM_elem_flag_enable(eve, BM_ELEM_TAG);
+ break;
+ }
+ }
+ }
+
+ /* flush vertex tags to edges */
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) && BM_elem_flag_test(eed->v2, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(eed, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_disable(eed, BM_ELEM_TAG);
+ }
+ }
+
+ /* find a vertex with only one tagged edge */
+ eve_start = NULL;
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ int tot_eed_tag = 0;
+ BM_ITER(eed, &eiter, em->bm, BM_EDGES_OF_VERT, eve) {
+ if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
+ tot_eed_tag++;
+ }
+ }
+
+ if (tot_eed_tag == 1) {
+ eve_start = eve;
+ break;
+ }
+ }
+
+ if (eve_start) {
+ BMVert **eve_line = NULL;
+ BMVert *eve_next = NULL;
+ BLI_array_declare(eve_line);
+ int i;
+
+ eve = eve_start;
+
+ /* walk over edges, building an array of verts in a line */
+ while (eve) {
+ BLI_array_append(eve_line, eve);
+ /* dont touch again */
+ BM_elem_flag_disable(eve, BM_ELEM_TAG);
+
+ eve_next = NULL;
+
+ /* find next eve */
+ BM_ITER(eed, &eiter, em->bm, BM_EDGES_OF_VERT, eve) {
+ if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
+ BMVert *eve_other = BM_edge_other_vert(eed, eve);
+ if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) {
+ /* this is a tagged vert we didnt walk over yet, step onto it */
+ eve_next = eve_other;
+ break;
}
- else {
- for(j= 0; (j < 3 || (j == 3 && efa->v4)); j++) { /* also for each point on the face */
- jtmpl= (*(&efa->v1 + j))->tmp.l;
- if(i != j && (!efa->v4 || ABS(i-j) != 2)) { /* if the points are connected */
- /* quad (0,1,2,3) 0,1 0,3 1,0 1,2 2,1 2,3 3,0 3,2
- * triangle (0,1,2) 0,1 0,2 1,0 1,2 2,0 2,1 */
- if(uvedit_uv_selected(scene, efa, tf, i) && uvedit_uv_selected(scene, efa, tf, j)) {
- /* if the edge is selected */
- if(pass == 1) { /* if finding first endpoint */
- if(starttmpl == -1) { /* if the first endpoint isn't found yet */
- starttmpl= itmpl; /* set unique name for endpoint */
- connectedtostarttmpl= jtmpl;
- /* get point that endpoint is connected to */
- startface= tf; /* get face it's on */
- startcorner= i; /* what corner of the face? */
- startefa= efa;
- efa= em->faces.first;
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- i= -1;
- break;
- }
- if(starttmpl == itmpl && jtmpl != connectedtostarttmpl) {
- starttmpl= -1; /* not an endpoint */
- efa= startefa;
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- i= startcorner;
- break;
- }
- }
- else if(pass == 2) { /* if finding second endpoint */
- if(endtmpl == -1 && itmpl != starttmpl) {
- endtmpl= itmpl;
- connectedtoendtmpl= jtmpl;
- endface= tf;
- endcorner= i;
- endefa= efa;
- efa= em->faces.first;
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- i= -1;
- break;
- }
- if(endtmpl == itmpl && jtmpl != connectedtoendtmpl) {
- endtmpl= -1;
- efa= endefa;
- tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- i= endcorner;
- break;
- }
- }
- }
- }
- }
+ }
+ }
+
+ eve = eve_next;
+ }
+
+ /* now we have all verts, make into a line */
+ if (BLI_array_count(eve_line) > 2) {
+
+ /* we know the returns from these must be valid */
+ float *uv_start = uv_sel_co_from_eve(scene, ima, em, eve_line[0]);
+ float *uv_end = uv_sel_co_from_eve(scene, ima, em, eve_line[BLI_array_count(eve_line) - 1]);
+
+ if (tool == 't') {
+ uv_start[0] = uv_end[0] = (uv_start[0] + uv_end[0]) * 0.5f;
+ }
+ else if (tool == 'u') {
+ uv_start[1] = uv_end[1] = (uv_start[1] + uv_end[1]) * 0.5f;
+ }
+
+ /* go over all verts except for endpoints */
+ for (i = 0; i < BLI_array_count(eve_line); i++) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_VERT, eve_line[i]) {
+ tf = CustomData_bmesh_get(&em->bm->pdata, l->f->head.data, CD_MTEXPOLY);
+
+ if (!uvedit_face_visible(scene, ima, l->f, tf))
+ continue;
+
+ if (uvedit_uv_selected(em, scene, l)) {
+ MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end);
}
}
}
}
- if(pass == 2 && (starttmpl == -1 || endtmpl == -1)) {
- /* if endpoints aren't found */
- pass=4;
+ else {
+ /* error - not a line, needs 3+ points */
}
+
+ if (eve_line) {
+ MEM_freeN(eve_line);
+ }
+ }
+ else {
+ /* error - cant find an endpoint */
}
}
+
uvedit_live_unwrap_update(sima, scene, obedit);
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)
@@ -1321,6 +1598,7 @@ static void UV_OT_weld(wmOperatorType *ot)
ot->poll= ED_operator_uvedit;
}
+
/* ******************** (de)select all operator **************** */
static void select_all_perform(bContext *C, int action)
@@ -1328,43 +1606,50 @@ static void select_all_perform(bContext *C, int action)
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) {
+
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_flag_enable_all(em, BM_ELEM_SELECT);
break;
case SEL_DESELECT:
- EM_deselect_all(em);
+ EDBM_flag_disable_all(em, BM_ELEM_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;
+
+ 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_face_visible(scene, ima, efa, tf)) {
- if(tf->flag & select_flag) {
+ if (luv->flag & MLOOPUV_VERTSEL) {
action = SEL_DESELECT;
break;
}
@@ -1372,21 +1657,25 @@ static void select_all_perform(bContext *C, int action)
}
}
- 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:
- tf->flag ^= select_flag;
+ luv->flag ^= MLOOPUV_VERTSEL;
break;
}
}
@@ -1397,14 +1686,12 @@ static void select_all_perform(bContext *C, int action)
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");
select_all_perform(C, action);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -1425,7 +1712,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;
@@ -1434,7 +1721,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(fabsf(hituv[i][0]-uv[0]) < limit[0] && fabsf(hituv[i][1]-uv[1]) < limit[1])
@@ -1455,13 +1742,19 @@ 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 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];
/* notice 'limit' is the same no matter the zoom level, since this is like
* remove doubles and could annoying if it joined points when zoomed out.
@@ -1496,76 +1789,100 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
/* find edge */
uv_find_nearest_edge(scene, ima, em, co, &hit);
if(hit.efa == NULL) {
- BKE_mesh_end_editmesh(obedit->data, em);
+ BLI_array_free(hitv);
+ BLI_array_free(hituv);
return OPERATOR_CANCELLED;
}
+
+ hitlen = 0;
}
else if(selectmode == UV_SELECT_VERTEX) {
/* find vertex */
uv_find_nearest_vert(scene, ima, em, co, penalty, &hit);
if(hit.efa == NULL) {
- BKE_mesh_end_editmesh(obedit->data, em);
+ BLI_array_free(hitv);
+ BLI_array_free(hituv);
return OPERATOR_CANCELLED;
}
/* mark 1 vertex as being hit */
- for(i=0; i<4; i++)
+ BLI_array_growitems(hitv, hit.efa->len);
+ BLI_array_growitems(hituv, hit.efa->len);
+ for(i=0; i<hit.efa->len; i++) {
hitv[i]= 0xFFFFFFFF;
+ }
- hitv[hit.uv]= hit.vert;
- hituv[hit.uv]= hit.tf->uv[hit.uv];
+ hitv[hit.lindex]= hit.vert1;
+ hituv[hit.lindex]= hit.luv->uv;
+
+ hitlen = hit.efa->len;
}
else if(selectmode == UV_SELECT_EDGE) {
/* find edge */
uv_find_nearest_edge(scene, ima, em, co, &hit);
if(hit.efa == NULL) {
- BKE_mesh_end_editmesh(obedit->data, em);
+ BLI_array_free(hitv);
+ BLI_array_free(hituv);
return OPERATOR_CANCELLED;
}
/* mark 2 edge vertices as being hit */
- for(i=0; i<4; i++)
+ BLI_array_growitems(hitv, hit.efa->len);
+ BLI_array_growitems(hituv, hit.efa->len);
+ for (i=0; i < hit.efa->len; i++) {
hitv[i]= 0xFFFFFFFF;
+ }
+
+ nvert= hit.efa->len;
- nvert= (hit.efa->v4)? 4: 3;
+ 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;
- 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];
+ 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);
+ BLI_array_free(hitv);
+ BLI_array_free(hituv);
return OPERATOR_CANCELLED;
}
/* make active */
- EM_set_actFace(em, hit.efa);
+ BM_active_face_set(em->bm, hit.efa);
/* mark all face vertices as being hit */
- for(i=0; i<4; i++)
- hituv[i]= hit.tf->uv[i];
- hitv[0]= hit.efa->v1->tmp.l;
- hitv[1]= hit.efa->v2->tmp.l;
- hitv[2]= hit.efa->v3->tmp.l;
+ BLI_array_growitems(hitv, hit.efa->len);
+ BLI_array_growitems(hituv, hit.efa->len);
+ 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);
+ hituv[i]= luv->uv;
+ hitv[i] = BM_elem_index_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) {
uv_find_nearest_vert(scene, ima, em, co, NULL, &hit);
if(hit.efa==NULL) {
- BKE_mesh_end_editmesh(obedit->data, em);
+ BLI_array_free(hitv);
+ BLI_array_free(hituv);
return OPERATOR_CANCELLED;
}
+
+ hitlen = 0;
}
else {
- BKE_mesh_end_editmesh(obedit->data, em);
+ hitlen = 0;
+ BLI_array_free(hitv);
+ BLI_array_free(hituv);
return OPERATOR_CANCELLED;
}
@@ -1579,36 +1896,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;
@@ -1616,109 +1933,101 @@ 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;
-
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
/* 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, BM_elem_index_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, BM_elem_index_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, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen))
+ uvedit_uv_select(em, scene, l);
flush= 1;
}
}
}
}
-
+
+#if 0 /* BM_elem_select_set API handles all of this? */
+
if(sync) {
/* flush for mesh selection */
if(ts->selectmode != SCE_SELECT_FACE) {
- if(flush==1) EM_select_flush(em);
- else if(flush==-1) EM_deselect_flush(em);
+ if(flush==1) EDBM_select_flush(em);
+ else if(flush==-1) EDBM_deselect_flush(em);
}
}
-
- DAG_id_tag_update(obedit->data, 0);
+
+#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);
+
+ BLI_array_free(hitv);
+ BLI_array_free(hituv);
+
return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
}
@@ -1819,7 +2128,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;
@@ -1827,7 +2136,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;
}
@@ -1858,7 +2166,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;
}
@@ -1923,31 +2230,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->ldata, 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->ldata, 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;
}
@@ -1982,78 +2303,78 @@ 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) {
+ BM_elem_flag_disable(eve, BM_ELEM_TAG);
+ }
- 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 (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
}
}
/* 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); */ /* UNUSED */
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
+ 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; */ /* UNUSED */
UvMapVert *start_vlist=NULL, *vlist_iter;
struct UvVertMap *vmap;
float limit[2];
unsigned 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 = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for (efa_index=0; efa; efa=BM_iter_step(&iter), efa_index++) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
+
+ 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, BM_elem_index_get(l->v));
while (vlist_iter) {
if(vlist_iter->separate)
@@ -2072,35 +2393,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); */ /* UNUSED */
if(select)
- uvedit_uv_select(scene, efa_vlist, tf_vlist, vlist_iter->tfindex);
+ uvedit_uv_select(em, scene, BM_iter_at_index(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, BM_iter_at_index(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 (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
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)
@@ -2111,9 +2430,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, extend;
@@ -2147,14 +2469,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);
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+
+ 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;
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ change = 1;
}
}
}
@@ -2166,51 +2490,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);
}
}
}
@@ -2219,20 +2518,20 @@ static int border_select_exec(bContext *C, wmOperator *op)
if(change) {
/* make sure newly selected vert selection is updated*/
+#if 0 /* BM_elem_select_set 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);
+ if(select) EDBM_select_flush(em);
+ else EDBM_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;
}
@@ -2261,20 +2560,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 *UNUSED(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.0f) {
- 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);
}
}
@@ -2283,10 +2584,12 @@ 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;
int x, y, radius, width, height, select;
float zoomx, zoomy, offset[2], ellipse[2];
int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
@@ -2308,21 +2611,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_elem_select_set 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;
}
@@ -2422,97 +2723,93 @@ 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)) copy_v2_v2(tface->uv[0], sima->cursor);
- if(uvedit_uv_selected(scene, efa, tface, 1)) copy_v2_v2(tface->uv[1], sima->cursor);
- if(uvedit_uv_selected(scene, efa, tface, 2)) copy_v2_v2(tface->uv[2], sima->cursor);
- if(efa->v4)
- if(uvedit_uv_selected(scene, efa, tface, 3)) copy_v2_v2(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);
+ copy_v2_v2(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;
-
+
+ /* BMESH_TODO - stop setting the index, bad juju
+ * not totally simple because 3 states and because the count is not
+ * based on the global vertex index :S - campbell */
+
/* 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)
+ BM_elem_index_set(eve, -1); /* set_dirty! */
+ em->bm->elem_index_dirty |= BM_VERT;
/* 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)) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ continue;
+ } else {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ }
+
+ change = 1;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (uvedit_uv_selected(em, scene, l) && BM_elem_index_get(l->v) == -1) {
+ BM_elem_index_set(l->v, count); /* set_dirty! */
+ count++;
+ }
}
- else
- efa->tmp.p = NULL;
}
+ em->bm->elem_index_dirty |= BM_VERT; /* set above but include for completeness since they are made dirty again */
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 (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ 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 (BM_elem_index_get(l->v) >= 0 &&
+ (!uvedit_uv_selected(em, scene, l))) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ add_v2_v2(&coords[BM_elem_index_get(l->v) * 2], luv->uv);
+ change = 1;
}
}
}
@@ -2521,46 +2818,23 @@ 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 (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ 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) && BM_elem_index_get(l->v) >= 0
+ && (users = usercount[BM_elem_index_get(l->v)])) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(luv->uv, &coords[BM_elem_index_get(l->v) * 2]);
}
}
}
@@ -2568,43 +2842,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;
}
@@ -2667,35 +2939,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;
}
@@ -2722,26 +2993,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;
}
@@ -2765,122 +3038,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;
+ 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;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ int hide = 0;
- tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
- }
+ 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*/
+ luv = 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;
}
- 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_elem_select_set(em->bm, efa, FALSE);
+ uvedit_face_deselect(scene, em, efa);
}
- 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 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_elem_select_set(em->bm, efa, FALSE);
+ }
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
+ } 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_elem_select_set(em->bm, l->v, FALSE);
+ 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;
}
@@ -2907,114 +3134,97 @@ 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;
+ /*Scene *scene = CTX_data_scene(C);*/ /*UNUSED*/
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
int facemode= sima ? sima->flag & SI_SELACTFACE : 0;
int stickymode= sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
-
+
/* 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;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_elem_select_set(em->bm, efa, TRUE);
+ 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;
+ }
}
}
}
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==NULL || (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;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ int totsel=0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ totsel += BM_elem_flag_test(l->v, BM_ELEM_SELECT);
+ }
+
+ if (!totsel) {
+ 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;
+ }
+
+ BM_elem_select_set(em->bm, efa, TRUE);
}
}
}
- }
- 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;
+ } else {
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_SELECT)==0) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
+ }
+
+ BM_elem_select_set(em->bm, efa, TRUE);
}
}
}
-
- /* 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;
+ } else if(em->selectmode == SCE_SELECT_FACE) {
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ 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;
+ }
+
+ BM_elem_select_set(em->bm, efa, TRUE);
}
}
-
- /* 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;
+ } else {
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_SELECT)==0) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
+ }
+
+ BM_elem_select_set(em->bm, efa, TRUE);
}
}
-
- /* 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);
}
-
+
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
@@ -3152,24 +3362,27 @@ static int seams_from_islands_exec(bContext *C, wmOperator *op)
UvVertMap *vmap;
Object *ob = CTX_data_edit_object(C);
Mesh *me= (Mesh*)ob->data;
- EditMesh *em;
- EditEdge *editedge;
+ BMEditMesh *em;
+ BMEdge *editedge;
float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
char mark_seams = RNA_boolean_get(op->ptr, "mark_seams");
char mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
- em = BKE_mesh_get_editmesh(me);
+ BMesh *bm;
+ BMIter iter;
- if(!EM_texFaceCheck(em)) {
- BKE_mesh_end_editmesh(ob->data, em);
+ em = me->edit_btmesh;
+ bm = em->bm;
+
+ if(!EDBM_texFaceCheck(em)) {
return OPERATOR_CANCELLED;
}
/* This code sets editvert->tmp.l to the index. This will be useful later on. */
- 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(editedge = em->edges.first; editedge; editedge = editedge->next) {
+ BM_ITER(editedge, &iter, bm, BM_EDGES_OF_MESH, NULL) {
/* flags to determine if we uv is separated from first editface match */
char separated1 = 0, separated2;
/* set to denote edge must be flagged as seam */
@@ -3179,30 +3392,30 @@ static int seams_from_islands_exec(bContext *C, wmOperator *op)
/* For use with v1coincident. v1coincident will change only if we've had commonFaces */
int commonFaces = 0;
- EditFace *efa1, *efa2;
+ BMFace *efa1, *efa2;
UvMapVert *mv1, *mvinit1, *mv2, *mvinit2, *mviter;
/* mv2cache stores the first of the list of coincident uv's for later comparison
* mv2sep holds the last separator and is copied to mv2cache when a hit is first found */
UvMapVert *mv2cache = NULL, *mv2sep = NULL;
- mvinit1 = vmap->vert[editedge->v1->tmp.l];
+ mvinit1 = vmap->vert[BM_elem_index_get(editedge->v1)];
if(mark_seams)
- editedge->seam = 0;
+ BM_elem_flag_disable(editedge, BM_ELEM_SEAM);
for(mv1 = mvinit1; mv1 && !faces_separated; mv1 = mv1->next) {
if(mv1->separate && commonFaces)
v1coincident = 0;
separated2 = 0;
- efa1 = EM_get_face_for_index(mv1->f);
- mvinit2 = vmap->vert[editedge->v2->tmp.l];
+ efa1 = EDBM_get_face_for_index(em, mv1->f);
+ mvinit2 = vmap->vert[BM_elem_index_get(editedge->v2)];
for(mv2 = mvinit2; mv2; mv2 = mv2->next) {
if(mv2->separate)
mv2sep = mv2;
- efa2 = EM_get_face_for_index(mv2->f);
+ efa2 = EDBM_get_face_for_index(em, mv2->f);
if(efa1 == efa2) {
/* if v1 is not coincident no point in comparing */
if(v1coincident) {
@@ -3237,17 +3450,16 @@ static int seams_from_islands_exec(bContext *C, wmOperator *op)
if(faces_separated) {
if(mark_seams)
- editedge->seam = 1;
+ BM_elem_flag_enable(editedge, BM_ELEM_SEAM);
if(mark_sharp)
- editedge->sharp = 1;
+ BM_elem_flag_disable(editedge, BM_ELEM_SMOOTH);
}
}
me->drawflag |= ME_DRAWSEAMS;
- EM_free_uv_vert_map(vmap);
- EM_free_index_arrays();
- BKE_mesh_end_editmesh(me, em);
+ EDBM_free_uv_vert_map(vmap);
+ EDBM_free_index_arrays(em);
DAG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
@@ -3279,16 +3491,19 @@ static int mark_seam_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
Mesh *me= (Mesh*)ob->data;
- EditMesh *em= BKE_mesh_get_editmesh(me);
- EditFace *efa;
+ BMEditMesh *em= me->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMFace *efa;
+ BMLoop *loop;
- for(efa = em->faces.first; efa; efa = efa->next) {
- MTFace *mt = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- int i, nverts = efa->v4? 4 : 3;
+ BMIter iter, liter;
- for(i = 0; i < nverts; i++)
- if(uvedit_edge_selected(scene, efa, mt, i))
- (*(&efa->e1 + i))->seam = 1;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BM_ITER(loop, &liter, bm, BM_LOOPS_OF_FACE, efa) {
+ if(uvedit_edge_selected(em, scene, loop)) {
+ BM_elem_flag_enable(loop, BM_ELEM_SEAM);
+ }
+ }
}
me->drawflag |= ME_DRAWSEAMS;
@@ -3296,8 +3511,6 @@ static int mark_seam_exec(bContext *C, wmOperator *UNUSED(op))
if(scene->toolsettings->edge_mode_live_unwrap)
ED_unwrap_lscm(scene, ob, FALSE);
- BKE_mesh_end_editmesh(me, em);
-
DAG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
@@ -3338,7 +3551,9 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_snap_selected);
WM_operatortype_append(UV_OT_align);
+
WM_operatortype_append(UV_OT_stitch);
+
WM_operatortype_append(UV_OT_seams_from_islands);
WM_operatortype_append(UV_OT_mark_seam);
WM_operatortype_append(UV_OT_weld);
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index d651a17b624..68c8669ccc7 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -743,8 +743,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 2cb4759c5ae..5adb3074314 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.h
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.h
@@ -33,6 +33,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_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index c012a23c175..70971e43409 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -50,6 +50,7 @@
#include "BKE_customdata.h"
#include "BKE_depsgraph.h"
#include "BKE_mesh.h"
+#include "BKE_tessmesh.h"
#include "ED_mesh.h"
#include "ED_uvedit.h"
@@ -116,7 +117,7 @@ typedef struct StitchState {
/* stich at midpoints or at islands */
char midpoints;
/* editmesh, cached for use in modal handler */
- EditMesh *em;
+ BMEditMesh *em;
/* element map for getting info about uv connectivity */
UvElementMap *element_map;
/* edge container */
@@ -162,21 +163,17 @@ static StitchPreviewer *_stitch_preview;
static StitchPreviewer * stitch_preview_init(void)
{
_stitch_preview = MEM_mallocN(sizeof(StitchPreviewer), "stitch_previewer");
- _stitch_preview->preview_quads = NULL;
_stitch_preview->preview_tris = NULL;
_stitch_preview->preview_stitchable = NULL;
_stitch_preview->preview_unstitchable = NULL;
- _stitch_preview->num_quads = 0;
_stitch_preview->num_tris = 0;
_stitch_preview->num_stitchable = 0;
_stitch_preview->num_unstitchable = 0;
- _stitch_preview->static_quads = NULL;
_stitch_preview->static_tris = NULL;
_stitch_preview->num_static_tris = 0;
- _stitch_preview->num_static_quads = 0;
return _stitch_preview;
}
@@ -186,10 +183,6 @@ static void stitch_preview_delete(void)
{
if(_stitch_preview)
{
- if(_stitch_preview->preview_quads){
- MEM_freeN(_stitch_preview->preview_quads);
- _stitch_preview->preview_quads = NULL;
- }
if(_stitch_preview->preview_tris){
MEM_freeN(_stitch_preview->preview_tris);
_stitch_preview->preview_tris = NULL;
@@ -202,10 +195,6 @@ static void stitch_preview_delete(void)
MEM_freeN(_stitch_preview->preview_unstitchable);
_stitch_preview->preview_unstitchable = NULL;
}
- if(_stitch_preview->static_quads){
- MEM_freeN(_stitch_preview->static_quads);
- _stitch_preview->static_quads = NULL;
- }
if(_stitch_preview->static_tris){
MEM_freeN(_stitch_preview->static_tris);
_stitch_preview->static_tris = NULL;
@@ -276,11 +265,17 @@ static int stitch_check_uvs_stitchable(UvElement *element, UvElement *element_it
do_limit = state->use_limit;
if(do_limit){
- MTFace *mtface_orig = CustomData_em_get(&state->em->fdata, element->face->data, CD_MTFACE);
- MTFace *mtface_iter = CustomData_em_get(&state->em->fdata, element_iter->face->data, CD_MTFACE);
+ MLoopUV *luv_orig, *luv_iter;
+ BMLoop *l_orig, *l_iter;
+
+
+ l_orig = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex);
+ luv_orig = CustomData_bmesh_get(&state->em->bm->ldata, l_orig->head.data, CD_MLOOPUV);
+ l_iter = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element_iter->tfindex);
+ luv_iter = CustomData_bmesh_get(&state->em->bm->ldata, l_iter->head.data, CD_MLOOPUV);
- if(fabs(mtface_orig->uv[element->tfindex][0] - mtface_iter->uv[element_iter->tfindex][0]) < limit
- && fabs(mtface_orig->uv[element->tfindex][1] - mtface_iter->uv[element_iter->tfindex][1]) < limit){
+ if(fabs(luv_orig->uv[0] - luv_iter->uv[0]) < limit
+ && fabs(luv_orig->uv[1] - luv_iter->uv[1]) < limit){
return 1;
}else
return 0;
@@ -301,8 +296,7 @@ static int stitch_check_uvs_state_stitchable(UvElement *element, UvElement *elem
/* calculate snapping for islands */
static void stitch_calculate_island_snapping(StitchState *state, StitchPreviewer *preview, IslandStitchData *island_stitch_data, int final){
int i;
- EditFace *efa;
- MTFace *mt;
+ BMFace *efa;
UvElement *element;
for(i = 0; i < state->element_map->totalIslands; i++){
@@ -322,15 +316,22 @@ static void stitch_calculate_island_snapping(StitchState *state, StitchPreviewer
for(j = 0; j < numOfIslandUVs; j++, element++){
/* stitchable uvs have already been processed, don't process */
if(!(element->flag & STITCH_PROCESSED)){
+ MLoopUV *luv;
+ BMLoop *l;
+
+ l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex);
+ luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+
efa = element->face;
- mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+
if(final){
- stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint, mt->uv[element->tfindex]);
+ stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint, luv->uv);
- mt->uv[element->tfindex][0] += island_stitch_data[i].translation[0];
- mt->uv[element->tfindex][1] += island_stitch_data[i].translation[1];
+ luv->uv[0] += island_stitch_data[i].translation[0];
+ luv->uv[1] += island_stitch_data[i].translation[1];
}
+ /* BMESH_TODO preview
else if(efa->tmp.l != STITCH_NO_PREVIEW){
if(efa->v4){
@@ -346,7 +347,8 @@ static void stitch_calculate_island_snapping(StitchState *state, StitchPreviewer
preview->preview_tris[efa->tmp.l + 2*element->tfindex] += island_stitch_data[i].translation[0];
preview->preview_tris[efa->tmp.l + 2*element->tfindex + 1] += island_stitch_data[i].translation[1];
}
- }
+ }*/
+ (void)preview;
}
/* cleanup */
element->flag &= STITCH_SELECTED;
@@ -360,30 +362,28 @@ static void stitch_calculate_island_snapping(StitchState *state, StitchPreviewer
static void stitch_island_calculate_edge_rotation(UvEdge *edge, StitchState *state, UVVertAverage *uv_average, unsigned int *uvfinal_map, IslandStitchData *island_stitch_data)
{
UvElement *element1, *element2;
- EditFace *efa1;
- EditFace *efa2;
- MTFace *mt1;
- MTFace *mt2;
float uv1[2], uv2[2];
float edgecos, edgesin;
int index1, index2;
float rotation;
+ MLoopUV *luv1, *luv2;
+ BMLoop *l1, *l2;
element1 = state->uvs[edge->uv1];
element2 = state->uvs[edge->uv2];
- efa1 = element1->face;
- mt1 = CustomData_em_get(&state->em->fdata, efa1->data, CD_MTFACE);
- efa2 = element2->face;
- mt2 = CustomData_em_get(&state->em->fdata, efa2->data, CD_MTFACE);
+ l1 = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element1->face, element1->tfindex);
+ luv1 = CustomData_bmesh_get(&state->em->bm->ldata, l1->head.data, CD_MLOOPUV);
+ l2 = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element2->face, element2->tfindex);
+ luv2 = CustomData_bmesh_get(&state->em->bm->ldata, l2->head.data, CD_MLOOPUV);
index1 = uvfinal_map[element1 - state->element_map->buf];
index2 = uvfinal_map[element2 - state->element_map->buf];
/* the idea here is to take the directions of the edges and find the rotation between final and initial
* direction. This, using inner and outer vector products, gives the angle. Directions are differences so... */
- uv1[0] = mt2->uv[element2->tfindex][0] - mt1->uv[element1->tfindex][0];
- uv1[1] = mt2->uv[element2->tfindex][1] - mt1->uv[element1->tfindex][1];
+ uv1[0] = luv2->uv[0] - luv1->uv[0];
+ uv1[1] = luv2->uv[1] - luv1->uv[1];
uv2[0] = uv_average[index2].uv[0] - uv_average[index1].uv[0];
uv2[1] = uv_average[index2].uv[1] - uv_average[index1].uv[1];
@@ -407,11 +407,14 @@ static void stitch_island_calculate_vert_rotation(UvElement *element, StitchStat
int index;
UvElement *element_iter;
float rotation = 0;
+ BMLoop *l;
if(element->island == state->static_island && !state->midpoints)
return;
- index = (*(&element->face->v1 + element->tfindex))->tmp.l;
+ l = BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, element->face, element->tfindex);
+
+ index = BM_elem_index_get(l->v);
element_iter = state->element_map->vert[index];
@@ -444,7 +447,7 @@ static void stitch_state_delete(StitchState *stitch_state)
{
if(stitch_state){
if(stitch_state->element_map){
- EM_free_uv_element_map(stitch_state->element_map);
+ EDBM_free_uv_element_map(stitch_state->element_map);
}
if(stitch_state->uvs){
MEM_freeN(stitch_state->uvs);
@@ -477,8 +480,11 @@ static void stitch_state_delete(StitchState *stitch_state)
static void determine_uv_stitchability(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data){
int vert_index;
UvElement *element_iter;
+ BMLoop *l;
+
+ l = BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, element->face, element->tfindex);
- vert_index = (*(&element->face->v1 + element->tfindex))->tmp.l;
+ vert_index = BM_elem_index_get(l->v);
element_iter = state->element_map->vert[vert_index];
for(; element_iter; element_iter = element_iter->next){
@@ -497,24 +503,23 @@ static void determine_uv_stitchability(UvElement *element, StitchState *state, I
/* set preview buffer position of UV face in editface->tmp.l */
-static void stitch_set_face_preview_buffer_position(EditFace *efa, StitchPreviewer *preview)
+static void stitch_set_face_preview_buffer_position(BMFace *efa, StitchPreviewer *preview, unsigned int *preview_position)
{
- if(efa->tmp.l == STITCH_NO_PREVIEW)
+ int index = BM_elem_index_get(efa);
+
+ if(preview_position[index] == STITCH_NO_PREVIEW)
{
- if(efa->v4)
- {
- efa->tmp.l = preview->num_quads*8;
- preview->num_quads++;
- } else {
- efa->tmp.l = preview->num_tris*6;
- preview->num_tris++;
- }
+ preview_position[index] = preview->num_tris*6;
+
+ /* BMESH_TODO, count per face triangles */
+ //preview->num_tris += 4;
}
}
/* setup face preview for all coincident uvs and their faces */
-static void stitch_setup_face_preview_for_uv_group(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data){
+static void stitch_setup_face_preview_for_uv_group(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
+ unsigned int *preview_position){
StitchPreviewer *preview = uv_get_stitch_previewer();
/* static island does not change so returning immediately */
@@ -526,19 +531,26 @@ static void stitch_setup_face_preview_for_uv_group(UvElement *element, StitchSta
}
do{
- stitch_set_face_preview_buffer_position(element->face, preview);
+ stitch_set_face_preview_buffer_position(element->face, preview, preview_position);
element = element->next;
}while(element && !element->separate);
}
/* checks if uvs are indeed stitchable and registers so that they can be shown in preview */
-static void stitch_validate_stichability(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data){
+static void stitch_validate_stichability (UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
+ unsigned int *preview_position){
UvElement *element_iter;
StitchPreviewer *preview;
+ int vert_index;
+ BMLoop *l;
+
+ l = BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, element->face, element->tfindex);
+
+ vert_index = BM_elem_index_get(l->v);
preview = uv_get_stitch_previewer();
- element_iter = state->element_map->vert[(*(&element->face->v1 + element->tfindex))->tmp.l];
+ element_iter = state->element_map->vert[vert_index];
for(; element_iter; element_iter = element_iter->next){
if(element_iter->separate){
@@ -548,7 +560,7 @@ static void stitch_validate_stichability(UvElement *element, StitchState *state,
if((element_iter->island == state->static_island) || (element->island == state->static_island)){
element->flag |= STITCH_STITCHABLE;
preview->num_stitchable++;
- stitch_setup_face_preview_for_uv_group(element, state, island_stitch_data);
+ stitch_setup_face_preview_for_uv_group(element, state, island_stitch_data, preview_position);
return;
}
}
@@ -568,21 +580,25 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
StitchPreviewer *preview;
IslandStitchData *island_stitch_data = NULL;
int previous_island = state->static_island;
- EditFace *efa;
- EditVert *ev;
+ BMFace *efa;
+ BMIter iter;
UVVertAverage *final_position;
char stitch_midpoints = state->midpoints;
/* used to map uv indices to uvaverage indices for selection */
unsigned int *uvfinal_map;
+ /* per face preview position in preview buffer */
+ unsigned int *preview_position;
/* cleanup previous preview */
stitch_preview_delete();
preview = stitch_preview_init();
if(preview == NULL)
return 0;
+
+ preview_position = MEM_mallocN(state->em->bm->totface*sizeof(*preview_position), "stitch_face_preview_position");
/* each face holds its position in the preview buffer in tmp. -1 is uninitialized */
- for(efa = state->em->faces.first; efa; efa = efa->next){
- efa->tmp.l = STITCH_NO_PREVIEW;
+ for(i = 0; i < state->em->bm->totface; i++){
+ preview_position[i] = STITCH_NO_PREVIEW;
}
island_stitch_data = MEM_callocN(sizeof(*island_stitch_data)*state->element_map->totalIslands, "stitch_island_data");
@@ -590,10 +606,8 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
return 0;
}
- /* store indices to editVerts. */
- for(ev = state->em->verts.first, i = 0; ev; ev = ev->next, i++){
- ev->tmp.l = i;
- }
+ /* store indices to editVerts and Faces. May be unneeded but ensuring anyway */
+ BM_mesh_elem_index_ensure(state->em->bm, BM_VERT | BM_FACE);
/*****************************************
* First determine stitchability of uvs *
@@ -618,7 +632,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
UvElement *element = state->selection_stack[i];
if(element->flag & STITCH_STITCHABLE_CANDIDATE){
element->flag &= ~STITCH_STITCHABLE_CANDIDATE;
- stitch_validate_stichability(element, state, island_stitch_data);
+ stitch_validate_stichability(element, state, island_stitch_data, preview_position);
}else{
/* add to preview for unstitchable */
preview->num_unstitchable++;
@@ -636,7 +650,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
element = &state->element_map->buf[state->element_map->islandIndices[i]];
for(j = 0; j < numOfIslandUVs; j++, element++){
- stitch_set_face_preview_buffer_position(element->face, preview);
+ stitch_set_face_preview_buffer_position(element->face, preview, preview_position);
}
}
}
@@ -646,47 +660,42 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
* Setup the preview buffers and fill them with the appropriate data *
*********************************************************************/
if(!final){
- unsigned int tricount = 0, quadcount = 0;
+ BMLoop *l;
+ MLoopUV *luv;
+ unsigned int tricount = 0;
int stitchBufferIndex = 0, unstitchBufferIndex = 0;
/* initialize the preview buffers */
- preview->preview_quads = (float *)MEM_mallocN(preview->num_quads*sizeof(float)*8, "quad_uv_stitch_prev");
preview->preview_tris = (float *)MEM_mallocN(preview->num_tris*sizeof(float)*6, "tri_uv_stitch_prev");
preview->preview_stitchable = (float *)MEM_mallocN(preview->num_stitchable*sizeof(float)*2, "stitch_preview_stichable_data");
preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable*sizeof(float)*2, "stitch_preview_unstichable_data");
- preview->static_quads = (float *)MEM_mallocN(state->quads_per_island[state->static_island]*sizeof(float)*8, "static_island_preview_quads");
preview->static_tris = (float *)MEM_mallocN(state->tris_per_island[state->static_island]*sizeof(float)*6, "static_island_preview_tris");
- preview->num_static_quads = state->quads_per_island[state->static_island];
preview->num_static_tris = state->tris_per_island[state->static_island];
/* will cause cancel and freeing of all data structures so OK */
- if(!preview->preview_quads || !preview->preview_tris || !preview->preview_stitchable || !preview->preview_unstitchable){
+ if(!preview->preview_tris || !preview->preview_stitchable || !preview->preview_unstitchable){
return 0;
}
/* copy data from MTFaces to the preview display buffers */
- for(efa = state->em->faces.first; efa; efa = efa->next){
- MTFace *mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+ BM_ITER(efa, &iter, state->em->bm, BM_FACES_OF_MESH, NULL) {
+ /* just to test if face was added for processing. uvs of inselected vertices will return NULL */
UvElement *element = ED_get_uv_element(state->element_map, efa, 0);
if(element){
- if(efa->tmp.l != STITCH_NO_PREVIEW){
- if(efa->v4) {
- memcpy(preview->preview_quads+efa->tmp.l, &mt->uv[0][0], 8*sizeof(float));
- } else {
- memcpy(preview->preview_tris+efa->tmp.l, &mt->uv[0][0], 6*sizeof(float));
- }
+ int index = BM_elem_index_get(efa);
+
+ if(preview_position[index] != STITCH_NO_PREVIEW){
+ /* BMESH_TODO preview */
+ //memcpy(preview->preview_tris+efa->tmp.l, &mt->uv[0][0], 6*sizeof(float));
}
if(element->island == state->static_island){
- if(efa->v4) {
- memcpy(preview->static_quads + quadcount*8, &mt->uv[0][0], 8*sizeof(float));
- quadcount++;
- } else {
- memcpy(preview->static_tris + tricount*6, &mt->uv[0][0], 6*sizeof(float));
- tricount++;
- }
+ /* BMESH_TODO preview */
+ //memcpy(preview->static_tris + tricount*6, &mt->uv[0][0], 6*sizeof(float));
+ //tricount++;
+ (void)tricount;
}
}
}
@@ -695,21 +704,18 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
for(i = 0; i < state->total_separate_uvs; i++){
UvElement *element = (UvElement *)state->uvs[i];
if(element->flag & STITCH_STITCHABLE){
- MTFace *mt;
- efa = element->face;
- mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+ l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex);
+ luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex*2], luv->uv);
- preview->preview_stitchable[stitchBufferIndex*2] = mt->uv[element->tfindex][0];
- preview->preview_stitchable[stitchBufferIndex*2 + 1] = mt->uv[element->tfindex][1];
stitchBufferIndex++;
}
else if(element->flag & STITCH_SELECTED){
- MTFace *mt;
- efa = element->face;
- mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+ l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex);
+ luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
- preview->preview_unstitchable[unstitchBufferIndex*2] = mt->uv[element->tfindex][0];
- preview->preview_unstitchable[unstitchBufferIndex*2 + 1] = mt->uv[element->tfindex][1];
+ copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex*2], luv->uv);
unstitchBufferIndex++;
}
}
@@ -726,39 +732,37 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
for(i = 0; i < state->selection_size; i++){
UvElement *element = state->selection_stack[i];
if(element->flag & STITCH_STITCHABLE){
- MTFace *mt;
-
+ BMLoop *l;
+ MLoopUV *luv;
UvElement *element_iter;
- uvfinal_map[element - state->element_map->buf] = i;
+ l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex);
+ luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+
- efa = element->face;
- mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+ uvfinal_map[element - state->element_map->buf] = i;
- final_position[i].uv[0] = mt->uv[element->tfindex][0];
- final_position[i].uv[1] = mt->uv[element->tfindex][1];
+ copy_v2_v2(final_position[i].uv, luv->uv);
final_position[i].count = 1;
if(state->snap_islands && element->island == state->static_island && !stitch_midpoints)
continue;
- element_iter = state->element_map->vert[(*(&element->face->v1 + element->tfindex))->tmp.l];
+ element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
for(;element_iter; element_iter = element_iter->next){
if(element_iter->separate){
if(stitch_check_uvs_state_stitchable(element, element_iter, state)){
- efa = element_iter->face;
- mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+ l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element_iter->face, element_iter->tfindex);
+ luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
if(stitch_midpoints){
- final_position[i].uv[0] += mt->uv[element_iter->tfindex][0];
- final_position[i].uv[1] += mt->uv[element_iter->tfindex][1];
+ add_v2_v2(final_position[i].uv, luv->uv);
final_position[i].count++;
}else if(element_iter->island == state->static_island){
/* if multiple uvs on the static island exist,
* last checked remains. to disambiguate we need to limit or use
* edge stitch */
- final_position[i].uv[0] = mt->uv[element_iter->tfindex][0];
- final_position[i].uv[1] = mt->uv[element_iter->tfindex][1];
+ copy_v2_v2(final_position[i].uv, luv->uv);
}
}
}
@@ -775,16 +779,18 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
for(i = 0; i < state->selection_size; i++){
UvElement *element = state->selection_stack[i];
if(element->flag & STITCH_STITCHABLE){
- MTFace *mt;
- efa = element->face;
- mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+ BMLoop *l;
+ MLoopUV *luv;
+
+ l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex);
+ luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
/* accumulate each islands' translation from stitchable elements. it is important to do here
* because in final pass MTFaces get modified and result is zero. */
- island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - mt->uv[element->tfindex][0];
- island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - mt->uv[element->tfindex][1];
- island_stitch_data[element->island].medianPoint[0] += mt->uv[element->tfindex][0];
- island_stitch_data[element->island].medianPoint[1] += mt->uv[element->tfindex][1];
+ island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - luv->uv[0];
+ island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - luv->uv[1];
+ island_stitch_data[element->island].medianPoint[0] += luv->uv[0];
+ island_stitch_data[element->island].medianPoint[1] += luv->uv[1];
island_stitch_data[element->island].numOfElements++;
}
}
@@ -816,26 +822,23 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
UvElement *element_iter = element;
/* propagate to coincident uvs */
do{
- MTFace *mt;
+ BMLoop *l;
+ MLoopUV *luv;
- efa = element_iter->face;
- mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+ l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element_iter->face, element_iter->tfindex);
+ luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
element_iter->flag |= STITCH_PROCESSED;
/* either flush to preview or to the MTFace, if final */
if(final){
- mt->uv[element_iter->tfindex][0] = final_position[i].uv[0];
- mt->uv[element_iter->tfindex][1] = final_position[i].uv[1];
-
- uvedit_uv_select(scene, efa, mt, element_iter->tfindex);
- }else if(efa->tmp.l != STITCH_NO_PREVIEW){
- if(efa->v4){
- *(preview->preview_quads+efa->tmp.l + element_iter->tfindex*2) = final_position[i].uv[0];
- *(preview->preview_quads+efa->tmp.l + element_iter->tfindex*2 + 1) = final_position[i].uv[1];
- }else{
- *(preview->preview_tris+efa->tmp.l + element_iter->tfindex*2) = final_position[i].uv[0];
- *(preview->preview_tris+efa->tmp.l + element_iter->tfindex*2 + 1) = final_position[i].uv[1];
- }
+ copy_v2_v2(luv->uv, final_position[i].uv);
+
+ uvedit_uv_select(state->em, scene, l);
+ }else if(preview_position[BM_elem_index_get(element_iter->face)] != STITCH_NO_PREVIEW){
+ /* BMESH_TODO: preview for stitch
+ *(preview->preview_tris+efa->tmp.l + element_iter->tfindex*2) = final_position[i].uv[0];
+ *(preview->preview_tris+efa->tmp.l + element_iter->tfindex*2 + 1) = final_position[i].uv[1];
+ */
}
/* end of calculations, keep only the selection flag */
@@ -856,6 +859,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
MEM_freeN(final_position);
MEM_freeN(uvfinal_map);
MEM_freeN(island_stitch_data);
+ MEM_freeN(preview_position);
return 1;
}
@@ -880,13 +884,15 @@ static int uv_edge_compare(const void *a, const void *b){
/* Select all common uvs */
-static void stitch_select_uv(UvElement *element, StitchState *stitch_state, int always_select)
+static void stitch_select_uv(UvElement *element, StitchState *state, int always_select)
{
- /* This works due to setting of tmp in find nearest uv vert */
+ BMLoop *l;
UvElement *element_iter;
- UvElement **selection_stack = stitch_state->selection_stack;
+ UvElement **selection_stack = state->selection_stack;
+
+ l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex);
- element_iter = stitch_state->element_map->vert[(*(&element->face->v1 + element->tfindex))->tmp.l];
+ element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
/* first deselect all common uvs */
for(; element_iter; element_iter = element_iter->next){
if(element_iter->separate){
@@ -897,26 +903,29 @@ static void stitch_select_uv(UvElement *element, StitchState *stitch_state, int
continue;
element_iter->flag &= ~STITCH_SELECTED;
- for(i = 0; i < stitch_state->selection_size; i++){
+ for(i = 0; i < state->selection_size; i++){
if(selection_stack[i] == element_iter){
- (stitch_state->selection_size)--;
- selection_stack[i] = selection_stack[stitch_state->selection_size];
+ (state->selection_size)--;
+ selection_stack[i] = selection_stack[state->selection_size];
break;
}
}
}else{
element_iter->flag |= STITCH_SELECTED;
- selection_stack[(stitch_state->selection_size)++] = element_iter;
+ selection_stack[state->selection_size++] = element_iter;
}
}
}
}
-static void stitch_calculate_edge_normal(EditMesh *em, UvEdge *edge, float *normal)
+static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal)
{
+ /* BMESH_TODO need a way to disambiguate between normals for bmesh. */
+#if 0
UvElement *element = edge->element;
- EditFace *efa = element->face;
+ BMFace *efa = element->face;
MTFace *mt = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
int nverts = efa->v4?4 : 3;
int index = (element->tfindex + 2)%nverts;
float tangent[2], internal[2];
@@ -924,17 +933,20 @@ static void stitch_calculate_edge_normal(EditMesh *em, UvEdge *edge, float *norm
sub_v2_v2v2(tangent, mt->uv[(element->tfindex + 1)%nverts], mt->uv[element->tfindex]);
sub_v2_v2v2(internal, mt->uv[index], mt->uv[element->tfindex]);
- /* choose one of the normals */
normal[0] = tangent[1];
normal[1] = -tangent[0];
- /* if normal points inside the face, invert */
if(dot_v2v2(normal, internal) > 0){
normal[0] = -tangent[1];
normal[1] = tangent[0];
}
normalize_v2(normal);
+#else
+ (void)em;
+ (void)edge;
+ (void)normal;
+#endif
}
static int stitch_init(bContext *C, wmOperator *op)
@@ -947,8 +959,10 @@ static int stitch_init(bContext *C, wmOperator *op)
/* maps uvelements to their first coincident uv */
int *map;
int counter = 0, i;
- EditFace *efa;
- EditMesh *em;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ BMEditMesh *em;
GHashIterator* ghi;
UvEdge *all_edges;
StitchState *state = MEM_mallocN(sizeof(StitchState), "stitch state");
@@ -965,15 +979,15 @@ static int stitch_init(bContext *C, wmOperator *op)
/* initialize state */
state->use_limit = RNA_boolean_get(op->ptr, "use_limit");
state->limit_dist = RNA_float_get(op->ptr, "limit");
- state->em = em = BKE_mesh_get_editmesh((Mesh*)obedit->data);
+ state->em = em = ((Mesh *)obedit->data)->edit_btmesh;
state->snap_islands = RNA_boolean_get(op->ptr, "snap_islands");
state->static_island = RNA_int_get(op->ptr, "static_island");
state->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap");
/* in uv synch selection, all uv's are visible */
if(ts->uv_flag & UV_SYNC_SELECTION){
- state->element_map = EM_make_uv_element_map(state->em, 0, 1);
+ state->element_map = EDBM_make_uv_element_map(state->em, 0, 1);
}else{
- state->element_map = EM_make_uv_element_map(state->em, 1, 1);
+ state->element_map = EDBM_make_uv_element_map(state->em, 1, 1);
}
if(!state->element_map){
stitch_state_delete(state);
@@ -1013,7 +1027,7 @@ static int stitch_init(bContext *C, wmOperator *op)
/* So that we can use this as index for the UvElements */
counter = -1;
/* initialize the unique UVs and map */
- for(i = 0; i < state->em->totvert; i++){
+ for(i = 0; i < em->bm->totvert; i++){
UvElement *element = state->element_map->vert[i];
for(; element; element = element->next){
if(element->separate){
@@ -1025,42 +1039,48 @@ static int stitch_init(bContext *C, wmOperator *op)
}
}
+ counter = 0;
/* Now, on to generate our uv connectivity data */
- for(efa = state->em->faces.first, counter = 0; efa; efa = efa->next){
- if((ts->uv_flag & UV_SYNC_SELECTION) || (!efa->h && efa->f & SELECT)){
- int nverts = efa->v4 ? 4 : 3;
-
- for(i = 0; i < nverts; i++){
- UvElement *element = ED_get_uv_element(state->element_map, efa, i);
- int offset1, itmp1 = element - state->element_map->buf;
- int offset2, itmp2 = ED_get_uv_element(state->element_map, efa, (i+1)%nverts) - state->element_map->buf;
-
- offset1 = map[itmp1];
- offset2 = map[itmp2];
-
- all_edges[counter].flag = 0;
- all_edges[counter].element = element;
- /* using an order policy, sort uvs according to address space. This avoids
- * Having two different UvEdges with the same uvs on different positions */
- if(offset1 < offset2){
- all_edges[counter].uv1 = offset1;
- all_edges[counter].uv2 = offset2;
- }
- else{
- all_edges[counter].uv1 = offset2;
- all_edges[counter].uv2 = offset1;
- }
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ int nverts;
+
+ if (!(ts->uv_flag & UV_SYNC_SELECTION) && ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT)))
+ continue;
+
+ nverts = efa->len;
+ i = 0;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ UvElement *element = ED_get_uv_element(state->element_map, efa, i);
+ int offset1, itmp1 = element - state->element_map->buf;
+ int offset2, itmp2 = ED_get_uv_element(state->element_map, efa, (i+1)%nverts) - state->element_map->buf;
+
+ offset1 = map[itmp1];
+ offset2 = map[itmp2];
+
+ all_edges[counter].flag = 0;
+ all_edges[counter].element = element;
+ /* using an order policy, sort uvs according to address space. This avoids
+ * Having two different UvEdges with the same uvs on different positions */
+ if(offset1 < offset2){
+ all_edges[counter].uv1 = offset1;
+ all_edges[counter].uv2 = offset2;
+ }
+ else{
+ all_edges[counter].uv1 = offset2;
+ all_edges[counter].uv2 = offset1;
+ }
- if(BLI_ghash_haskey(edgeHash, &all_edges[counter])){
- char *flag = BLI_ghash_lookup(edgeHash, &all_edges[counter]);
- *flag = 0;
- }
- else{
- BLI_ghash_insert(edgeHash, &all_edges[counter], &(all_edges[counter].flag));
- all_edges[counter].flag = STITCH_BOUNDARY;
- }
- counter++;
+ if(BLI_ghash_haskey(edgeHash, &all_edges[counter])){
+ char *flag = BLI_ghash_lookup(edgeHash, &all_edges[counter]);
+ *flag = 0;
}
+ else{
+ BLI_ghash_insert(edgeHash, &all_edges[counter], &(all_edges[counter].flag));
+ all_edges[counter].flag = STITCH_BOUNDARY;
+ }
+ counter++;
+ i++;
}
}
@@ -1126,34 +1146,30 @@ static int stitch_init(bContext *C, wmOperator *op)
int faceIndex, elementIndex;
UvElement *element;
- EM_init_index_arrays(em, 0, 0, 1);
-
+ EDBM_init_index_arrays(em, 0, 0, 1);
- RNA_BEGIN(op->ptr, itemptr, "selection") {
- faceIndex = RNA_int_get(&itemptr, "face_index");
- elementIndex = RNA_int_get(&itemptr, "element_index");
- efa = EM_get_face_for_index(faceIndex);
- element = ED_get_uv_element(state->element_map, efa, elementIndex);
- stitch_select_uv(element, state, 1);
- }
- RNA_END;
+ RNA_BEGIN(op->ptr, itemptr, "selection") {
+ faceIndex = RNA_int_get(&itemptr, "face_index");
+ elementIndex = RNA_int_get(&itemptr, "element_index");
+ efa = EDBM_get_face_for_index(em, faceIndex);
+ element = ED_get_uv_element(state->element_map, efa, elementIndex);
+ stitch_select_uv(element, state, 1);
+ }
+ RNA_END;
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
/* Clear the selection */
RNA_collection_clear(op->ptr, "selection");
} else {
- for(efa = state->em->faces.first ; efa; efa = efa->next){
- int numOfVerts;
- MTFace *mt;
- mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
- numOfVerts = efa->v4 ? 4 : 3;
-
- for(i = 0; i < numOfVerts; i++){
- if(uvedit_uv_selected(scene, efa, mt, i)){
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ i = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if(uvedit_uv_selected(em, scene, l)){
UvElement *element = ED_get_uv_element(state->element_map, efa, i);
stitch_select_uv(element, state, 1);
}
+ i++;
}
}
}
@@ -1169,16 +1185,12 @@ static int stitch_init(bContext *C, wmOperator *op)
state->tris_per_island[i] = 0;
}
- for(efa = state->em->faces.first; efa; efa = efa->next){
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
UvElement *element = ED_get_uv_element(state->element_map, efa, 0);
if(element){
- if(efa->v4){
- state->quads_per_island[element->island]++;
- }
- else {
- state->tris_per_island[element->island]++;
- }
+ /* BMESH_TODO preview active island */
+ //state->tris_per_island[element->island]++;
}
}
@@ -1217,7 +1229,6 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished)
stitch_state = (StitchState *)op->customdata;
if(finished){
- EditFace *efa;
int i;
RNA_float_set(op->ptr, "limit", stitch_state->limit_dist);
@@ -1226,10 +1237,6 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished)
RNA_int_set(op->ptr, "static_island", stitch_state->static_island);
RNA_boolean_set(op->ptr, "midpoint_snap", stitch_state->midpoints);
- for(i = 0, efa = stitch_state->em->faces.first; efa; efa = efa->next, i++){
- efa->tmp.l = i;
- }
-
/* Store selection for re-execution of stitch */
for(i = 0; i < stitch_state->selection_size; i++){
PointerRNA itemptr;
@@ -1237,7 +1244,7 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished)
RNA_collection_add(op->ptr, "selection", &itemptr);
- RNA_int_set(&itemptr, "face_index", element->face->tmp.l);
+ RNA_int_set(&itemptr, "face_index", BM_elem_index_get(element->face));
RNA_int_set(&itemptr, "element_index", element->tfindex);
}
@@ -1250,7 +1257,6 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished)
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, stitch_state->em);
stitch_state_delete(stitch_state);
op->customdata = NULL;
@@ -1297,7 +1303,7 @@ static void stitch_select(bContext *C, Scene *scene, wmEvent *event, StitchState
* you can do stuff like deselect the opposite stitchable vertex and the initial still gets deselected */
/* This works due to setting of tmp in find nearest uv vert */
- UvElement *element = ED_get_uv_element(stitch_state->element_map, hit.efa, hit.uv);
+ UvElement *element = ED_get_uv_element(stitch_state->element_map, hit.efa, hit.lindex);
stitch_select_uv(element, stitch_state, 0);
}
@@ -1467,5 +1473,3 @@ void UV_OT_stitch(wmOperatorType *ot)
/* Selection should not be editable or viewed in toolbar */
RNA_def_property_flag(prop, PROP_HIDDEN);
}
-
-
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index f3569639454..6d15d023fbe 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -42,11 +42,13 @@
#include "DNA_scene_types.h"
#include "DNA_modifier_types.h"
+#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_edgehash.h"
#include "BLI_editVert.h"
#include "BLI_uvproject.h"
#include "BLI_utildefines.h"
+#include "BLI_rand.h"
#include "BLI_string.h"
#include "BKE_cdderivedmesh.h"
@@ -58,6 +60,14 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_report.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"
@@ -80,9 +90,9 @@
static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit)
{
Main *bmain= CTX_data_main(C);
- 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;
@@ -90,15 +100,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_data_layer_add(em->bm, &em->bm->pdata, CD_MTEXPOLY);
+ BM_data_layer_add(em->bm, &em->bm->ldata, CD_MLOOPUV);
+ }
+
if(!ED_uvedit_test(obedit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
return 0;
}
@@ -128,70 +138,69 @@ static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit)
ED_uvedit_assign_image(bmain, 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 int uvedit_have_selection(Scene *scene, EditMesh *em, short implicit)
+static int uvedit_have_selection(Scene *scene, BMEditMesh *em, short implicit)
{
- EditFace *efa;
- MTFace *tf;
-
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
/* verify if we have any selected uv's before unwrapping,
so we can cancel the operator early */
- for(efa= em->faces.first; efa; efa= efa->next) {
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
- if(efa->h)
+ if(BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
continue;
}
- else if((efa->h) || ((efa->f & SELECT)==0))
+ else if(BM_elem_flag_test(efa, BM_ELEM_HIDDEN) || !BM_elem_flag_test(efa, BM_ELEM_SELECT))
continue;
-
- tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
- if(!tf)
- return 1; /* default selected if doesn't exists */
+
+ 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)
+ return 1;
+
+ if (uvedit_uv_selected(em, scene, l))
+ break;
+ }
- 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)) )
- ) {
+ if (implicit && !l)
continue;
- }
-
+
return 1;
}
return 0;
}
-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;
- int a;
+ BMFace *efa;
+ BMLoop *l;
+ BMEdge *eed;
+ BMIter iter, liter;
+ MTexPoly *tf;
handle = param_construct_begin();
if(correct_aspect) {
- efa = EM_get_actFace(em, 1);
+ efa = BM_active_face_get(em->bm, TRUE);
if(efa) {
float aspx, aspy;
- 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);
@@ -201,71 +210,108 @@ 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;
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
- 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;
-
- if((efa->h) || (sel && (efa->f & SELECT)==0))
- continue;
+ int lsel;
- 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)) )
- ) {
+ if((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || (sel && BM_elem_flag_test(efa, BM_ELEM_SELECT)==0))
continue;
+
+ /* tf= (MTexPoly *)CustomData_em_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
+ 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!*/
+ BLI_begin_edgefill();
+
+ firstv = lastv = NULL;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ int i;
+
+ v = BLI_addfillvert(l->v->co);
+
+ /*add small random offset*/
+ for (i=0; i<3; i++) {
+ v->co[i] += (BLI_drand()-0.5f)*FLT_EPSILON*50;
+ }
+
+ v->tmp.p = l;
+
+ if (lastv) {
+ BLI_addfilledge(lastv, v);
+ }
+
+ lastv = v;
+ if (!firstv)
+ firstv = v;
+ }
+
+ BLI_addfilledge(firstv, v);
+
+ /*mode 2 enables faster handling of tri/quads*/
+ BLI_edgefill(2);
+ 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)BM_elem_index_get(ls[0]->v);
+ vkeys[1] = (ParamKey)BM_elem_index_get(ls[1]->v);
+ vkeys[2] = (ParamKey)BM_elem_index_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);
}
- else
- nverts = 3;
- param_face_add(handle, key, nverts, 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_elem_flag_test(eed, BM_ELEM_SEAM)) {
ParamKey vkeys[2];
- vkeys[0] = (ParamKey)eed->v1->tmp.l;
- vkeys[1] = (ParamKey)eed->v2->tmp.l;
+ vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
+ vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2);
param_edge_set_seam(handle, vkeys);
}
}
@@ -277,9 +323,11 @@ static ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short imp
}
-static void texface_from_original_index(EditFace *editFace, MTFace *texFace, int index, float **uv, ParamBool *pin, ParamBool *select, Scene *scene)
+static void texface_from_original_index(BMFace *efa, int index, float **uv, ParamBool *pin, ParamBool *select, Scene *scene, BMEditMesh *em)
{
- int i, nverts = (editFace->v4)? 4: 3;
+ BMLoop *l;
+ BMIter liter;
+ MLoopUV *luv;
*uv = NULL;
*pin = 0;
@@ -288,29 +336,28 @@ static void texface_from_original_index(EditFace *editFace, MTFace *texFace, int
if(index == ORIGINDEX_NONE)
return;
- for(i = 0; i < nverts; i++) {
- if((*(&editFace->v1 + i))->tmp.t == index) {
- *uv = texFace->uv[i];
- *pin = ((texFace->unwrap & TF_PIN_MASK(i)) != 0);
- *select = (uvedit_uv_selected(scene, editFace, texFace, i) != 0);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ if(BM_elem_index_get(l->v) == index) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ *uv = luv->uv;
+ *pin = (luv->flag & MLOOPUV_PINNED)? 1 : 0;
+ *select = (uvedit_uv_selected(em, scene, l) != 0);
}
}
}
-/* unwrap handle initialization for subsurf aware-unwrapper. The many modifications required to make the original function(see above)
+/* unwrap handle initialisation for subsurf aware-unwrapper. The many modifications required to make the original function(see above)
* work justified the existence of a new function. */
-static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *editMesh, short fill, short sel, short correct_aspect)
+static ParamHandle *construct_param_handle_subsurfed(Scene *scene, BMEditMesh *em, short fill, short sel, short correct_aspect)
{
ParamHandle *handle;
/* index pointers */
MFace *face;
MEdge *edge;
- EditVert *editVert;
- EditFace *editFace, **editFaceTmp;
- EditEdge *editEdge, **editEdgeTmp;
+ BMFace *editFace;
int i;
- /* modifier initialization data, will control what type of subdivision will happen*/
+ /* modifier initialisation data, will control what type of subdivision will happen*/
SubsurfModifierData smd = {{0}};
/* Used to hold subsurfed Mesh */
DerivedMesh *derivedMesh, *initialDerived;
@@ -320,29 +367,26 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *edi
MVert *subsurfedVerts;
MEdge *subsurfedEdges;
MFace *subsurfedFaces;
- /* MTFace *subsurfedTexfaces; */ /* UNUSED */
/* number of vertices and faces for subsurfed mesh*/
int numOfEdges, numOfFaces;
/* holds a map to editfaces for every subsurfed MFace. These will be used to get hidden/ selected flags etc. */
- EditFace **faceMap;
- /* Mini container to hold all EditFaces so that they may be indexed easily and fast. */
- EditFace **editFaceArray;
+ BMFace **faceMap;
/* similar to the above, we need a way to map edges to their original ones */
- EditEdge **edgeMap;
- EditEdge **editEdgeArray;
+ BMEdge **edgeMap;
handle = param_construct_begin();
if(correct_aspect) {
- EditFace *eface = EM_get_actFace(editMesh, 1);
+ editFace = BM_active_face_get(em->bm, TRUE);
- if(eface) {
+ if(editFace) {
+ MTexPoly *tf;
float aspx, aspy;
- MTFace *texface= CustomData_em_get(&editMesh->fdata, eface->data, CD_MTFACE);
+ tf= CustomData_bmesh_get(&em->bm->pdata, editFace->head.data, CD_MTEXPOLY);
+
+ ED_image_uv_aspect(tf->tpage, &aspx, &aspy);
- ED_image_uv_aspect(texface->tpage, &aspx, &aspy);
-
if(aspx!=aspy)
param_aspect_ratio(handle, aspx, aspy);
}
@@ -352,7 +396,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *edi
smd.levels = scene->toolsettings->uv_subsurf_level;
smd.subdivType = ME_CC_SUBSURF;
- initialDerived = CDDM_from_editmesh(editMesh, NULL);
+ initialDerived = CDDM_from_BMEditMesh(em, NULL, 0, 0);
derivedMesh = subsurf_make_derived_from_derived(initialDerived, &smd,
0, NULL, 0, 0, 1);
@@ -361,49 +405,34 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *edi
/* get the derived data */
subsurfedVerts = derivedMesh->getVertArray(derivedMesh);
subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh);
- subsurfedFaces = derivedMesh->getFaceArray(derivedMesh);
+ subsurfedFaces = derivedMesh->getTessFaceArray(derivedMesh);
origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX);
origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX);
- origFaceIndices = derivedMesh->getFaceDataArray(derivedMesh, CD_ORIGINDEX);
-
- /* subsurfedTexfaces = derivedMesh->getFaceDataArray(derivedMesh, CD_MTFACE); */ /* UNUSED */
+ origFaceIndices = derivedMesh->getTessFaceDataArray(derivedMesh, CD_ORIGINDEX);
numOfEdges = derivedMesh->getNumEdges(derivedMesh);
- numOfFaces = derivedMesh->getNumFaces(derivedMesh);
+ numOfFaces = derivedMesh->getNumTessFaces(derivedMesh);
faceMap = MEM_mallocN(numOfFaces*sizeof(EditFace *), "unwrap_edit_face_map");
- editFaceArray = MEM_mallocN(editMesh->totface*sizeof(EditFace *), "unwrap_editFaceArray");
- /* fill edit face array with edit faces */
- for(editFace = editMesh->faces.first, editFaceTmp = editFaceArray; editFace; editFace= editFace->next, editFaceTmp++)
- *editFaceTmp = editFace;
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+ EDBM_init_index_arrays(em, 0, 1, 1);
/* map subsurfed faces to original editFaces */
for(i = 0; i < numOfFaces; i++)
- faceMap[i] = editFaceArray[origFaceIndices[i]];
-
- MEM_freeN(editFaceArray);
+ faceMap[i] = EDBM_get_face_for_index(em, origFaceIndices[i]);
edgeMap = MEM_mallocN(numOfEdges*sizeof(EditEdge *), "unwrap_edit_edge_map");
- editEdgeArray = MEM_mallocN(editMesh->totedge*sizeof(EditEdge *), "unwrap_editEdgeArray");
-
- /* fill edit edge array with edit edges */
- for(editEdge = editMesh->edges.first, editEdgeTmp = editEdgeArray; editEdge; editEdge= editEdge->next, editEdgeTmp++)
- *editEdgeTmp = editEdge;
/* map subsurfed edges to original editEdges */
for(i = 0; i < numOfEdges; i++) {
/* not all edges correspond to an old edge */
edgeMap[i] = (origEdgeIndices[i] != -1)?
- editEdgeArray[origEdgeIndices[i]] : NULL;
+ EDBM_get_edge_for_index(em, origEdgeIndices[i]) : NULL;
}
- MEM_freeN(editEdgeArray);
-
- /* we need the editvert indices too */
- for(editVert = editMesh->verts.first, i=0; editVert; editVert = editVert->next, i++)
- editVert->tmp.t = i;
+ EDBM_free_index_arrays(em);
/* Prepare and feed faces to the solver */
for(i = 0; i < numOfFaces; i++) {
@@ -411,23 +440,19 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *edi
ParamBool pin[4], select[4];
float *co[4];
float *uv[4];
- EditFace *origFace = faceMap[i];
- MTFace *origtexface = (MTFace *)CustomData_em_get(&editMesh->fdata, origFace->data, CD_MTFACE);
+ BMFace *origFace = faceMap[i];
face = subsurfedFaces+i;
if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
- if(origFace->h)
+ if(BM_elem_flag_test(origFace, BM_ELEM_HIDDEN))
continue;
}
else {
- if((origFace->h) || (sel && (origFace->f & SELECT)==0))
+ if(BM_elem_flag_test(origFace, BM_ELEM_HIDDEN) || (sel && !BM_elem_flag_test(origFace, BM_ELEM_SELECT)))
continue;
}
- /* Now we feed the rest of the data from the subsurfed faces */
- /* texface= subsurfedTexfaces+i; */ /* UNUSED */
-
/* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */
key = (ParamKey)face;
vkeys[0] = (ParamKey)face->v1;
@@ -442,17 +467,17 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *edi
/* This is where all the magic is done. If the vertex exists in the, we pass the original uv pointer to the solver, thus
* flushing the solution to the edit mesh. */
- texface_from_original_index(origFace, origtexface, origVertIndices[face->v1], &uv[0], &pin[0], &select[0], scene);
- texface_from_original_index(origFace, origtexface, origVertIndices[face->v2], &uv[1], &pin[1], &select[1], scene);
- texface_from_original_index(origFace, origtexface, origVertIndices[face->v3], &uv[2], &pin[2], &select[2], scene);
- texface_from_original_index(origFace, origtexface, origVertIndices[face->v4], &uv[3], &pin[3], &select[3], scene);
+ texface_from_original_index(origFace, origVertIndices[face->v1], &uv[0], &pin[0], &select[0], scene, em);
+ texface_from_original_index(origFace, origVertIndices[face->v2], &uv[1], &pin[1], &select[1], scene, em);
+ texface_from_original_index(origFace, origVertIndices[face->v3], &uv[2], &pin[2], &select[2], scene, em);
+ texface_from_original_index(origFace, origVertIndices[face->v4], &uv[3], &pin[3], &select[3], scene, em);
param_face_add(handle, key, 4, vkeys, co, uv, pin, select);
}
/* these are calculated from original mesh too */
for(edge = subsurfedEdges, i = 0; i < numOfEdges; i++, edge++) {
- if((edgeMap[i] != NULL) && edgeMap[i]->seam) {
+ if((edgeMap[i] != NULL) && BM_elem_flag_test(edgeMap[i], BM_ELEM_SEAM)) {
ParamKey vkeys[2];
vkeys[0] = (ParamKey)edge->v1;
vkeys[1] = (ParamKey)edge->v2;
@@ -475,7 +500,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *edi
typedef struct MinStretch {
Scene *scene;
Object *obedit;
- EditMesh *em;
+ BMEditMesh *em;
ParamHandle *handle;
float blend;
double lasttime;
@@ -487,13 +512,12 @@ static int 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");
short implicit= 1;
if(!uvedit_have_selection(scene, em, implicit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
return 0;
}
@@ -674,12 +698,9 @@ void UV_OT_minimize_stretch(wmOperatorType *ot)
ot->poll= ED_operator_uvedit;
/* properties */
- RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes",
- "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry");
- RNA_def_float_factor(ot->srna, "blend", 0.0f, 0.0f, 1.0f, "Blend",
- "Blend factor between stretch minimized and original", 0.0f, 1.0f);
- RNA_def_int(ot->srna, "iterations", 0, 0, INT_MAX, "Iterations",
- "Number of iterations to run, 0 is unlimited when run interactively", 0, 100);
+ RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry");
+ RNA_def_float_factor(ot->srna, "blend", 0.0f, 0.0f, 1.0f, "Blend", "Blend factor between stretch minimized and original", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "iterations", 0, 0, INT_MAX, "Iterations", "Number of iterations to run, 0 is unlimited when run interactively", 0, 100);
}
/* ******************** Pack Islands operator **************** */
@@ -688,12 +709,11 @@ static int pack_islands_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;
short implicit= 1;
if(!uvedit_have_selection(scene, em, implicit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
@@ -712,7 +732,6 @@ static int pack_islands_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;
}
@@ -728,8 +747,7 @@ void UV_OT_pack_islands(wmOperatorType *ot)
ot->poll= ED_operator_uvedit;
/* properties */
- RNA_def_float_factor(ot->srna, "margin", 0.0f, 0.0f, 1.0f, "Margin",
- "Space between islands", 0.0f, 1.0f);
+ RNA_def_float_factor(ot->srna, "margin", 0.0f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
}
/* ******************** Average Islands Scale operator **************** */
@@ -738,12 +756,11 @@ 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;
short implicit= 1;
if(!uvedit_have_selection(scene, em, implicit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
@@ -755,7 +772,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;
}
@@ -777,13 +793,12 @@ 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;
short use_subsurf = scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF;
if(!ED_uvedit_test(obedit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
return;
}
@@ -793,7 +808,6 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
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)
@@ -824,9 +838,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;
@@ -836,13 +853,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_elem_flag_test(efa, BM_ELEM_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);
@@ -917,7 +933,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 */
@@ -944,7 +960,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)
@@ -970,14 +985,17 @@ static void uv_transform_properties(wmOperatorType *ot, int 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= BM_active_face_get(em->bm, TRUE);
+ 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);
}
@@ -987,30 +1005,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.5f)*scale)+0.5f;
- tf->uv[1][0]= ((tf->uv[1][0]-0.5f)*scale)+0.5f;
- tf->uv[2][0]= ((tf->uv[2][0]-0.5f)*scale)+0.5f;
- if(efa->v4)
- tf->uv[3][0]= ((tf->uv[3][0]-0.5f)*scale)+0.5f;
+ 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_elem_flag_test(efa, BM_ELEM_SELECT) || BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
+ 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.5f)*scale)+0.5f;
- tf->uv[1][1]= ((tf->uv[1][1]-0.5f)*scale)+0.5f;
- tf->uv[2][1]= ((tf->uv[2][1]-0.5f)*scale)+0.5f;
- if(efa->v4)
- tf->uv[3][1]= ((tf->uv[3][1]-0.5f)*scale)+0.5f;
+ 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_elem_flag_test(efa, BM_ELEM_SELECT)||BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
+ 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;
}
}
}
@@ -1028,12 +1044,13 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot)
"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");
int clip_to_bounds= RNA_boolean_get(op->ptr, "clip_to_bounds");
int scale_to_bounds= RNA_boolean_get(op->ptr, "scale_to_bounds");
@@ -1045,16 +1062,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);
-
- DO_MINMAX2(tf->uv[0], min, max);
- DO_MINMAX2(tf->uv[1], min, max);
- DO_MINMAX2(tf->uv[2], min, max);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
- 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);
}
}
@@ -1067,31 +1081,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_elem_flag_test(efa, BM_ELEM_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;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
- for(b=0; b<nverts; b++) {
- CLAMP(tf->uv[b][0], 0.0f, 1.0f);
- CLAMP(tf->uv[b][1], 0.0f, 1.0f);
- }
+ 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.0f, 1.0f);
+ CLAMP(luv->uv[1], 0.0f, 1.0f);
}
}
}
@@ -1102,9 +1113,9 @@ static void uv_map_clip_correct(EditMesh *em, wmOperator *op)
/* assumes UV Map is checked, doesn't run update funcs */
void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
{
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
ParamHandle *handle;
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
const short fill_holes= scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES;
const short correct_aspect= !(scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT);
const short use_subsurf = scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF;
@@ -1123,15 +1134,13 @@ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
param_flush(handle);
param_delete(handle);
-
- BKE_mesh_end_editmesh(obedit->data, em);
}
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;
int method = RNA_enum_get(op->ptr, "method");
int fill_holes = RNA_boolean_get(op->ptr, "fill_holes");
int correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
@@ -1141,11 +1150,8 @@ static int unwrap_exec(bContext *C, wmOperator *op)
short implicit= 0;
if(!uvedit_have_selection(scene, em, implicit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
- return 0;
+ return OPERATOR_CANCELLED;
}
-
- BKE_mesh_end_editmesh(obedit->data, em);
/* add uvs if they don't exist yet */
if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
@@ -1215,17 +1221,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;
}
@@ -1235,17 +1242,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_elem_flag_test(efa, BM_ELEM_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);
}
}
}
@@ -1253,15 +1258,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_elem_flag_test(efa, BM_ELEM_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);
}
}
@@ -1271,15 +1274,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_elem_flag_test(efa, BM_ELEM_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);
}
}
}
@@ -1289,7 +1290,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;
}
@@ -1325,38 +1325,20 @@ 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;
+ Mesh *me = (Mesh*)obedit->data;
/* add uvs if they don't exist yet */
- if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- BKE_mesh_end_editmesh(obedit->data, em);
+ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
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);
-
- tf->uv[0][0]= 0.0f;
- tf->uv[0][1]= 0.0f;
-
- tf->uv[1][0]= 1.0f;
- tf->uv[1][1]= 0.0f;
-
- tf->uv[2][0]= 1.0f;
- tf->uv[2][1]= 1.0f;
-
- tf->uv[3][0]= 0.0f;
- tf->uv[3][1]= 1.0f;
- }
+ if (!ED_mesh_uv_loop_reset(C, me)) {
+ return OPERATOR_CANCELLED;
}
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;
}
@@ -1388,55 +1370,69 @@ 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 *UNUSED(tf))
{
+ BMLoop *l;
+ BMIter liter;
+ MLoopUV *luv;
+ float **uvs = NULL;
+ BLI_array_fixedstack_declare(uvs, BM_NGON_STACK_SIZE, efa->len, __func__);
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);
+ 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.5f) tf->uv[i][0] += 1.0f;
+ dx = uvs[mi][0] - uvs[i][0];
+ if(dx > 0.5f) uvs[i][0] += 1.0f;
}
}
+
+ BLI_array_fixedstack_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_elem_flag_test(efa, BM_ELEM_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);
@@ -1444,7 +1440,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;
}
@@ -1484,31 +1479,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_elem_flag_test(efa, BM_ELEM_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);
@@ -1516,7 +1513,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;
}
@@ -1542,15 +1538,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;
- float no[3], cube_size, *loc, dx, dy;
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ /* MTexPoly *tf; */ /* UNUSED */
+ MLoopUV *luv;
+ float 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;
}
@@ -1560,34 +1558,31 @@ 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);
-
- axis_dominant_v3(&cox, &coy, no);
-
- tf->uv[0][0]= 0.5f+0.5f*cube_size*(loc[cox] + efa->v1->co[cox]);
- tf->uv[0][1]= 0.5f+0.5f*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.5f+0.5f*cube_size*(loc[cox] + efa->v2->co[cox]);
- tf->uv[1][1]= 0.5f+0.5f*cube_size*(loc[coy] + efa->v2->co[coy]);
- tf->uv[1][0] -= dx;
- tf->uv[1][1] -= dy;
- tf->uv[2][0]= 0.5f+0.5f*cube_size*(loc[cox] + efa->v3->co[cox]);
- tf->uv[2][1]= 0.5f+0.5f*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.5f+0.5f*cube_size*(loc[cox] + efa->v4->co[cox]);
- tf->uv[3][1]= 0.5f+0.5f*cube_size*(loc[coy] + efa->v4->co[coy]);
- tf->uv[3][0] -= dx;
- tf->uv[3][1] -= dy;
+ 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); */ /* UNUSED */
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
+
+ axis_dominant_v3(&cox, &coy, efa->no);
+
+ dx = dy = 0;
+ 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.5f+0.5f*cube_size*(loc[cox] + l->v->co[cox]);
+ luv->uv[1] = 0.5f+0.5f*cube_size*(loc[coy] + l->v->co[coy]);
+
+ if (first) {
+ dx = floor(luv->uv[0]);
+ dy = floor(luv->uv[1]);
+ first = 0;
}
+
+
+ luv->uv[0] -= dx;
+ luv->uv[1] -= dy;
}
}
@@ -1596,7 +1591,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;
}
@@ -1612,7 +1606,6 @@ void UV_OT_cube_project(wmOperatorType *ot)
ot->poll= ED_operator_uvmap;
/* properties */
- RNA_def_float(ot->srna, "cube_size", 1.0f, 0.0f, FLT_MAX, "Cube Size",
- "Size of the cube to project on", 0.001f, 100.0f);
+ RNA_def_float(ot->srna, "cube_size", 1.0f, 0.0f, FLT_MAX, "Cube Size", "Size of the cube to project on", 0.001f, 100.0f);
uv_map_clip_correct_properties(ot);
}
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 99dd3987937..b128a6e46e7 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -395,8 +395,8 @@ GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
int points_per_mat[MAX_MATERIALS];
int i, curmat, curpoint, totface;
- mface = dm->getFaceArray(dm);
- totface= dm->getNumFaces(dm);
+ mface = dm->getTessFaceArray(dm);
+ totface= dm->getNumTessFaces(dm);
/* get the number of points used by each material, treating
each quad as two triangles */
@@ -573,9 +573,9 @@ static void GPU_buffer_copy_vertex(DerivedMesh *dm, float *varray, int *index, i
int i, j, start, totface;
mvert = dm->getVertArray(dm);
- f = dm->getFaceArray(dm);
+ f = dm->getTessFaceArray(dm);
- totface= dm->getNumFaces(dm);
+ totface= dm->getNumTessFaces(dm);
for(i = 0; i < totface; i++, f++) {
start = index[mat_orig_to_new[f->mat_nr]];
@@ -610,11 +610,11 @@ static void GPU_buffer_copy_normal(DerivedMesh *dm, float *varray, int *index, i
int start;
float f_no[3];
- float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
+ float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
MVert *mvert = dm->getVertArray(dm);
- MFace *f = dm->getFaceArray(dm);
+ MFace *f = dm->getTessFaceArray(dm);
- totface= dm->getNumFaces(dm);
+ totface= dm->getNumTessFaces(dm);
for(i = 0; i < totface; i++, f++) {
const int smoothnormal = (f->flag & ME_SMOOTH);
@@ -673,11 +673,11 @@ static void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int *
MTFace *mtface;
MFace *f;
- if(!(mtface = DM_get_face_data_layer(dm, CD_MTFACE)))
+ if(!(mtface = DM_get_tessface_data_layer(dm, CD_MTFACE)))
return;
- f = dm->getFaceArray(dm);
+ f = dm->getTessFaceArray(dm);
- totface = dm->getNumFaces(dm);
+ totface = dm->getNumTessFaces(dm);
for(i = 0; i < totface; i++, f++) {
start = index[mat_orig_to_new[f->mat_nr]];
@@ -703,9 +703,9 @@ static void GPU_buffer_copy_color3(DerivedMesh *dm, float *varray_, int *index,
int i, totface;
char *varray = (char *)varray_;
char *mcol = (char *)user;
- MFace *f = dm->getFaceArray(dm);
+ MFace *f = dm->getTessFaceArray(dm);
- totface= dm->getNumFaces(dm);
+ totface= dm->getNumTessFaces(dm);
for(i=0; i < totface; i++, f++) {
int start = index[mat_orig_to_new[f->mat_nr]];
@@ -738,9 +738,9 @@ static void GPU_buffer_copy_mcol(DerivedMesh *dm, float *varray_, int *index, in
int i, totface;
unsigned char *varray = (unsigned char *)varray_;
unsigned char *mcol = (unsigned char *)user;
- MFace *f = dm->getFaceArray(dm);
+ MFace *f = dm->getTessFaceArray(dm);
- totface= dm->getNumFaces(dm);
+ totface= dm->getNumTessFaces(dm);
for(i=0; i < totface; i++, f++) {
int start = index[mat_orig_to_new[f->mat_nr]];
@@ -777,15 +777,15 @@ static void GPU_buffer_copy_edge(DerivedMesh *dm, float *varray_, int *UNUSED(in
static void GPU_buffer_copy_uvedge(DerivedMesh *dm, float *varray, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user))
{
- MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
+ MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
int i, j=0;
if(!tf)
return;
- for(i = 0; i < dm->numFaceData; i++, tf++) {
+ for(i = 0; i < dm->numTessFaceData; i++, tf++) {
MFace mf;
- dm->getFace(dm,i,&mf);
+ dm->getTessFace(dm,i,&mf);
copy_v2_v2(&varray[j],tf->uv[0]);
copy_v2_v2(&varray[j+2],tf->uv[1]);
@@ -816,13 +816,13 @@ static MCol *gpu_buffer_color_type(DerivedMesh *dm)
int type;
type = CD_ID_MCOL;
- c = DM_get_face_data_layer(dm, type);
+ c = DM_get_tessface_data_layer(dm, type);
if(!c) {
type = CD_WEIGHT_MCOL;
- c = DM_get_face_data_layer(dm, type);
+ c = DM_get_tessface_data_layer(dm, type);
if(!c) {
type = CD_MCOL;
- c = DM_get_face_data_layer(dm, type);
+ c = DM_get_tessface_data_layer(dm, type);
}
}
@@ -916,7 +916,7 @@ static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type)
return NULL;
}
else if(type == GPU_BUFFER_UV) {
- if(!DM_get_face_data_layer(dm, CD_MTFACE))
+ if(!DM_get_tessface_data_layer(dm, CD_MTFACE))
return NULL;
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index ef2abb20cf3..0ddaf07c67e 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -1071,7 +1071,7 @@ static void do_material_tex(GPUShadeInput *shi)
else
newnor = tnor;
- norfac = MIN2(fabsf(mtex->norfac), 1.0f);
+ norfac = minf(fabsf(mtex->norfac), 1.0f);
if(norfac == 1.0f && !GPU_link_changed(stencil)) {
shi->vn = newnor;
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index e1481d2a08f..ade63aa1e9c 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -459,12 +459,13 @@ static int round_up(int x, int mod)
static struct proxy_output_ctx * alloc_proxy_output_ffmpeg(
struct anim * anim,
AVStream * st, int proxy_size, int width, int height,
- int UNUSED(quality))
+ int quality)
{
struct proxy_output_ctx * rv = MEM_callocN(
sizeof(struct proxy_output_ctx), "alloc_proxy_output");
char fname[FILE_MAX];
+ int ffmpeg_quality;
// JPEG requires this
width = round_up(width, 8);
@@ -514,6 +515,12 @@ static struct proxy_output_ctx * alloc_proxy_output_ffmpeg(
rv->c->time_base.num = 1;
rv->st->time_base = rv->c->time_base;
+ /* there's no way to set JPEG quality in the same way as in AVI JPEG and image sequence,
+ * but this seems to be giving expected quality result */
+ ffmpeg_quality = (int)(1.0f + 30.0f * (1.0f - (float)quality / 100.0f) + 0.5f);
+ av_set_int(rv->c, "qmin", ffmpeg_quality);
+ av_set_int(rv->c, "qmax", ffmpeg_quality);
+
if (rv->of->flags & AVFMT_GLOBALHEADER) {
rv->c->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index eeeb0581527..f7f40e99617 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[64]; /* layer name, MAX_CUSTOMDATA_LAYER_AAME */
void *data; /* layer data */
} CustomDataLayer;
@@ -63,11 +63,13 @@ 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[32]; /* runtime only! - maps types to indices of first layer of that type,
+ int typemap[33]; /* runtime only! - maps types to indices of first layer of that type,
* MUST be >= CD_NUMTYPES, but we cant use a define here.
* Correct size is ensured in CustomData_update_typemap assert() */
+ int pad1;
+
int totlayer, maxlayer; /* number of layers, size of layers array */
- int totsize, pad; /* in editmode, total size of all data layers */
+ int totsize, pad2; /* in editmode, total size of all data layers */
void *pool; /* Bmesh: Memory pool for allocation of blocks */
CustomDataExternal *external; /* external file storing customdata layers */
} CustomData;
@@ -99,8 +101,6 @@ typedef struct CustomData {
#define CD_CLOTH_ORCO 23
#define CD_RECAST 24
-#ifdef USE_BMESH_FORWARD_COMPAT
-
/* BMESH ONLY START */
#define CD_MPOLY 25
#define CD_MLOOP 26
@@ -108,16 +108,11 @@ typedef struct CustomData {
#define CD_SHAPEKEY 28
#define CD_BWEIGHT 29
#define CD_CREASE 30
-#define CD_WEIGHT_MLOOPCOL 31
+#define CD_ORIGSPACE_MLOOP 31
+#define CD_WEIGHT_MLOOPCOL 32
/* BMESH ONLY END */
-#define CD_NUMTYPES 32
-
-#else
-
-#define CD_NUMTYPES 25
-
-#endif
+#define CD_NUMTYPES 33
/* Bits for CustomDataMask */
#define CD_MASK_MVERT (1 << CD_MVERT)
@@ -144,8 +139,6 @@ typedef struct CustomData {
#define CD_MASK_CLOTH_ORCO (1 << CD_CLOTH_ORCO)
#define CD_MASK_RECAST (1 << CD_RECAST)
-#ifdef USE_BMESH_FORWARD_COMPAT
-
/* BMESH ONLY START */
#define CD_MASK_MPOLY (1 << CD_MPOLY)
#define CD_MASK_MLOOP (1 << CD_MLOOP)
@@ -153,11 +146,10 @@ typedef struct CustomData {
#define CD_MASK_SHAPEKEY (1 << CD_SHAPEKEY)
#define CD_MASK_BWEIGHT (1 << CD_BWEIGHT)
#define CD_MASK_CREASE (1 << CD_CREASE)
-#define CD_MASK_WEIGHT_MLOOPCOL (1 << CD_WEIGHT_MLOOPCOL)
+#define CD_MASK_ORIGSPACE_MLOOP (1 << CD_ORIGSPACE_MLOOP)
+#define CD_MASK_WEIGHT_MLOOPCOL (1LL << CD_WEIGHT_MLOOPCOL)
/* BMESH ONLY END */
-#endif
-
/* CustomData.flag */
/* indicates layer should not be copied by CustomData_from_template or
diff --git a/source/blender/makesdna/DNA_defs.h b/source/blender/makesdna/DNA_defs.h
index aa2cfb3f6e9..762e027f934 100644
--- a/source/blender/makesdna/DNA_defs.h
+++ b/source/blender/makesdna/DNA_defs.h
@@ -45,7 +45,8 @@
/* hrmf, we need a better include then this */
#include "../blenloader/BLO_sys_types.h" /* needed for int64_t only! */
-#define USE_BMESH_FORWARD_COMPAT
+/* Must not be defined for BMesh, as this guards code for pre-BMesh code to load BMesh .blend files */
+/* #define USE_BMESH_FORWARD_COMPAT */
/* non-id name variables should use this length */
#define MAX_NAME 64
diff --git a/source/blender/makesdna/DNA_key_types.h b/source/blender/makesdna/DNA_key_types.h
index d27ec513cc1..f2840a3b9b7 100644
--- a/source/blender/makesdna/DNA_key_types.h
+++ b/source/blender/makesdna/DNA_key_types.h
@@ -53,6 +53,8 @@ typedef struct KeyBlock {
float slidermin;
float slidermax;
+
+ int uid, pad3;
} KeyBlock;
@@ -72,6 +74,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 ********************* */
@@ -92,5 +97,5 @@ 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 ea626b5221d..f422e80b864 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -69,7 +69,6 @@ typedef struct Mesh {
struct Key *key;
struct Material **mat;
-/*#ifdef USE_BMESH_FORWARD_COMPAT*/ /* XXX - ifdefs dont work here! */
/* BMESH ONLY */
/*new face structures*/
struct MPoly *mpoly;
@@ -78,36 +77,36 @@ typedef struct Mesh {
struct MLoopUV *mloopuv;
struct MLoopCol *mloopcol;
/* END BMESH ONLY */
-/*#endif*/
- struct MFace *mface; /* array of mesh object mode faces */
- struct MTFace *mtface; /* store face UV's and texture here */
+ /*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;
-/*#ifdef USE_BMESH_FORWARD_COMPAT*/ /* XXX - ifdefs dont work here! */
/* BMESH ONLY */
struct CustomData pdata, ldata;
/* END BMESH ONLY */
-/*#endif*/
int totvert, totedge, totface, totselect;
-/*#ifdef USE_BMESH_FORWARD_COMPAT*/
/* BMESH ONLY */
int totpoly, totloop;
/* END BMESH ONLY */
-/*#endif*/ /* XXX - ifdefs dont work here! */
/* 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
@@ -229,9 +228,8 @@ typedef struct TFace {
/* this is so we can save bmesh files that load in trunk, ignoring NGons
* will eventually be removed */
-#if 0 /* enable in bmesh branch only for now */
#define USE_BMESH_SAVE_AS_COMPAT
-#endif
+#define USE_BMESH_SAVE_WITHOUT_MFACE
#endif
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index e0a793f3371..53f9ff101a3 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -38,6 +38,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;
@@ -67,14 +68,13 @@ typedef struct MVert {
char flag, bweight;
} MVert;
-/* at the moment alpha is abused for vertex painting
- * and not used for transperency, note that red and blue are swapped */
+/* tesselation vertex color data.
+ * at the moment alpha is abused for vertex painting
+ * and not used for transparency, note that red and blue are swapped */
typedef struct MCol {
char a, r, g, b;
} MCol;
-#ifdef USE_BMESH_FORWARD_COMPAT
-
/*new face structure, replaces MFace, which is now
only used for storing tesselations.*/
typedef struct MPoly {
@@ -92,19 +92,35 @@ typedef struct MLoop {
unsigned int e; /*edge index*/
} MLoop;
-#endif /* USE_BMESH_FORWARD_COMPAT */
-
-/*bmesh custom data stuff*/
typedef struct MTexPoly {
struct Image *tpage;
char flag, transp;
short mode,tile,unwrap;
} MTexPoly;
+/* can copy from/to MTexPoly/MTFace */
+#define ME_MTEXFACE_CPY(dst, src) \
+{ \
+ (dst)->tpage = (src)->tpage; \
+ (dst)->flag = (src)->flag; \
+ (dst)->transp = (src)->transp; \
+ (dst)->mode = (src)->mode; \
+ (dst)->tile = (src)->tile; \
+ (dst)->unwrap = (src)->unwrap; \
+}
+
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 transparency, note that red and blue are swapped */
typedef struct MLoopCol {
char a, r, g, b;
} MLoopCol;
@@ -118,6 +134,7 @@ typedef struct MSelect {
int type; /* EDITVERT/EDITEDGE/EDITFACE */
} MSelect;
+/*tesselation uv face data*/
typedef struct MTFace {
float uv[4][2];
struct Image *tpage;
@@ -140,6 +157,10 @@ typedef struct OrigSpaceFace {
float uv[4][2];
} OrigSpaceFace;
+typedef struct OrigSpaceLoop {
+ float uv[2];
+} OrigSpaceLoop;
+
typedef struct MDisps {
/* Strange bug in SDNA: if disps pointer comes first, it fails to see totdisp */
int totdisp;
@@ -233,7 +254,16 @@ typedef struct MRecast {
#define ME_SMOOTH 1
#define ME_FACE_SEL 2
#define ME_FREESTYLE_FACE 4
- /* flag ME_HIDE==16 is used here too */
+/* flag ME_HIDE==16 is used here too */
+
+#define ME_POLY_LOOP_PREV(mloop, mp, i) (&(mloop)[(mp)->loopstart + (((i) + (mp)->totloop - 1) % (mp)->totloop)])
+#define ME_POLY_LOOP_NEXT(mloop, mp, i) (&(mloop)[(mp)->loopstart + (((i) + 1) % (mp)->totloop)])
+
+/* mselect->type */
+#define ME_VSEL 0
+#define ME_ESEL 1
+#define ME_FSEL 2
+
/* mtface->flag */
#define TF_SELECT 1 /* use MFace hide flag (after 2.43), should be able to reuse after 2.44 */
#define TF_ACTIVE 2 /* deprecated! */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 0899b77abbc..93e8c2973f2 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -77,6 +77,7 @@ typedef enum ModifierType {
eModifierType_Ocean,
eModifierType_DynamicPaint,
eModifierType_Remesh,
+ eModifierType_NgonInterp,
NUM_MODIFIER_TYPES
} ModifierType;
@@ -676,6 +677,7 @@ typedef struct ShrinkwrapModifierData {
#define MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS (1<<2)
#define MOD_SHRINKWRAP_PROJECT_OVER_NORMAL 0 /* projection over normal is used if no axis is selected */
+
typedef struct SimpleDeformModifierData {
ModifierData modifier;
@@ -808,9 +810,14 @@ typedef struct OceanModifierData {
#define MOD_OCEAN_GENERATE_NORMALS 2
-typedef struct WarpModifierData {
+/* BMESH_ONLY */
+typedef struct NgonInterpModifierData {
ModifierData modifier;
+ int resolution, pad0;
+} NgonInterpModifierData;
+typedef struct WarpModifierData {
+ ModifierData modifier;
/* keep in sync with MappingInfoModifierData */
struct Tex *texture;
struct Object *map_object;
diff --git a/source/blender/makesdna/DNA_vec_types.h b/source/blender/makesdna/DNA_vec_types.h
index 0e832b8c95f..1420ca48c22 100644
--- a/source/blender/makesdna/DNA_vec_types.h
+++ b/source/blender/makesdna/DNA_vec_types.h
@@ -60,11 +60,11 @@ typedef struct vec2d {
typedef struct vec3i {
int x, y, z;
} vec3i;
-
+*/
typedef struct vec3f {
float x, y, z;
} vec3f;
-
+/*
typedef struct vec3d {
double x, y, z;
} vec3d;
diff --git a/source/blender/makesdna/intern/SConscript b/source/blender/makesdna/intern/SConscript
index 8185676cbfc..a819d827788 100644
--- a/source/blender/makesdna/intern/SConscript
+++ b/source/blender/makesdna/intern/SConscript
@@ -18,7 +18,7 @@ dna = env.Clone()
makesdna_tool.Append(CCFLAGS = '-DBASE_HEADER="\\"source/blender/makesdna/\\"" ')
makesdna_tool.Append (CPPPATH = ['#/intern/guardedalloc',
- '../../makesdna', '../../blenloader'])
+ '../../makesdna', '../../blenloader', '../../bmesh'])
if env['OURPLATFORM'] == 'linuxcross':
USE_WINE = True # when cross compiling on linux 64bit this is useful
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 5b115a404ce..9c2289b2edd 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -42,6 +42,7 @@
#include "MEM_guardedalloc.h" // for MEM_freeN MEM_mallocN MEM_callocN
#ifdef WITH_DNA_GHASH
+# include "BLI_utildefines.h"
# include "BLI_ghash.h"
#endif
@@ -389,7 +390,7 @@ static void init_structDNA(SDNA *sdna, int do_endian_swap)
while(nr<sdna->nr_types) {
sdna->types[nr]= cp;
- /* this is a patch, to change struct names without a confict with SDNA */
+ /* this is a patch, to change struct names without a conflict with SDNA */
/* be careful to use it, in this case for a system-struct (opengl/X) */
if( *cp == 'b') {
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 9127724eeb4..2232655afae 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -343,9 +343,12 @@ extern StructRNA RNA_Menu;
extern StructRNA RNA_Mesh;
extern StructRNA RNA_MeshColor;
extern StructRNA RNA_MeshColorLayer;
+extern StructRNA RNA_MeshLoopColorLayer;
extern StructRNA RNA_MeshDeformModifier;
extern StructRNA RNA_MeshEdge;
extern StructRNA RNA_MeshFace;
+extern StructRNA RNA_MeshPolygon;
+extern StructRNA RNA_MeshLoop;
extern StructRNA RNA_MeshFloatProperty;
extern StructRNA RNA_MeshFloatPropertyLayer;
extern StructRNA RNA_MeshIntProperty;
@@ -355,6 +358,8 @@ extern StructRNA RNA_MeshStringProperty;
extern StructRNA RNA_MeshStringPropertyLayer;
extern StructRNA RNA_MeshTextureFace;
extern StructRNA RNA_MeshTextureFaceLayer;
+extern StructRNA RNA_MeshTexturePoly;
+extern StructRNA RNA_MeshTexturePolyLayer;
extern StructRNA RNA_MeshVertex;
extern StructRNA RNA_MessageSensor;
extern StructRNA RNA_MetaBall;
diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript
index 2df5d29fcae..f1817bfbe6f 100644
--- a/source/blender/makesrna/SConscript
+++ b/source/blender/makesrna/SConscript
@@ -13,6 +13,9 @@ incs += ' ../nodes'
incs += ' #/extern/glew/include'
incs += ' ../freestyle'
+incs += ' ../bmesh'
+
+
defs = []
if env['WITH_BF_OPENEXR']:
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 4aa90bf93ea..ac5718a27f6 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -241,6 +241,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 26fa793de9d..60818680d0c 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 #/intern/cycles/blender'
incs += ' #/extern/glew/include '
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index ee3899c8a5c..eaa39548712 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -1,4 +1,4 @@
-/*
+/**
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -8,7 +8,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
@@ -20,6 +20,10 @@
* ***** 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.*/
+
/** \file blender/makesrna/intern/rna_mesh.c
* \ingroup RNA
*/
@@ -27,8 +31,11 @@
#include <stdlib.h>
+#include "MEM_guardedalloc.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_types.h"
#include "rna_internal.h"
@@ -39,6 +46,7 @@
#include "WM_types.h"
+#include "BLI_array.h"
#include "BLI_math_base.h"
#include "BLI_math_rotation.h"
@@ -53,14 +61,55 @@
#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
-
+#include "BKE_tessmesh.h"
#include "ED_mesh.h" /* XXX Bad level call */
#include "WM_api.h"
#include "WM_types.h"
-static void rna_Mesh_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+#include "rna_mesh_utils.h"
+
+static Mesh *rna_mesh(PointerRNA *ptr)
+{
+ Mesh *me = (Mesh *)ptr->id.data;
+ return me;
+}
+
+static CustomData *rna_mesh_pdata_helper(Mesh *me)
+{
+ return (me->edit_btmesh) ? &me->edit_btmesh->bm->pdata : &me->pdata;
+}
+
+static CustomData *rna_mesh_ldata_helper(Mesh *me)
+{
+ return (me->edit_btmesh) ? &me->edit_btmesh->bm->ldata : &me->ldata;
+}
+
+static CustomData *rna_mesh_fdata_helper(Mesh *me)
+{
+ return (me->edit_btmesh) ? NULL : &me->fdata;
+}
+
+static CustomData *rna_mesh_pdata(PointerRNA *ptr)
+{
+ Mesh *me = rna_mesh(ptr);
+ return rna_mesh_pdata_helper(me);
+}
+
+static CustomData *rna_mesh_ldata(PointerRNA *ptr)
+{
+ Mesh *me = rna_mesh(ptr);
+ return rna_mesh_ldata_helper(me);
+}
+
+static CustomData *rna_mesh_fdata(PointerRNA *ptr)
+{
+ Mesh *me = rna_mesh(ptr);
+ return rna_mesh_fdata_helper(me);
+}
+
+static void rna_Mesh_update_data(Main *bmain, Scene *scene, PointerRNA *ptr)
{
ID *id= ptr->id.data;
@@ -71,7 +120,7 @@ static void rna_Mesh_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin
}
}
-static void rna_Mesh_update_select(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_Mesh_update_select(Main *bmain, Scene *scene, PointerRNA *ptr)
{
ID *id= ptr->id.data;
/* cheating way for importers to avoid slow updates */
@@ -80,7 +129,7 @@ static void rna_Mesh_update_select(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
}
}
-void rna_Mesh_update_draw(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+void rna_Mesh_update_draw(Main *bmain, Scene *scene, PointerRNA *ptr)
{
ID *id= ptr->id.data;
/* cheating way for importers to avoid slow updates */
@@ -159,21 +208,37 @@ static void rna_MEdge_crease_set(PointerRNA *ptr, float value)
medge->crease= (char)(CLAMPIS(value*255.0f, 0, 255));
}
+static void rna_MeshPolygon_normal_get(PointerRNA *ptr, float *values)
+{
+ Mesh *me = rna_mesh(ptr);
+ MPoly *mp= (MPoly*)ptr->data;
+
+ /* BMESH_TODO: might be faster to look for a CD_NORMALS layer and use that */
+ mesh_calc_poly_normal(mp, me->mloop+mp->loopstart, me->mvert, values);
+}
+
+static float rna_MeshPolygon_area_get(PointerRNA *ptr)
+{
+ Mesh *me = (Mesh*)ptr->id.data;
+ MPoly *mp = (MPoly*)ptr->data;
+
+ return mesh_calc_poly_area(mp, me->mloop+mp->loopstart, me->mvert, NULL);
+}
+
static void rna_MeshFace_normal_get(PointerRNA *ptr, float *values)
{
- Mesh *me= (Mesh*)ptr->id.data;
+ Mesh *me = rna_mesh(ptr);
MFace *mface= (MFace*)ptr->data;
-
+
if(mface->v4)
- normal_quad_v3(values,me->mvert[mface->v1].co, me->mvert[mface->v2].co,
- me->mvert[mface->v3].co, me->mvert[mface->v4].co);
+ normal_quad_v3( values,me->mvert[mface->v1].co, me->mvert[mface->v2].co, me->mvert[mface->v3].co, me->mvert[mface->v4].co);
else
normal_tri_v3( values,me->mvert[mface->v1].co, me->mvert[mface->v2].co, me->mvert[mface->v3].co);
}
static float rna_MeshFace_area_get(PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->id.data;
+ Mesh *me = rna_mesh(ptr);
MFace *mface= (MFace*)ptr->data;
if(mface->v4)
@@ -182,6 +247,112 @@ static float rna_MeshFace_area_get(PointerRNA *ptr)
return area_tri_v3(me->mvert[mface->v1].co, me->mvert[mface->v2].co, me->mvert[mface->v3].co);
}
+static void rna_MeshTextureFace_uv1_get(PointerRNA *ptr, float *values)
+{
+ MTFace *mtface= (MTFace*)ptr->data;
+
+ values[0]= mtface->uv[0][0];
+ values[1]= mtface->uv[0][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];
+}
+
+static int rna_CustomDataData_numverts(PointerRNA *ptr, int type)
+{
+ Mesh *me = rna_mesh(ptr);
+ CustomData *fdata = rna_mesh_fdata(ptr);
+ CustomDataLayer *cdl;
+ int a, b;
+
+ for (cdl = fdata->layers, a = 0; a < fdata->totlayer; cdl++, a++) {
+ if(cdl->type == type) {
+ b = ((char *)ptr->data - ((char*)cdl->data)) / CustomData_sizeof(type);
+ if(b >= 0 && b < me->totface) {
+ return (me->mface[b].v4 ? 4 : 3);
+ }
+ }
+ }
+
+ 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];
+}
+
+static void rna_MeshTextureFace_uv_get(PointerRNA *ptr, float *values)
+{
+ MTFace *mtface= (MTFace*)ptr->data;
+ int totvert= rna_CustomDataData_numverts(ptr, CD_MTFACE);
+
+ 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);
+
+ memcpy(mtface->uv, values, totvert * 2 * sizeof(float));
+}
+
/* notice red and blue are swapped */
static void rna_MeshColor_color1_get(PointerRNA *ptr, float *values)
{
@@ -255,58 +426,33 @@ 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 *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_MeshLoopColor_color_get(PointerRNA *ptr, float *values)
{
- Mesh *me= (Mesh*)ptr->data;
-
- if (me->texflag & AUTOSPACE)
- tex_space_mesh(me);
-}
+ MLoopCol *mcol= (MLoopCol *)ptr->data;
-
-static int rna_Mesh_texspace_editable(PointerRNA *ptr)
-{
- Mesh *me= (Mesh*)ptr->data;
- return (me->texflag & AUTOSPACE)? 0: PROP_EDITABLE;
+ values[2]= (&mcol->r)[0]/255.0f;
+ values[1]= (&mcol->r)[1]/255.0f;
+ values[0]= (&mcol->r)[2]/255.0f;
}
-static void rna_Mesh_texspace_loc_get(PointerRNA *ptr, float *values)
+static void rna_MeshLoopColor_color_set(PointerRNA *ptr, const float *values)
{
- Mesh *me= (Mesh *)ptr->data;
-
- if (!me->bb)
- tex_space_mesh(me);
-
- copy_v3_v3(values, me->loc);
-}
+ MLoopCol *mcol= (MLoopCol *)ptr->data;
-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);
+ (&mcol->r)[2]= (char)(CLAMPIS(values[0]*255.0f, 0, 255));
+ (&mcol->r)[1]= (char)(CLAMPIS(values[1]*255.0f, 0, 255));
+ (&mcol->r)[0]= (char)(CLAMPIS(values[2]*255.0f, 0, 255));
}
-static void rna_Mesh_texspace_size_set(PointerRNA *ptr, const float *values)
+static int rna_Mesh_texspace_editable(PointerRNA *ptr)
{
- Mesh *me= (Mesh *)ptr->data;
-
- copy_v3_v3(me->size, values);
+ Mesh *me= (Mesh*)ptr->data;
+ return (me->texflag & AUTOSPACE)? 0: PROP_EDITABLE;
}
static void rna_MeshVertex_groups_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->id.data;
+ Mesh *me = rna_mesh(ptr);
if(me->dvert) {
MVert *mvert= (MVert*)ptr->data;
@@ -320,524 +466,293 @@ static void rna_MeshVertex_groups_begin(CollectionPropertyIterator *iter, Pointe
static void rna_MeshFace_material_index_range(PointerRNA *ptr, int *min, int *max)
{
- Mesh *me= (Mesh*)ptr->id.data;
+ Mesh *me = rna_mesh(ptr);
*min= 0;
*max= me->totcol-1;
*max= MAX2(0, *max);
}
-static CustomData *rna_mesh_fdata(Mesh *me)
-{
- return (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata;
-}
-
-static int rna_CustomDataLayer_length(PointerRNA *ptr, int type)
-{
- Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
- CustomDataLayer *layer;
- int i, length= 0;
-
- for(layer=fdata->layers, i=0; i<fdata->totlayer; layer++, i++)
- if(layer->type == type)
- length++;
-
- return length;
-}
-
-static int rna_CustomDataLayer_active_get(PointerRNA *ptr, int type, int render)
+static int rna_CustomDataLayer_active_get(PointerRNA *ptr, CustomData *data, int type, int render)
{
- Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
- int n= ((CustomDataLayer*)ptr->data) - fdata->layers;
+ int n= ((CustomDataLayer*)ptr->data) - data->layers;
- if(render) return (n == CustomData_get_render_layer_index(fdata, type));
- else return (n == CustomData_get_active_layer_index(fdata, type));
+ if(render) return (n == CustomData_get_render_layer_index(data, type));
+ else return (n == CustomData_get_active_layer_index(data, type));
}
-static int rna_CustomDataLayer_clone_get(PointerRNA *ptr, int type, int UNUSED(render))
+static int rna_CustomDataLayer_clone_get(PointerRNA *ptr, CustomData *data, int type, int render)
{
- Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
- int n= ((CustomDataLayer*)ptr->data) - fdata->layers;
+ int n= ((CustomDataLayer*)ptr->data) - data->layers;
- return (n == CustomData_get_clone_layer_index(fdata, type));
+ return (n == CustomData_get_clone_layer_index(data, type));
}
-static void rna_CustomDataLayer_active_set(PointerRNA *ptr, int value, int type, int render)
+static void rna_CustomDataLayer_active_set(PointerRNA *ptr, CustomData *data, int value, int type, int render)
{
- Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
- int n= ((CustomDataLayer*)ptr->data) - fdata->layers;
+ int n= ((CustomDataLayer*)ptr->data) - data->layers;
if(value == 0)
return;
- if(render) CustomData_set_layer_render_index(fdata, type, n);
- else CustomData_set_layer_active_index(fdata, type, n);
+ if(render) CustomData_set_layer_render_index(data, type, n);
+ else CustomData_set_layer_active_index(data, type, n);
}
-static void rna_CustomDataLayer_clone_set(PointerRNA *ptr, int value, int type, int UNUSED(render))
+static void rna_CustomDataLayer_clone_set(PointerRNA *ptr, CustomData *data, int value, int type, int render)
{
- Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
- int n= ((CustomDataLayer*)ptr->data) - fdata->layers;
+ int n= ((CustomDataLayer*)ptr->data) - data->layers;
if(value == 0)
return;
- CustomData_set_layer_clone_index(fdata, type, n);
-}
-
-static int rna_uv_texture_check(CollectionPropertyIterator *UNUSED(iter), void *data)
-{
- CustomDataLayer *layer= (CustomDataLayer*)data;
- return (layer->type != CD_MTFACE);
-}
-
-static void rna_Mesh_uv_textures_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_uv_texture_check);
+ CustomData_set_layer_clone_index(data, type, n);
}
-static int rna_Mesh_uv_textures_length(PointerRNA *ptr)
-{
- return rna_CustomDataLayer_length(ptr, CD_MTFACE);
-}
+/* uv_loop_layers */
-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);
- CustomDataLayer *cdl= (index == -1)? NULL: &fdata->layers[index];
+DEFINE_CUSTOMDATA_LAYER_COLLECTION(uv_loop_layer, ldata, CD_MLOOPUV)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(uv_loop_layer, ldata, CD_MLOOPUV, active, MeshUVLoopLayer)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(uv_loop_layer, ldata, CD_MLOOPUV, clone, MeshUVLoopLayer)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(uv_loop_layer, ldata, CD_MLOOPUV, stencil, MeshUVLoopLayer)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(uv_loop_layer, ldata, CD_MLOOPUV, render, MeshUVLoopLayer)
- return rna_pointer_inherit_refine(ptr, &RNA_MeshTextureFaceLayer, cdl);
-}
+/* MeshUVLoopLayer */
-static PointerRNA rna_Mesh_uv_texture_clone_get(PointerRNA *ptr)
+static char *rna_MeshUVLoopLayer_path(PointerRNA *ptr)
{
- 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);
+ return BLI_sprintfN("uv_loop_layer[\"%s\"]", ((CustomDataLayer*)ptr->data)->name);
}
-static PointerRNA rna_Mesh_uv_texture_stencil_get(PointerRNA *ptr)
+static void rna_MeshUVLoopLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- 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);
+ Mesh *me = rna_mesh(ptr);
+ CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
+ rna_iterator_array_begin(iter, layer->data, sizeof(MLoopUV), (me->edit_btmesh) ? 0 : me->totloop, 0, NULL);
}
-static void rna_Mesh_active_uv_texture_set(PointerRNA *ptr, PointerRNA value)
+static int rna_MeshUVLoopLayer_data_length(PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(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);
- mesh_update_customdata_pointers(me);
- return;
- }
- }
+ Mesh *me = rna_mesh(ptr);
+ return (me->edit_btmesh) ? 0 : me->totloop;
}
-static void rna_Mesh_uv_texture_clone_set(PointerRNA *ptr, PointerRNA value)
-{
- Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
- CustomDataLayer *cdl;
- int a;
+/* face uv_textures */
- for(cdl=fdata->layers, a=0; a<fdata->totlayer; cdl++, a++) {
- if(value.data == cdl) {
- CustomData_set_layer_clone_index(fdata, CD_MTFACE, a);
- return;
- }
- }
-}
+DEFINE_CUSTOMDATA_LAYER_COLLECTION(tessface_uv_texture, fdata, CD_MTFACE)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(tessface_uv_texture, fdata, CD_MTFACE, active, MeshTextureFaceLayer)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(tessface_uv_texture, fdata, CD_MTFACE, clone, MeshTextureFaceLayer)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(tessface_uv_texture, fdata, CD_MTFACE, stencil, MeshTextureFaceLayer)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(tessface_uv_texture, fdata, CD_MTFACE, render, MeshTextureFaceLayer)
-static void rna_Mesh_uv_texture_stencil_set(PointerRNA *ptr, PointerRNA value)
-{
- Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
- CustomDataLayer *cdl;
- int a;
-
- for(cdl=fdata->layers, a=0; a<fdata->totlayer; cdl++, a++) {
- if(value.data == cdl) {
- CustomData_set_layer_stencil_index(fdata, CD_MTFACE, a);
- 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);
-}
-
-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);
-}
-
-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);
-}
-
-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_set_layer_active(fdata, CD_MTFACE, 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_set_layer_clone(fdata, CD_MTFACE, 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_set_layer_stencil(fdata, CD_MTFACE, 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);
-
- *min= 0;
- *max= CustomData_number_of_layers(fdata, CD_MTFACE)-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;
-
- values[0]= mtface->uv[0][0];
- values[1]= mtface->uv[0][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)
+static void rna_MeshTextureFaceLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- MTFace *mtface= (MTFace*)ptr->data;
-
- values[0]= mtface->uv[1][0];
- values[1]= mtface->uv[1][1];
+ Mesh *me = rna_mesh(ptr);
+ CustomDataLayer *layer= (CustomDataLayer*)ptr->data;
+ rna_iterator_array_begin(iter, layer->data, sizeof(MTFace), (me->edit_btmesh)? 0: me->totface, 0, NULL);
}
-static void rna_MeshTextureFace_uv2_set(PointerRNA *ptr, const float *values)
+static int rna_MeshTextureFaceLayer_data_length(PointerRNA *ptr)
{
- MTFace *mtface= (MTFace*)ptr->data;
-
- mtface->uv[1][0]= values[0];
- mtface->uv[1][1]= values[1];
+ Mesh *me = rna_mesh(ptr);
+ return (me->edit_btmesh)? 0: me->totface;
}
-static void rna_MeshTextureFace_uv3_get(PointerRNA *ptr, float *values)
+static int rna_MeshTextureFaceLayer_active_render_get(PointerRNA *ptr)
{
- MTFace *mtface= (MTFace*)ptr->data;
-
- values[0]= mtface->uv[2][0];
- values[1]= mtface->uv[2][1];
+ return rna_CustomDataLayer_active_get(ptr, rna_mesh_fdata(ptr), CD_MTFACE, 1);
}
-static void rna_MeshTextureFace_uv3_set(PointerRNA *ptr, const float *values)
+static int rna_MeshTextureFaceLayer_active_get(PointerRNA *ptr)
{
- MTFace *mtface= (MTFace*)ptr->data;
-
- mtface->uv[2][0]= values[0];
- mtface->uv[2][1]= values[1];
+ return rna_CustomDataLayer_active_get(ptr, rna_mesh_fdata(ptr), CD_MTFACE, 0);
}
-static void rna_MeshTextureFace_uv4_get(PointerRNA *ptr, float *values)
+static int rna_MeshTextureFaceLayer_clone_get(PointerRNA *ptr)
{
- MTFace *mtface= (MTFace*)ptr->data;
-
- values[0]= mtface->uv[3][0];
- values[1]= mtface->uv[3][1];
+ return rna_CustomDataLayer_clone_get(ptr, rna_mesh_fdata(ptr), CD_MTFACE, 0);
}
-static void rna_MeshTextureFace_uv4_set(PointerRNA *ptr, const float *values)
+static void rna_MeshTextureFaceLayer_active_render_set(PointerRNA *ptr, int value)
{
- MTFace *mtface= (MTFace*)ptr->data;
-
- mtface->uv[3][0]= values[0];
- mtface->uv[3][1]= values[1];
+ rna_CustomDataLayer_active_set(ptr, rna_mesh_fdata(ptr), value, CD_MTFACE, 1);
}
-static int rna_CustomDataData_numverts(PointerRNA *ptr, int type)
+static void rna_MeshTextureFaceLayer_active_set(PointerRNA *ptr, int value)
{
- Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
- CustomDataLayer *cdl;
- int a, b;
-
- for(cdl=fdata->layers, a=0; a<fdata->totlayer; cdl++, a++) {
- if(cdl->type == type) {
- b= ((char*)ptr->data - ((char*)cdl->data))/CustomData_sizeof(type);
- if(b >= 0 && b < me->totface)
- return (me->mface[b].v4? 4: 3);
- }
- }
-
- return 0;
+ rna_CustomDataLayer_active_set(ptr, rna_mesh_fdata(ptr), value, CD_MTFACE, 0);
}
-static int rna_MeshTextureFace_uv_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static void rna_MeshTextureFaceLayer_clone_set(PointerRNA *ptr, int value)
{
- length[0]= rna_CustomDataData_numverts(ptr, CD_MTFACE);
- length[1]= 2;
- return length[0]*length[1];
+ rna_CustomDataLayer_clone_set(ptr, rna_mesh_fdata(ptr), value, CD_MTFACE, 0);
}
-static void rna_MeshTextureFace_uv_get(PointerRNA *ptr, float *values)
+static void rna_MeshTextureFaceLayer_name_set(PointerRNA *ptr, const char *value)
{
- MTFace *mtface= (MTFace*)ptr->data;
- int totvert= rna_CustomDataData_numverts(ptr, CD_MTFACE);
-
- memcpy(values, mtface->uv, totvert * 2 * sizeof(float));
+ CustomData *fdata= rna_mesh_fdata(ptr);
+ CustomDataLayer *cdl= (CustomDataLayer*)ptr->data;
+ BLI_strncpy_utf8(cdl->name, value, sizeof(cdl->name));
+ CustomData_set_layer_unique_name(fdata, cdl - fdata->layers);
}
-static void rna_MeshTextureFace_uv_set(PointerRNA *ptr, const float *values)
-{
- MTFace *mtface= (MTFace*)ptr->data;
- int totvert= rna_CustomDataData_numverts(ptr, CD_MTFACE);
+/* poly uv_textures */
- memcpy(mtface->uv, values, totvert * 2 * sizeof(float));
-}
+DEFINE_CUSTOMDATA_LAYER_COLLECTION(uv_texture, pdata, CD_MTEXPOLY)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(uv_texture, pdata, CD_MTEXPOLY, active, MeshTexturePolyLayer)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(uv_texture, pdata, CD_MTEXPOLY, clone, MeshTexturePolyLayer)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(uv_texture, pdata, CD_MTEXPOLY, stencil, MeshTexturePolyLayer)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(uv_texture, pdata, CD_MTEXPOLY, render, MeshTexturePolyLayer)
-static void rna_MeshTextureFaceLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+static void rna_MeshTexturePolyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->id.data;
+ Mesh *me = rna_mesh(ptr);
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->edit_btmesh) ? 0 : me->totpoly, 0, NULL);
}
-static int rna_MeshTextureFaceLayer_data_length(PointerRNA *ptr)
+static int rna_MeshTexturePolyLayer_data_length(PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->id.data;
- return (me->edit_mesh)? 0: me->totface;
+ Mesh *me = rna_mesh(ptr);
+ return (me->edit_btmesh) ? 0 : me->totpoly;
}
-static int rna_MeshTextureFaceLayer_active_render_get(PointerRNA *ptr)
+static int rna_MeshTexturePolyLayer_active_render_get(PointerRNA *ptr)
{
- return rna_CustomDataLayer_active_get(ptr, CD_MTFACE, 1);
+ return rna_CustomDataLayer_active_get(ptr, rna_mesh_pdata(ptr), CD_MTEXPOLY, 1);
}
-static int rna_MeshTextureFaceLayer_active_get(PointerRNA *ptr)
+static int rna_MeshTexturePolyLayer_active_get(PointerRNA *ptr)
{
- return rna_CustomDataLayer_active_get(ptr, CD_MTFACE, 0);
+ return rna_CustomDataLayer_active_get(ptr, rna_mesh_pdata(ptr), CD_MTEXPOLY, 0);
}
-static int rna_MeshTextureFaceLayer_clone_get(PointerRNA *ptr)
+static int rna_MeshTexturePolyLayer_clone_get(PointerRNA *ptr)
{
- return rna_CustomDataLayer_clone_get(ptr, CD_MTFACE, 0);
+ return rna_CustomDataLayer_clone_get(ptr, rna_mesh_pdata(ptr), CD_MTEXPOLY, 0);
}
-static void rna_MeshTextureFaceLayer_active_render_set(PointerRNA *ptr, int value)
+static void rna_MeshTexturePolyLayer_active_render_set(PointerRNA *ptr, int value)
{
- rna_CustomDataLayer_active_set(ptr, value, CD_MTFACE, 1);
+ rna_CustomDataLayer_active_set(ptr, rna_mesh_pdata(ptr), value, CD_MTEXPOLY, 1);
}
-static void rna_MeshTextureFaceLayer_active_set(PointerRNA *ptr, int value)
+static void rna_MeshTexturePolyLayer_active_set(PointerRNA *ptr, int value)
{
- rna_CustomDataLayer_active_set(ptr, value, CD_MTFACE, 0);
+ rna_CustomDataLayer_active_set(ptr, rna_mesh_pdata(ptr), value, CD_MTEXPOLY, 0);
}
-static void rna_MeshTextureFaceLayer_clone_set(PointerRNA *ptr, int value)
+static void rna_MeshTexturePolyLayer_clone_set(PointerRNA *ptr, int value)
{
- rna_CustomDataLayer_clone_set(ptr, value, CD_MTFACE, 0);
+ rna_CustomDataLayer_clone_set(ptr, rna_mesh_pdata(ptr), value, CD_MTEXPOLY, 0);
}
-static void rna_MeshTextureFaceLayer_name_set(PointerRNA *ptr, const char *value)
+static void rna_MeshTexturePolyLayer_name_set(PointerRNA *ptr, const char *value)
{
- Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
+ CustomData *pdata= rna_mesh_pdata(ptr);
CustomDataLayer *cdl= (CustomDataLayer*)ptr->data;
BLI_strncpy_utf8(cdl->name, value, sizeof(cdl->name));
- CustomData_set_layer_unique_name(fdata, cdl - fdata->layers);
+ CustomData_set_layer_unique_name(pdata, cdl - pdata->layers);
}
-static int rna_vertex_color_check(CollectionPropertyIterator *UNUSED(iter), void *data)
-{
- CustomDataLayer *layer= (CustomDataLayer*)data;
- return (layer->type != CD_MCOL);
-}
+/* vertex_color_layers */
-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);
-}
+DEFINE_CUSTOMDATA_LAYER_COLLECTION(tessface_vertex_color, fdata, CD_MCOL)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(tessface_vertex_color, fdata, CD_MCOL, active, MeshColorLayer)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(tessface_vertex_color, fdata, CD_MCOL, render, MeshColorLayer)
-static int rna_Mesh_vertex_colors_length(PointerRNA *ptr)
+static void rna_MeshColorLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- return rna_CustomDataLayer_length(ptr, CD_MCOL);
+ Mesh *me = rna_mesh(ptr);
+ CustomDataLayer *layer= (CustomDataLayer*)ptr->data;
+ rna_iterator_array_begin(iter, layer->data, sizeof(CD_MCOL), me->totloop, 0, NULL);
}
-static PointerRNA rna_Mesh_active_vertex_color_get(PointerRNA *ptr)
+static int rna_MeshColorLayer_data_length(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];
-
- return rna_pointer_inherit_refine(ptr, &RNA_MeshColorLayer, cdl);
+ Mesh *me = rna_mesh(ptr);
+ return me->totloop;
}
-static void rna_Mesh_active_vertex_color_set(PointerRNA *ptr, PointerRNA value)
+static int rna_MeshColorLayer_active_render_get(PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(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_MCOL, a);
- mesh_update_customdata_pointers(me);
- return;
- }
- }
+ return rna_CustomDataLayer_active_get(ptr, rna_mesh_fdata(ptr), CD_MCOL, 1);
}
-static int rna_Mesh_active_vertex_color_index_get(PointerRNA *ptr)
+static int rna_MeshColorLayer_active_get(PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
- return CustomData_get_active_layer(fdata, CD_MCOL);
+ return rna_CustomDataLayer_active_get(ptr, rna_mesh_fdata(ptr), CD_MCOL, 0);
}
-static void rna_Mesh_active_vertex_color_index_set(PointerRNA *ptr, int value)
+static void rna_MeshColorLayer_active_render_set(PointerRNA *ptr, int value)
{
- Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
-
- CustomData_set_layer_active(fdata, CD_MCOL, value);
- mesh_update_customdata_pointers(me);
+ rna_CustomDataLayer_active_set(ptr, rna_mesh_fdata(ptr), value, CD_MCOL, 1);
}
-static void rna_Mesh_active_vertex_color_index_range(PointerRNA *ptr, int *min, int *max)
+static void rna_MeshColorLayer_active_set(PointerRNA *ptr, int value)
{
- Mesh *me= (Mesh*)ptr->data;
- CustomData *fdata= rna_mesh_fdata(me);
-
- *min= 0;
- *max= CustomData_number_of_layers(fdata, CD_MCOL)-1;
- *max= MAX2(0, *max);
+ rna_CustomDataLayer_active_set(ptr, rna_mesh_fdata(ptr), value, CD_MCOL, 0);
}
-static void rna_MeshColorLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_color, ldata, CD_MLOOPCOL)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(vertex_color, ldata, CD_MLOOPCOL, active, MeshLoopColorLayer)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(vertex_color, ldata, CD_MLOOPCOL, render, MeshLoopColorLayer)
+
+static void rna_MeshLoopColorLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->id.data;
+ Mesh *me = rna_mesh(ptr);
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)
+static int rna_MeshLoopColorLayer_data_length(PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->id.data;
- return (me->edit_mesh)? 0: me->totface;
+ Mesh *me = rna_mesh(ptr);
+ return me->totloop;
}
-static int rna_MeshColorLayer_active_render_get(PointerRNA *ptr)
+static int rna_MeshLoopColorLayer_active_render_get(PointerRNA *ptr)
{
- return rna_CustomDataLayer_active_get(ptr, CD_MCOL, 1);
+ return rna_CustomDataLayer_active_get(ptr, rna_mesh_ldata(ptr), CD_MLOOPCOL, 1);
}
-static int rna_MeshColorLayer_active_get(PointerRNA *ptr)
+static int rna_MeshLoopColorLayer_active_get(PointerRNA *ptr)
{
- return rna_CustomDataLayer_active_get(ptr, CD_MCOL, 0);
+ return rna_CustomDataLayer_active_get(ptr, rna_mesh_ldata(ptr), CD_MLOOPCOL, 0);
}
-static void rna_MeshColorLayer_active_render_set(PointerRNA *ptr, int value)
+static void rna_MeshLoopColorLayer_active_render_set(PointerRNA *ptr, int value)
{
- rna_CustomDataLayer_active_set(ptr, value, CD_MCOL, 1);
+ rna_CustomDataLayer_active_set(ptr, rna_mesh_ldata(ptr), value, CD_MLOOPCOL, 1);
}
-static void rna_MeshColorLayer_active_set(PointerRNA *ptr, int value)
+static void rna_MeshLoopColorLayer_active_set(PointerRNA *ptr, int value)
{
- rna_CustomDataLayer_active_set(ptr, value, CD_MCOL, 0);
+ rna_CustomDataLayer_active_set(ptr, rna_mesh_ldata(ptr), value, CD_MLOOPCOL, 0);
}
-static void rna_MeshColorLayer_name_set(PointerRNA *ptr, const char *value)
+static void rna_MeshLoopColorLayer_name_set(PointerRNA *ptr, const char *value)
{
- Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
+ /* Mesh *me = rna_mesh(ptr); */ /* UNUSED */
+ /* CustomData *pdata = rna_mesh_pdata(ptr); */ /* UNUSED */
CustomDataLayer *cdl= (CustomDataLayer*)ptr->data;
BLI_strncpy_utf8(cdl->name, value, sizeof(cdl->name));
- CustomData_set_layer_unique_name(fdata, cdl - fdata->layers);
+ CustomData_set_layer_unique_name(rna_mesh_ldata(ptr), cdl - rna_mesh_ldata(ptr)->layers);
}
static void rna_MeshFloatPropertyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->id.data;
+ Mesh *me = rna_mesh(ptr);
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;
+ Mesh *me = rna_mesh(ptr);
+ return me->totface;
}
-static int rna_float_layer_check(CollectionPropertyIterator *UNUSED(iter), void *data)
+static int rna_float_layer_check(CollectionPropertyIterator *iter, void *data)
{
CustomDataLayer *layer= (CustomDataLayer*)data;
return (layer->type != CD_PROP_FLT);
@@ -845,17 +760,16 @@ static int rna_float_layer_check(CollectionPropertyIterator *UNUSED(iter), void
static void rna_Mesh_float_layers_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_float_layer_check);
+ CustomData *pdata = rna_mesh_pdata(ptr);
+ rna_iterator_array_begin(iter, (void*)pdata->layers, sizeof(CustomDataLayer), pdata->totlayer, 0, rna_float_layer_check);
}
static int rna_Mesh_float_layers_length(PointerRNA *ptr)
{
- return rna_CustomDataLayer_length(ptr, CD_PROP_FLT);
+ return CustomData_number_of_layers(rna_mesh_pdata(ptr), CD_PROP_FLT);
}
-static int rna_int_layer_check(CollectionPropertyIterator *UNUSED(iter), void *data)
+static int rna_int_layer_check(CollectionPropertyIterator *iter, void *data)
{
CustomDataLayer *layer= (CustomDataLayer*)data;
return (layer->type != CD_PROP_INT);
@@ -863,30 +777,29 @@ static int rna_int_layer_check(CollectionPropertyIterator *UNUSED(iter), void *d
static void rna_MeshIntPropertyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->id.data;
+ Mesh *me = rna_mesh(ptr);
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;
+ Mesh *me = rna_mesh(ptr);
+ 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);
- rna_iterator_array_begin(iter, (void*)fdata->layers, sizeof(CustomDataLayer), fdata->totlayer, 0, rna_int_layer_check);
+ CustomData *pdata = rna_mesh_pdata(ptr);
+ rna_iterator_array_begin(iter, (void*)pdata->layers, sizeof(CustomDataLayer), pdata->totlayer, 0, rna_int_layer_check);
}
static int rna_Mesh_int_layers_length(PointerRNA *ptr)
{
- return rna_CustomDataLayer_length(ptr, CD_PROP_INT);
+ return CustomData_number_of_layers(rna_mesh_pdata(ptr), CD_PROP_INT);
}
-static int rna_string_layer_check(CollectionPropertyIterator *UNUSED(iter), void *data)
+static int rna_string_layer_check(CollectionPropertyIterator *iter, void *data)
{
CustomDataLayer *layer= (CustomDataLayer*)data;
return (layer->type != CD_PROP_STR);
@@ -894,32 +807,31 @@ static int rna_string_layer_check(CollectionPropertyIterator *UNUSED(iter), void
static void rna_MeshStringPropertyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->id.data;
+ Mesh *me = rna_mesh(ptr);
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;
+ Mesh *me = rna_mesh(ptr);
+ 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);
- rna_iterator_array_begin(iter, (void*)fdata->layers, sizeof(CustomDataLayer), fdata->totlayer, 0, rna_string_layer_check);
+ CustomData *pdata = rna_mesh_pdata(ptr);
+ rna_iterator_array_begin(iter, (void*)pdata->layers, sizeof(CustomDataLayer), pdata->totlayer, 0, rna_string_layer_check);
}
static int rna_Mesh_string_layers_length(PointerRNA *ptr)
{
- return rna_CustomDataLayer_length(ptr, CD_PROP_STR);
+ return CustomData_number_of_layers(rna_mesh_pdata(ptr), CD_PROP_STR);
}
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) {
@@ -936,7 +848,7 @@ static void rna_TextureFace_image_set(PointerRNA *ptr, PointerRNA value)
static void rna_Mesh_auto_smooth_angle_set(PointerRNA *ptr, float value)
{
- Mesh *me= (Mesh*)ptr->id.data;
+ Mesh *me = rna_mesh(ptr);
value= RAD2DEGF(value);
CLAMP(value, 1.0f, 80.0f);
me->smoothresh= (int)value;
@@ -944,7 +856,7 @@ static void rna_Mesh_auto_smooth_angle_set(PointerRNA *ptr, float value)
static float rna_Mesh_auto_smooth_angle_get(PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->id.data;
+ Mesh *me = rna_mesh(ptr);
return DEG2RADF((float)me->smoothresh);
}
@@ -972,94 +884,165 @@ static void rna_MeshFace_verts_set(PointerRNA *ptr, const int *values)
memcpy(&face->v1, values, (face->v4 ? 4 : 3) * sizeof(int));
}
+/* poly.vertices - this is faked loop access for convenience */
+static int rna_MeshPoly_vertices_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ MPoly *mp= (MPoly*)ptr->data;
+ /* note, raw access uses dummy item, this _could_ crash, watch out for this, mface uses it but it cant work here */
+ return (length[0]= mp->totloop);
+}
+
+static void rna_MeshPoly_vertices_get(PointerRNA *ptr, int *values)
+{
+ Mesh *me = rna_mesh(ptr);
+ MPoly *mp= (MPoly*)ptr->data;
+ MLoop *ml= &me->mloop[mp->loopstart];
+ unsigned int i;
+ for(i= mp->totloop; i > 0; i--, values++, ml++) {
+ *values = ml->v;
+ }
+}
+
+static void rna_MeshPoly_vertices_set(PointerRNA *ptr, const int *values)
+{
+ Mesh *me = rna_mesh(ptr);
+ MPoly *mp= (MPoly*)ptr->data;
+ MLoop *ml= &me->mloop[mp->loopstart];
+ unsigned int i;
+ for(i= mp->totloop; i > 0; i--, values++, ml++) {
+ ml->v = *values;
+ }
+}
+
+
static int rna_MeshVertex_index_get(PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->id.data;
+ Mesh *me = rna_mesh(ptr);
MVert *vert= (MVert*)ptr->data;
return (int)(vert - me->mvert);
}
static int rna_MeshEdge_index_get(PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->id.data;
+ Mesh *me = rna_mesh(ptr);
MEdge *edge= (MEdge*)ptr->data;
return (int)(edge - me->medge);
}
static int rna_MeshFace_index_get(PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->id.data;
+ Mesh *me = rna_mesh(ptr);
MFace *face= (MFace*)ptr->data;
return (int)(face - me->mface);
}
+static int rna_MeshPolygon_index_get(PointerRNA *ptr)
+{
+ Mesh *me = rna_mesh(ptr);
+ MPoly *mpoly= (MPoly*)ptr->data;
+ return (int)(mpoly - me->mpoly);
+}
+
/* path construction */
static char *rna_VertexGroupElement_path(PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->id.data; /* XXX not always! */
+ Mesh *me = rna_mesh(ptr); /* XXX not always! */
MDeformWeight *dw= (MDeformWeight*)ptr->data;
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_MeshPolygon_path(PointerRNA *ptr)
+{
+ return BLI_sprintfN("polygons[%d]", (int)((MPoly*)ptr->data - rna_mesh(ptr)->mpoly));
+}
+
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]", (int)((MFace*)ptr->data - rna_mesh(ptr)->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]", (int)((MEdge*)ptr->data - rna_mesh(ptr)->medge));
+}
+
+static char *rna_MeshLoop_path(PointerRNA *ptr)
+{
+ return BLI_sprintfN("loops[%d]", (int)((MLoop*)ptr->data - rna_mesh(ptr)->mloop));
}
+
static char *rna_MeshVertex_path(PointerRNA *ptr)
{
- return BLI_sprintfN("vertices[%d]", (int)((MVert*)ptr->data - ((Mesh*)ptr->id.data)->mvert));
+ return BLI_sprintfN("vertices[%d]", (int)((MVert*)ptr->data - rna_mesh(ptr)->mvert));
}
static char *rna_MeshTextureFaceLayer_path(PointerRNA *ptr)
{
+ return BLI_sprintfN("tessface_uv_textures[\"%s\"]", ((CustomDataLayer*)ptr->data)->name);
+}
+
+static char *rna_MeshTexturePolyLayer_path(PointerRNA *ptr)
+{
return BLI_sprintfN("uv_textures[\"%s\"]", ((CustomDataLayer*)ptr->data)->name);
}
-static char *rna_CustomDataData_path(PointerRNA *ptr, char *collection, int type)
+static char *rna_PolyCustomData_data_path(PointerRNA *ptr, char *collection, int type)
{
- Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
CustomDataLayer *cdl;
- int a, b;
+ Mesh *me = rna_mesh(ptr);
+ CustomData *pdata = rna_mesh_pdata(ptr);
+ int a, b, totpoly = (me->edit_btmesh) ? 0 : me->totpoly;
+
+ for(cdl=pdata->layers, a=0; a<pdata->totlayer; cdl++, a++) {
+ if(cdl->type == type) {
+ b= ((char*)ptr->data - ((char*)cdl->data))/CustomData_sizeof(type);
+ if(b >= 0 && b < totpoly)
+ return BLI_sprintfN("%s[\"%s\"].data[%d]", collection, cdl->name, b);
+ }
+ }
+
+ return NULL;
+}
+
+static char *rna_LoopCustomData_data_path(PointerRNA *ptr, char *collection, int type)
+{
+ CustomDataLayer *cdl;
+ Mesh *me = rna_mesh(ptr);
+ CustomData *ldata = rna_mesh_ldata(ptr);
+ int a, b, totloop = (me->edit_btmesh) ? 0 : me->totloop;
+
+ for(cdl=ldata->layers, a=0; a<ldata->totlayer; cdl++, a++) {
+ if(cdl->type == type) {
+ b= ((char*)ptr->data - ((char*)cdl->data))/CustomData_sizeof(type);
+ if(b >= 0 && b < totloop)
+ return BLI_sprintfN("%s[\"%s\"].data[%d]", collection, cdl->name, b);
+ }
+ }
+
+ return NULL;
+}
+
+static char *rna_FaceCustomData_data_path(PointerRNA *ptr, char *collection, int type)
+{
+ CustomDataLayer *cdl;
+ Mesh *me = rna_mesh(ptr);
+ CustomData *fdata = rna_mesh_fdata(ptr);
+ int a, b, totloop = (me->edit_btmesh) ? 0 : me->totloop;
for(cdl=fdata->layers, a=0; a<fdata->totlayer; cdl++, a++) {
if(cdl->type == type) {
b= ((char*)ptr->data - ((char*)cdl->data))/CustomData_sizeof(type);
- if(b >= 0 && b < me->totface)
+ if(b >= 0 && b < totloop)
return BLI_sprintfN("%s[\"%s\"].data[%d]", collection, cdl->name, b);
}
}
@@ -1067,24 +1050,39 @@ static char *rna_CustomDataData_path(PointerRNA *ptr, char *collection, int type
return NULL;
}
+static char *rna_MeshUVLoop_path(PointerRNA *ptr)
+{
+ return rna_LoopCustomData_data_path(ptr, "uv_loop_layers", CD_MLOOPUV);
+}
+
static char *rna_MeshTextureFace_path(PointerRNA *ptr)
{
- return rna_CustomDataData_path(ptr, "uv_textures", CD_MTFACE);
+ return rna_FaceCustomData_data_path(ptr, "tessface_uv_textures", CD_MTFACE);
+}
+
+static char *rna_MeshTexturePoly_path(PointerRNA *ptr)
+{
+ return rna_PolyCustomData_data_path(ptr, "uv_textures", CD_MTEXPOLY);
}
static char *rna_MeshColorLayer_path(PointerRNA *ptr)
{
+ return BLI_sprintfN("tessface_vertex_colors[\"%s\"]", ((CustomDataLayer*)ptr->data)->name);
+}
+
+static char *rna_MeshLoopColorLayer_path(PointerRNA *ptr)
+{
return BLI_sprintfN("vertex_colors[\"%s\"]", ((CustomDataLayer*)ptr->data)->name);
}
static char *rna_MeshColor_path(PointerRNA *ptr)
{
- return rna_CustomDataData_path(ptr, "vertex_colors", CD_MCOL);
+ return rna_LoopCustomData_data_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]", (int)((MSticky*)ptr->data - rna_mesh(ptr)->msticky));
}
static char *rna_MeshIntPropertyLayer_path(PointerRNA *ptr)
@@ -1094,7 +1092,7 @@ static char *rna_MeshIntPropertyLayer_path(PointerRNA *ptr)
static char *rna_MeshIntProperty_path(PointerRNA *ptr)
{
- return rna_CustomDataData_path(ptr, "layers_int", CD_MCOL);
+ return rna_PolyCustomData_data_path(ptr, "layers_int", CD_PROP_INT);
}
static char *rna_MeshFloatPropertyLayer_path(PointerRNA *ptr)
@@ -1104,7 +1102,7 @@ static char *rna_MeshFloatPropertyLayer_path(PointerRNA *ptr)
static char *rna_MeshFloatProperty_path(PointerRNA *ptr)
{
- return rna_CustomDataData_path(ptr, "layers_float", CD_MCOL);
+ return rna_PolyCustomData_data_path(ptr, "layers_float", CD_PROP_FLT);
}
static char *rna_MeshStringPropertyLayer_path(PointerRNA *ptr)
@@ -1114,38 +1112,38 @@ static char *rna_MeshStringPropertyLayer_path(PointerRNA *ptr)
static char *rna_MeshStringProperty_path(PointerRNA *ptr)
{
- return rna_CustomDataData_path(ptr, "layers_string", CD_MCOL);
+ return rna_PolyCustomData_data_path(ptr, "layers_string", CD_PROP_STR);
}
static int rna_Mesh_tot_vert_get(PointerRNA *ptr)
{
- Mesh *me= (Mesh*)ptr->id.data;
- return me->edit_mesh ? me->edit_mesh->totvertsel : 0;
+ Mesh *me = rna_mesh(ptr);
+ 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;
+ Mesh *me = rna_mesh(ptr);
+ 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;
+ Mesh *me = rna_mesh(ptr);
+ return me->edit_btmesh ? me->edit_btmesh->bm->totfacesel : 0;
}
static PointerRNA rna_Mesh_vertex_color_new(struct Mesh *me, struct bContext *C, const char *name)
{
PointerRNA ptr;
- CustomData *fdata;
+ CustomData *ldata;
CustomDataLayer *cdl= NULL;
int index= ED_mesh_color_add(C, NULL, NULL, me, name, FALSE);
if(index != -1) {
- fdata= rna_mesh_fdata(me);
- cdl= &fdata->layers[CustomData_get_layer_index_n(fdata, CD_MCOL, index)];
+ ldata= rna_mesh_ldata_helper(me);
+ cdl= &ldata->layers[CustomData_get_layer_index_n(ldata, CD_MLOOPCOL, index)];
}
- RNA_pointer_create(&me->id, &RNA_MeshColorLayer, cdl, &ptr);
+ RNA_pointer_create(&me->id, &RNA_MeshLoopColorLayer, cdl, &ptr);
return ptr;
}
@@ -1197,16 +1195,16 @@ static PointerRNA rna_Mesh_string_property_new(struct Mesh *me, struct bContext
static PointerRNA rna_Mesh_uv_texture_new(struct Mesh *me, struct bContext *C, const char *name)
{
PointerRNA ptr;
- CustomData *fdata;
+ CustomData *pdata;
CustomDataLayer *cdl= NULL;
- int index= ED_mesh_uv_texture_add(C, me, name, FALSE);
+ int index = ED_mesh_uv_texture_add(C, me, name, FALSE);
if(index != -1) {
- fdata= rna_mesh_fdata(me);
- cdl= &fdata->layers[CustomData_get_layer_index_n(fdata, CD_MTFACE, index)];
+ pdata= rna_mesh_pdata_helper(me);
+ cdl= &pdata->layers[CustomData_get_layer_index_n(pdata, CD_MTEXPOLY, index)];
}
- RNA_pointer_create(&me->id, &RNA_MeshTextureFaceLayer, cdl, &ptr);
+ RNA_pointer_create(&me->id, &RNA_MeshTexturePolyLayer, cdl, &ptr);
return ptr;
}
@@ -1275,8 +1273,7 @@ static void rna_def_mvert(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop= RNA_def_property(srna, "groups", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_funcs(prop, "rna_MeshVertex_groups_begin", "rna_iterator_array_next",
- "rna_iterator_array_end", "rna_iterator_array_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_collection_funcs(prop, "rna_MeshVertex_groups_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", NULL, NULL, NULL, NULL);
RNA_def_property_struct_type(prop, "VertexGroupElement");
RNA_def_property_ui_text(prop, "Groups", "Weights for the vertex groups this vertex is member of");
@@ -1408,12 +1405,12 @@ static void rna_def_mface(BlenderRNA *brna)
RNA_def_property_range(prop, -1.0f, 1.0f);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_MeshFace_normal_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Face normal", "Local space unit length normal vector for this face");
+ RNA_def_property_ui_text(prop, "face normal", "local space unit length normal vector for this face");
prop= RNA_def_property(srna, "area", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_MeshFace_area_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Face area", "Read only area of the face");
+ RNA_def_property_ui_text(prop, "face area", "read only area of the face");
prop= RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1421,6 +1418,129 @@ static void rna_def_mface(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Index", "Index number of the vertex");
}
+
+static void rna_def_mloop(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna= RNA_def_struct(brna, "MeshLoop", NULL);
+ RNA_def_struct_sdna(srna, "MLoop");
+ RNA_def_struct_ui_text(srna, "Mesh Loop", "Loop in a Mesh datablock");
+ RNA_def_struct_path_func(srna, "rna_MeshLoop_path");
+ RNA_def_struct_ui_icon(srna, ICON_EDGESEL);
+
+ prop= RNA_def_property(srna, "vertex_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "v");
+ RNA_def_property_ui_text(prop, "Vertex", "Vertex index");
+
+ prop= RNA_def_property(srna, "edge_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "e");
+ RNA_def_property_ui_text(prop, "Edge", "Edge index");
+}
+
+static void rna_def_mpolygon(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna= RNA_def_struct(brna, "MeshPolygon", NULL);
+ RNA_def_struct_sdna(srna, "MPoly");
+ RNA_def_struct_ui_text(srna, "Mesh Polygon", "Polygon in a Mesh datablock");
+ RNA_def_struct_path_func(srna, "rna_MeshPolygon_path");
+ RNA_def_struct_ui_icon(srna, ICON_FACESEL);
+
+ /* faked, actually access to loop vertex values, dont this way because manually setting up vertex/edge per loop is very low level
+ * instead we setup poly sizes, assign indicies, then calc edges automatic when creating meshes from rna/py */
+ prop= RNA_def_property(srna, "vertices", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_array(prop, 3); // eek, this is still used in some cases but infact we dont want to use it at all here.
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_MeshPoly_vertices_get_length");
+ RNA_def_property_int_funcs(prop, "rna_MeshPoly_vertices_get", "rna_MeshPoly_vertices_set", NULL);
+ RNA_def_property_ui_text(prop, "Vertices", "Vertex indices");
+
+ /* these are both very low level access */
+ prop= RNA_def_property(srna, "loop_start", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "loopstart");
+ RNA_def_property_ui_text(prop, "Loop Start", "");
+ /* also low level */
+ prop= RNA_def_property(srna, "loop_total", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "totloop");
+ RNA_def_property_ui_text(prop, "Loop Total", "");
+
+ prop= RNA_def_property(srna, "material_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "mat_nr");
+ RNA_def_property_ui_text(prop, "Material Index", "");
+ RNA_def_property_int_funcs(prop, NULL, NULL, "rna_MeshFace_material_index_range");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_FACE_SEL);
+ RNA_def_property_ui_text(prop, "Select", "");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_select");
+
+ prop= RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_HIDE);
+ RNA_def_property_ui_text(prop, "Hide", "");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_select");
+
+ prop= RNA_def_property(srna, "use_smooth", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SMOOTH);
+ RNA_def_property_ui_text(prop, "Smooth", "");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_property(srna, "normal", PROP_FLOAT, PROP_DIRECTION);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, -1.0f, 1.0f);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_MeshPolygon_normal_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "face normal", "local space unit length normal vector for this polygon");
+
+ prop= RNA_def_property(srna, "area", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_MeshPolygon_area_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "face area", "read only area of the face");
+
+ prop= RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_int_funcs(prop, "rna_MeshPolygon_index_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Index", "Index number of the vertex");
+}
+
+/* mesh.loop_uvs */
+static void rna_def_mloopuv(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna= RNA_def_struct(brna, "MeshUVLoopLayer", NULL);
+ RNA_def_struct_sdna(srna, "CustomDataLayer");
+ RNA_def_struct_path_func(srna, "rna_MeshUVLoopLayer_path");
+
+ prop= RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MeshUVLoop");
+ RNA_def_property_collection_funcs(prop, "rna_MeshUVLoopLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshUVLoopLayer_data_length", NULL, NULL, NULL);
+
+ srna= RNA_def_struct(brna, "MeshUVLoop", NULL);
+ RNA_def_struct_sdna(srna, "MLoopUV");
+ RNA_def_struct_path_func(srna, "rna_MeshUVLoop_path");
+
+ prop= RNA_def_property(srna, "uv", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_property(srna, "pin_uv", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MLOOPUV_PINNED);
+ RNA_def_property_ui_text(prop, "UV Pinned", "");
+
+ prop= RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MLOOPUV_VERTSEL);
+ RNA_def_property_ui_text(prop, "UV Select", "");
+
+ prop= RNA_def_property(srna, "select_edge", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MLOOPUV_EDGESEL);
+ RNA_def_property_ui_text(prop, "UV Edge Select", "");
+}
+
static void rna_def_mtface(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1473,7 +1593,6 @@ static void rna_def_mtface(BlenderRNA *brna)
prop= RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "tpage");
RNA_def_property_pointer_funcs(prop, NULL, "rna_TextureFace_image_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Image", "");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
@@ -1528,6 +1647,81 @@ static void rna_def_mtface(BlenderRNA *brna)
}
+static void rna_def_mtexpoly(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+#if 0 /* BMESH_TODO: needed later when do another todo */
+ int uv_dim[]= {4, 2};
+#endif
+
+ srna= RNA_def_struct(brna, "MeshTexturePolyLayer", NULL);
+ RNA_def_struct_ui_text(srna, "Mesh UV Map", "UV map with assigned image textures in a Mesh datablock");
+ RNA_def_struct_sdna(srna, "CustomDataLayer");
+ RNA_def_struct_path_func(srna, "rna_MeshTexturePolyLayer_path");
+ RNA_def_struct_ui_icon(srna, ICON_GROUP_UVS);
+
+ prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshTexturePolyLayer_name_set");
+ RNA_def_property_ui_text(prop, "Name", "Name of UV map");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_MeshTexturePolyLayer_active_get", "rna_MeshTexturePolyLayer_active_set");
+ RNA_def_property_ui_text(prop, "Active", "Set the map as active for display and editing");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_property(srna, "active_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "active_rnd", 0);
+ RNA_def_property_boolean_funcs(prop, "rna_MeshTexturePolyLayer_active_render_get", "rna_MeshTexturePolyLayer_active_render_set");
+ RNA_def_property_ui_text(prop, "Active Render", "Set the map as active for rendering");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_property(srna, "active_clone", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "active_clone", 0);
+ RNA_def_property_boolean_funcs(prop, "rna_MeshTexturePolyLayer_clone_get", "rna_MeshTexturePolyLayer_clone_set");
+ RNA_def_property_ui_text(prop, "Active Clone", "Set the map as active for cloning");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MeshTexturePoly");
+ RNA_def_property_ui_text(prop, "Data", "");
+ RNA_def_property_collection_funcs(prop, "rna_MeshTexturePolyLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshTexturePolyLayer_data_length", NULL, NULL, NULL);
+
+ srna= RNA_def_struct(brna, "MeshTexturePoly", NULL);
+ RNA_def_struct_sdna(srna, "MTexPoly");
+ RNA_def_struct_ui_text(srna, "Mesh UV Map Face", "UV map and image texture for a face");
+ RNA_def_struct_path_func(srna, "rna_MeshTexturePoly_path");
+ RNA_def_struct_ui_icon(srna, ICON_FACESEL_HLT);
+
+ prop= RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "tpage");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_TextureFace_image_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Image", "");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_property(srna, "select_uv", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", TF_SEL1);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "UV Selected", "");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_select");
+
+#if 0 /* moved to MeshUVLoopLayer */
+ 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, "uv_raw", PROP_FLOAT, PROP_NONE);
+ 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)
{
StructRNA *srna;
@@ -1556,7 +1750,7 @@ static void rna_def_mcol(BlenderRNA *brna)
prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_struct_name_property(srna, prop);
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshColorLayer_name_set");
+ RNA_def_property_string_funcs(prop, NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Name", "Name of Vertex color layer");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
@@ -1574,9 +1768,7 @@ static void rna_def_mcol(BlenderRNA *brna)
prop= RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshColor");
RNA_def_property_ui_text(prop, "Data", "");
- RNA_def_property_collection_funcs(prop, "rna_MeshColorLayer_data_begin", "rna_iterator_array_next",
- "rna_iterator_array_end", "rna_iterator_array_get",
- "rna_MeshColorLayer_data_length", NULL, NULL, NULL);
+ RNA_def_property_collection_funcs(prop, "rna_MeshColorLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshColorLayer_data_length", NULL, NULL, NULL);
srna= RNA_def_struct(brna, "MeshColor", NULL);
RNA_def_struct_sdna(srna, "MCol");
@@ -1612,6 +1804,53 @@ static void rna_def_mcol(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
}
+static void rna_def_mloopcol(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna= RNA_def_struct(brna, "MeshLoopColorLayer", NULL);
+ RNA_def_struct_ui_text(srna, "Mesh Vertex Color Layer", "Layer of vertex colors in a Mesh datablock");
+ RNA_def_struct_sdna(srna, "CustomDataLayer");
+ RNA_def_struct_path_func(srna, "rna_MeshLoopColorLayer_path");
+ RNA_def_struct_ui_icon(srna, ICON_GROUP_VCOL);
+
+ prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshLoopColorLayer_name_set");
+ RNA_def_property_ui_text(prop, "Name", "Name of Vertex color layer");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_MeshLoopColorLayer_active_get", "rna_MeshLoopColorLayer_active_set");
+ RNA_def_property_ui_text(prop, "Active", "Sets the layer as active for display and editing");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_property(srna, "active_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "active_rnd", 0);
+ RNA_def_property_boolean_funcs(prop, "rna_MeshLoopColorLayer_active_render_get", "rna_MeshLoopColorLayer_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);
+ RNA_def_property_struct_type(prop, "MeshLoopColor");
+ RNA_def_property_ui_text(prop, "Data", "");
+ RNA_def_property_collection_funcs(prop, "rna_MeshLoopColorLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshLoopColorLayer_data_length", NULL, NULL, NULL);
+
+
+ srna= RNA_def_struct(brna, "MeshLoopColor", NULL);
+ RNA_def_struct_sdna(srna, "MLoopCol");
+ RNA_def_struct_ui_text(srna, "Mesh Vertex Color", "Vertex loop colors in a Mesh");
+ RNA_def_struct_path_func(srna, "rna_MeshColor_path");
+
+ prop= RNA_def_property(srna, "color", 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_MeshLoopColor_color_get", "rna_MeshLoopColor_color_set", NULL);
+ RNA_def_property_ui_text(prop, "Color", "");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+}
+
static void rna_def_mproperties(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1631,9 +1870,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
prop= RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshFloatProperty");
RNA_def_property_ui_text(prop, "Data", "");
- RNA_def_property_collection_funcs(prop, "rna_MeshFloatPropertyLayer_data_begin", "rna_iterator_array_next",
- "rna_iterator_array_end", "rna_iterator_array_get",
- "rna_MeshFloatPropertyLayer_data_length", NULL, NULL, NULL);
+ RNA_def_property_collection_funcs(prop, "rna_MeshFloatPropertyLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshFloatPropertyLayer_data_length", NULL, NULL, NULL);
srna= RNA_def_struct(brna, "MeshFloatProperty", NULL);
RNA_def_struct_sdna(srna, "MFloatProperty");
@@ -1659,9 +1896,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
prop= RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshIntProperty");
RNA_def_property_ui_text(prop, "Data", "");
- RNA_def_property_collection_funcs(prop, "rna_MeshIntPropertyLayer_data_begin", "rna_iterator_array_next",
- "rna_iterator_array_end", "rna_iterator_array_get",
- "rna_MeshIntPropertyLayer_data_length", NULL, NULL, NULL);
+ RNA_def_property_collection_funcs(prop, "rna_MeshIntPropertyLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshIntPropertyLayer_data_length", NULL, NULL, NULL);
srna= RNA_def_struct(brna, "MeshIntProperty", NULL);
RNA_def_struct_sdna(srna, "MIntProperty");
@@ -1687,9 +1922,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
prop= RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshStringProperty");
RNA_def_property_ui_text(prop, "Data", "");
- RNA_def_property_collection_funcs(prop, "rna_MeshStringPropertyLayer_data_begin", "rna_iterator_array_next",
- "rna_iterator_array_end", "rna_iterator_array_get",
- "rna_MeshStringPropertyLayer_data_length", NULL, NULL, NULL);
+ RNA_def_property_collection_funcs(prop, "rna_MeshStringPropertyLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshStringPropertyLayer_data_length", NULL, NULL, NULL);
srna= RNA_def_struct(brna, "MeshStringProperty", NULL);
RNA_def_struct_sdna(srna, "MStringProperty");
@@ -1703,6 +1936,45 @@ 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_location", 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", "");
+ RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */
+ RNA_def_property_collection_funcs(prop, 0, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int");
+}
+
+
+/* scene.objects */
/* mesh.vertices */
static void rna_def_mesh_vertices(BlenderRNA *brna, PropertyRNA *cprop)
{
@@ -1758,7 +2030,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);
@@ -1769,12 +2041,6 @@ 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 UV Map Face", "Active UV Map 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 faces to add", 0, INT_MAX);
@@ -1785,25 +2051,101 @@ static void rna_def_mesh_faces(BlenderRNA *brna, PropertyRNA *cprop)
#endif
}
-/* mesh.vertex_colors */
-static void rna_def_vertex_colors(BlenderRNA *brna, PropertyRNA *cprop)
+/* mesh.loops */
+static void rna_def_mesh_loops(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+
+ /*PropertyRNA *prop;*/
+
+ FunctionRNA *func;
+ /*PropertyRNA *parm;*/
+
+ RNA_def_property_srna(cprop, "MeshLoops");
+ srna= RNA_def_struct(brna, "MeshLoops", NULL);
+ RNA_def_struct_sdna(srna, "Mesh");
+ RNA_def_struct_ui_text(srna, "Mesh Loops", "Collection of mesh loops");
+
+#if 0 // BMESH_TODO
+ prop= RNA_def_property(srna, "active", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "act_face");
+ RNA_def_property_ui_text(prop, "Active Polygon", "The active polygon for this mesh");
+#endif
+
+ func= RNA_def_function(srna, "add", "ED_mesh_loops_add");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of loops to add", 0, INT_MAX);
+}
+
+/* mesh.polygons */
+static void rna_def_mesh_polygons(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
+
PropertyRNA *prop;
FunctionRNA *func;
PropertyRNA *parm;
+ RNA_def_property_srna(cprop, "MeshPolygons");
+ srna= RNA_def_struct(brna, "MeshPolygons", NULL);
+ RNA_def_struct_sdna(srna, "Mesh");
+ RNA_def_struct_ui_text(srna, "Mesh Polygons", "Collection of mesh polygons");
+
+ prop= RNA_def_property(srna, "active", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "act_face");
+ RNA_def_property_ui_text(prop, "Active Polygon", "The active polygon for this mesh");
+
+ func= RNA_def_function(srna, "add", "ED_mesh_polys_add");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm= RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of polygons to add", 0, INT_MAX);
+}
+
+
+/* mesh.vertex_colors */
+static void rna_def_tessface_vertex_colors(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ //FunctionRNA *func;
+ //PropertyRNA *parm;
+
RNA_def_property_srna(cprop, "VertexColors");
srna= RNA_def_struct(brna, "VertexColors", NULL);
RNA_def_struct_sdna(srna, "Mesh");
RNA_def_struct_ui_text(srna, "Vertex Colors", "Collection of vertex colors");
+ prop= RNA_def_property(srna, "active", PROP_POINTER, PROP_UNSIGNED);
+ RNA_def_property_struct_type(prop, "MeshColorLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_Mesh_tessface_vertex_color_active_get", "rna_Mesh_tessface_vertex_color_active_set", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Active Vertex Color Layer", "Active vertex color layer");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_Mesh_tessface_vertex_color_active_index_get", "rna_Mesh_tessface_vertex_color_active_index_set", "rna_Mesh_vertex_color_index_range");
+ RNA_def_property_ui_text(prop, "Active Vertex Color Index", "Active vertex color index");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+}
+
+static void rna_def_loop_colors(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "LoopColors");
+ srna= RNA_def_struct(brna, "LoopColors", NULL);
+ RNA_def_struct_sdna(srna, "Mesh");
+ RNA_def_struct_ui_text(srna, "Loop Colors", "Collection of vertex colors");
+
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_pointer(func, "layer", "MeshColorLayer", "", "The newly created layer");
+ parm= RNA_def_pointer(func, "layer", "MeshLoopColorLayer", "", "The newly created layer");
RNA_def_property_flag(parm, PROP_RNAPTR);
RNA_def_function_return(func, parm);
@@ -1815,18 +2157,44 @@ static void rna_def_vertex_colors(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_flag(parm, PROP_REQUIRED|PROP_NEVER_NULL);
*/
prop= RNA_def_property(srna, "active", PROP_POINTER, PROP_UNSIGNED);
- RNA_def_property_struct_type(prop, "MeshColorLayer");
- RNA_def_property_pointer_funcs(prop, "rna_Mesh_active_vertex_color_get", "rna_Mesh_active_vertex_color_set", NULL, NULL);
+ RNA_def_property_struct_type(prop, "MeshLoopColorLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_Mesh_vertex_color_active_get", "rna_Mesh_vertex_color_active_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Active Vertex Color Layer", "Active vertex color layer");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop= RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop, "rna_Mesh_active_vertex_color_index_get", "rna_Mesh_active_vertex_color_index_set", "rna_Mesh_active_vertex_color_index_range");
+ RNA_def_property_int_funcs(prop, "rna_Mesh_vertex_color_active_index_get", "rna_Mesh_vertex_color_active_index_set", "rna_Mesh_vertex_color_index_range");
RNA_def_property_ui_text(prop, "Active Vertex Color Index", "Active vertex color index");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
}
+static void rna_def_uv_loop_layers(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ //FunctionRNA *func;
+ //PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "UVLoopLayers");
+ srna= RNA_def_struct(brna, "UVLoopLayers", NULL);
+ RNA_def_struct_sdna(srna, "Mesh");
+ RNA_def_struct_ui_text(srna, "UV Loop Layers", "Collection of uv loop layers");
+
+ prop= RNA_def_property(srna, "active", PROP_POINTER, PROP_UNSIGNED);
+ RNA_def_property_struct_type(prop, "MeshUVLoopLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_Mesh_uv_loop_layer_active_get", "rna_Mesh_uv_loop_layer_active_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Active UV loop layer", "Active UV loop layer");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_Mesh_uv_loop_layer_active_index_get", "rna_Mesh_uv_loop_layer_active_index_set", "rna_Mesh_uv_loop_layer_index_range");
+ RNA_def_property_ui_text(prop, "Active UV loop layer Index", "Active UV loop layer index");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+}
+
/* mesh int layers */
static void rna_def_int_layers(BlenderRNA *brna, PropertyRNA *cprop)
{
@@ -1894,6 +2262,32 @@ static void rna_def_string_layers(BlenderRNA *brna, PropertyRNA *cprop)
}
/* mesh.uv_layers */
+static void rna_def_tessface_uv_textures(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ //FunctionRNA *func;
+ //PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "TessfaceUVTextures");
+ srna= RNA_def_struct(brna, "TessfaceUVTextures", NULL);
+ RNA_def_struct_sdna(srna, "Mesh");
+ RNA_def_struct_ui_text(srna, "UV Maps", "Collection of UV maps for tesselated faces");
+
+ prop= RNA_def_property(srna, "active", PROP_POINTER, PROP_UNSIGNED);
+ RNA_def_property_struct_type(prop, "MeshTextureFaceLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_Mesh_tessface_uv_texture_active_get", "rna_Mesh_tessface_uv_texture_active_set", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Active UV Map", "Active UV Map");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_Mesh_tessface_uv_texture_active_index_get", "rna_Mesh_tessface_uv_texture_active_index_set", "rna_Mesh_uv_texture_index_range");
+ RNA_def_property_ui_text(prop, "Active UV Map Index", "Active UV Map index");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+}
+
+
static void rna_def_uv_textures(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@@ -1909,9 +2303,9 @@ 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_function_ui_description(func, "Add a UV map layer to Mesh");
RNA_def_string(func, "name", "UVMap", 0, "", "UV map name");
- parm= RNA_def_pointer(func, "layer", "MeshTextureFaceLayer", "", "The newly created layer");
+ parm= RNA_def_pointer(func, "layer", "MeshTexturePolyLayer", "", "The newly created layer");
RNA_def_property_flag(parm, PROP_RNAPTR);
RNA_def_function_return(func, parm);
@@ -1923,15 +2317,14 @@ static void rna_def_uv_textures(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_flag(parm, PROP_REQUIRED|PROP_NEVER_NULL);
*/
prop= RNA_def_property(srna, "active", PROP_POINTER, PROP_UNSIGNED);
- RNA_def_property_struct_type(prop, "MeshTextureFaceLayer");
- RNA_def_property_pointer_funcs(prop, "rna_Mesh_active_uv_texture_get", "rna_Mesh_active_uv_texture_set", NULL, NULL);
+ RNA_def_property_struct_type(prop, "MeshTexturePolyLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_Mesh_uv_texture_active_get", "rna_Mesh_uv_texture_active_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Active UV Map", "Active UV Map");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop= RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop, "rna_Mesh_active_uv_texture_index_get",
- "rna_Mesh_active_uv_texture_index_set", "rna_Mesh_active_uv_texture_index_range");
+ RNA_def_property_int_funcs(prop, "rna_Mesh_uv_texture_active_index_get", "rna_Mesh_uv_texture_active_index_set", "rna_Mesh_uv_texture_index_range");
RNA_def_property_ui_text(prop, "Active UV Map Index", "Active UV Map index");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
}
@@ -1963,6 +2356,18 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Faces", "Faces of the mesh");
rna_def_mesh_faces(brna, prop);
+ prop= RNA_def_property(srna, "loops", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "mloop", "totloop");
+ RNA_def_property_struct_type(prop, "MeshLoop");
+ RNA_def_property_ui_text(prop, "Loops", "Loops of the mesh");
+ rna_def_mesh_loops(brna, prop);
+
+ prop= RNA_def_property(srna, "polygons", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "mpoly", "totpoly");
+ RNA_def_property_struct_type(prop, "MeshPolygon");
+ RNA_def_property_ui_text(prop, "Polygons", "Polygons of the mesh");
+ rna_def_mesh_polygons(brna, prop);
+
prop= RNA_def_property(srna, "sticky", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "msticky", "totvert");
RNA_def_property_struct_type(prop, "MeshSticky");
@@ -1972,50 +2377,97 @@ 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 loop layers */
+ prop= RNA_def_property(srna, "uv_loop_layers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "ldata.layers", "ldata.totlayer");
+ RNA_def_property_collection_funcs(prop, "rna_Mesh_uv_loop_layers_begin", NULL, NULL, NULL,
+ "rna_Mesh_uv_loop_layers_length", NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "MeshUVLoopLayer");
+ RNA_def_property_ui_text(prop, "UV Loop Layers", "All UV loop layers");
+ rna_def_uv_loop_layers(brna, prop);
+
+ prop= RNA_def_property(srna, "uv_loop_layer_clone", PROP_POINTER, PROP_UNSIGNED);
+ RNA_def_property_struct_type(prop, "MeshUVLoopLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_Mesh_uv_loop_layer_clone_get", "rna_Mesh_uv_loop_layer_clone_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Clone UV loop layer", "UV loop layer to be used as cloning source");
- /* UV textures */
- prop= RNA_def_property(srna, "uv_textures", PROP_COLLECTION, PROP_NONE);
+ prop= RNA_def_property(srna, "uv_loop_layer_clone_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_Mesh_uv_loop_layer_clone_index_get", "rna_Mesh_uv_loop_layer_clone_index_set", "rna_Mesh_uv_loop_layer_index_range");
+ RNA_def_property_ui_text(prop, "Clone UV loop layer Index", "Clone UV loop layer index");
+
+ prop= RNA_def_property(srna, "uv_loop_layer_stencil", PROP_POINTER, PROP_UNSIGNED);
+ RNA_def_property_struct_type(prop, "MeshUVLoopLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_Mesh_uv_loop_layer_stencil_get", "rna_Mesh_uv_loop_layer_stencil_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Mask UV loop layer", "UV loop layer to mask the painted area");
+
+ prop= RNA_def_property(srna, "uv_loop_layer_stencil_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_Mesh_uv_loop_layer_stencil_index_get", "rna_Mesh_uv_loop_layer_stencil_index_set", "rna_Mesh_uv_loop_layer_index_range");
+ RNA_def_property_ui_text(prop, "Mask UV loop layer Index", "Mask UV loop layer index");
+
+ /* Tesselated face UV maps - used by renderers */
+ prop= RNA_def_property(srna, "tessface_uv_textures", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer");
+ RNA_def_property_collection_funcs(prop, "rna_Mesh_tessface_uv_textures_begin", NULL, NULL, NULL,
+ "rna_Mesh_tessface_uv_textures_length", NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "MeshTextureFaceLayer");
+ RNA_def_property_ui_text(prop, "Tesselated Face UV Maps", "All UV maps for tesselated faces (read-only, for use by renderers)");
+ rna_def_tessface_uv_textures(brna, prop);
+
+ /* UV maps */
+ prop= RNA_def_property(srna, "uv_textures", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "pdata.layers", "pdata.totlayer");
RNA_def_property_collection_funcs(prop, "rna_Mesh_uv_textures_begin", NULL, NULL, NULL,
"rna_Mesh_uv_textures_length", NULL, NULL, NULL);
- RNA_def_property_struct_type(prop, "MeshTextureFaceLayer");
- RNA_def_property_ui_text(prop, "UV Maps", "");
+ RNA_def_property_struct_type(prop, "MeshTexturePolyLayer");
+ RNA_def_property_ui_text(prop, "UV Maps", "All UV maps");
rna_def_uv_textures(brna, prop);
prop= RNA_def_property(srna, "uv_texture_clone", PROP_POINTER, PROP_UNSIGNED);
- RNA_def_property_struct_type(prop, "MeshTextureFaceLayer");
+ RNA_def_property_struct_type(prop, "MeshTexturePolyLayer");
RNA_def_property_pointer_funcs(prop, "rna_Mesh_uv_texture_clone_get", "rna_Mesh_uv_texture_clone_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Clone UV Map", "UV map to be used as cloning source");
prop= RNA_def_property(srna, "uv_texture_clone_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop, "rna_Mesh_uv_texture_clone_index_get",
- "rna_Mesh_uv_texture_clone_index_set", "rna_Mesh_active_uv_texture_index_range");
- RNA_def_property_ui_text(prop, "Clone UV Map Index", "Clone UV texture index");
+ RNA_def_property_int_funcs(prop, "rna_Mesh_uv_texture_clone_index_get", "rna_Mesh_uv_texture_clone_index_set", "rna_Mesh_uv_texture_index_range");
+ RNA_def_property_ui_text(prop, "Clone UV Map Index", "Clone UV map index");
prop= RNA_def_property(srna, "uv_texture_stencil", PROP_POINTER, PROP_UNSIGNED);
- RNA_def_property_struct_type(prop, "MeshTextureFaceLayer");
+ RNA_def_property_struct_type(prop, "MeshTexturePolyLayer");
RNA_def_property_pointer_funcs(prop, "rna_Mesh_uv_texture_stencil_get", "rna_Mesh_uv_texture_stencil_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Mask UV Map", "UV map to mask the painted area");
prop= RNA_def_property(srna, "uv_texture_stencil_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop, "rna_Mesh_uv_texture_stencil_index_get", "rna_Mesh_uv_texture_stencil_index_set", "rna_Mesh_active_uv_texture_index_range");
+ RNA_def_property_int_funcs(prop, "rna_Mesh_uv_texture_stencil_index_get", "rna_Mesh_uv_texture_stencil_index_set", "rna_Mesh_uv_texture_index_range");
RNA_def_property_ui_text(prop, "Mask UV Map Index", "Mask UV map index");
+ /* Tesselated face colors - used by renderers */
+
+ prop= RNA_def_property(srna, "tessface_vertex_colors", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer");
+ RNA_def_property_collection_funcs(prop, "rna_Mesh_tessface_vertex_colors_begin", NULL, NULL, NULL,
+ "rna_Mesh_tessface_vertex_colors_length", NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "MeshColorLayer");
+ RNA_def_property_ui_text(prop, "Tesselated Face Colors", "All tesselated face colors (read-only, for use by renderers)");
+ rna_def_tessface_vertex_colors(brna, prop);
+
/* 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", NULL, NULL, NULL,
"rna_Mesh_vertex_colors_length", NULL, NULL, NULL);
- RNA_def_property_struct_type(prop, "MeshColorLayer");
- RNA_def_property_ui_text(prop, "Vertex Colors", "");
- rna_def_vertex_colors(brna, prop);
+ RNA_def_property_struct_type(prop, "MeshLoopColorLayer");
+ RNA_def_property_ui_text(prop, "Vertex Colors", "All vertex colors");
+ rna_def_loop_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", NULL, NULL, NULL,
"rna_Mesh_float_layers_length", NULL, NULL, NULL);
RNA_def_property_struct_type(prop, "MeshFloatPropertyLayer");
@@ -2023,7 +2475,7 @@ static void rna_def_mesh(BlenderRNA *brna)
rna_def_float_layers(brna, prop);
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", NULL, NULL, NULL,
"rna_Mesh_int_layers_length", NULL, NULL, NULL);
RNA_def_property_struct_type(prop, "MeshIntPropertyLayer");
@@ -2031,7 +2483,7 @@ static void rna_def_mesh(BlenderRNA *brna)
rna_def_int_layers(brna, prop);
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", NULL, NULL, NULL,
"rna_Mesh_string_layers_length", NULL, NULL, NULL);
RNA_def_property_struct_type(prop, "MeshStringPropertyLayer");
@@ -2040,9 +2492,7 @@ static void rna_def_mesh(BlenderRNA *brna)
prop= RNA_def_property(srna, "use_auto_smooth", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_AUTOSMOOTH);
- RNA_def_property_ui_text(prop, "Auto Smooth",
- "Treat all set-smoothed faces with angles less than the "
- "specified angle as 'smooth' during render");
+ RNA_def_property_ui_text(prop, "Auto Smooth", "Treats all set-smoothed faces with angles less than the specified angle as 'smooth' during render");
#if 1 /* expose as radians */
prop= RNA_def_property(srna, "auto_smooth_angle", PROP_FLOAT, PROP_ANGLE);
@@ -2053,8 +2503,7 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "smoothresh");
RNA_def_property_range(prop, 1, 80);
#endif
- RNA_def_property_ui_text(prop, "Auto Smooth Angle",
- "Maximum angle between face normals that 'Auto Smooth' will operate on");
+ RNA_def_property_ui_text(prop, "Auto Smooth Angle", "Defines maximum angle between face normals that 'Auto Smooth' will operate on");
prop= RNA_def_property(srna, "show_double_sided", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_TWOSIDED);
@@ -2073,24 +2522,16 @@ static void rna_def_mesh(BlenderRNA *brna)
/* texture space */
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",
- "Adjust 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);
+ 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_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_float_funcs(prop, "rna_Mesh_texspace_loc_get", "rna_Mesh_texspace_loc_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);
RNA_def_property_float(prop, NULL, "rot");
@@ -2098,60 +2539,52 @@ static void rna_def_mesh(BlenderRNA *brna)
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 */
- RNA_def_property_collection_funcs(prop, 0, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int");
/* 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", "Display 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", "Display all edges for wireframe in all view modes in the 3D view");
+ 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);
- RNA_def_property_ui_text(prop, "Draw Faces", "Display all faces as shades in the 3D view and UV editor");
+ RNA_def_property_ui_text(prop, "Draw Faces", "Displays all faces as shades in the 3D view and UV editor");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop= RNA_def_property(srna, "show_normal_face", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWNORMALS);
- RNA_def_property_ui_text(prop, "Draw Normals", "Display face normals as lines");
+ RNA_def_property_ui_text(prop, "Draw Normals", "Displays face normals as lines");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop= RNA_def_property(srna, "show_normal_vertex", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAW_VNORMALS);
- RNA_def_property_ui_text(prop, "Draw Vertex Normals", "Display vertex normals as lines");
+ RNA_def_property_ui_text(prop, "Draw Vertex Normals", "Displays vertex normals as lines");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop= RNA_def_property(srna, "show_edge_crease", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWCREASES);
- RNA_def_property_ui_text(prop, "Draw Creases", "Display creases created for subsurf weighting");
+ RNA_def_property_ui_text(prop, "Draw Creases", "Displays creases created for subsurf weighting");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop= RNA_def_property(srna, "show_edge_bevel_weight", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWBWEIGHTS);
- RNA_def_property_ui_text(prop, "Draw Bevel Weights", "Display weights created for the Bevel modifier");
+ RNA_def_property_ui_text(prop, "Draw Bevel Weights", "Displays weights created for the Bevel modifier");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop= RNA_def_property(srna, "show_edge_seams", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWSEAMS);
- RNA_def_property_ui_text(prop, "Draw Seams", "Display UV unwrapping seams");
+ RNA_def_property_ui_text(prop, "Draw Seams", "Displays UV unwrapping seams");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop= RNA_def_property(srna, "show_edge_sharp", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWSHARP);
- RNA_def_property_ui_text(prop, "Draw Sharp", "Display sharp edges, used with the EdgeSplit modifier");
+ RNA_def_property_ui_text(prop, "Draw Sharp", "Displays sharp edges, used with the EdgeSplit modifier");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
prop= RNA_def_property(srna, "show_freestyle_edge_marks", PROP_BOOLEAN, PROP_NONE);
@@ -2166,21 +2599,17 @@ static void rna_def_mesh(BlenderRNA *brna)
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",
- "Display selected edge lengths, using global values when set in the transform panel");
+ 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);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEXTRA_FACEANG);
- RNA_def_property_ui_text(prop, "Faces Angles",
- "Display the angles between the selected edges in degrees, using "
- "global values when set in the transform panel");
+ RNA_def_property_ui_text(prop, "Face 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);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEXTRA_FACEAREA);
- RNA_def_property_ui_text(prop, "Face Area",
- "Display the area of selected faces, using global values when set in the transform panel");
+ 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, "show_extra_indices", PROP_BOOLEAN, PROP_NONE);
@@ -2205,8 +2634,7 @@ static void rna_def_mesh(BlenderRNA *brna)
prop= RNA_def_property(srna, "use_mirror_topology", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_TOPO);
- RNA_def_property_ui_text(prop, "Topology Mirror",
- "Use topology based mirroring (for when both sides of mesh have matching, unique topology)");
+ RNA_def_property_ui_text(prop, "Topology Mirror", "Use topology based mirroring. For when both sides of mesh have matching, unique topology");
prop= RNA_def_property(srna, "use_paint_mask", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_PAINT_MASK);
@@ -2238,6 +2666,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);
}
@@ -2249,9 +2678,14 @@ void RNA_def_mesh(BlenderRNA *brna)
rna_def_mvert_group(brna);
rna_def_medge(brna);
rna_def_mface(brna);
+ rna_def_mloop(brna);
+ rna_def_mpolygon(brna);
+ rna_def_mloopuv(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 0a93c9b05c5..9bee359bbf5 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -40,7 +40,15 @@
#include "ED_mesh.h"
#ifdef RNA_RUNTIME
-
+const char *rna_Mesh_unit_test_compare(struct Mesh *mesh, bContext *C, struct Mesh *mesh2)
+{
+ const char *ret = mesh_cmp(mesh, mesh2, FLT_EPSILON*60);
+
+ if (!ret)
+ ret = "Same";
+
+ return ret;
+}
#else
@@ -61,6 +69,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");
diff --git a/source/blender/makesrna/intern/rna_mesh_utils.h b/source/blender/makesrna/intern/rna_mesh_utils.h
new file mode 100644
index 00000000000..b946089b8d2
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_mesh_utils.h
@@ -0,0 +1,111 @@
+/*
+ * ***** 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.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Andrew Wiggin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/source/blender/makesrna/intern/rna_mesh_utils.h
+ * \ingroup RNA
+ */
+
+#ifndef __RNA_MESH_UTILS_H__
+#define __RNA_MESH_UTILS_H__
+
+/* Macros to help reduce code clutter in rna_mesh.c */
+
+/* Define the accessors for a basic CustomDataLayer collection */
+#define DEFINE_CUSTOMDATA_LAYER_COLLECTION(collection_name, customdata_type, layer_type) \
+ \
+ static int rna_##collection_name##_check(CollectionPropertyIterator *iter, void *data) \
+ { \
+ CustomDataLayer *layer= (CustomDataLayer*)data; \
+ return (layer->type != layer_type); \
+ } \
+ \
+ static void rna_Mesh_##collection_name##s_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) \
+ { \
+ CustomData *data = rna_mesh_##customdata_type(ptr); \
+ rna_iterator_array_begin(iter, (void*)data->layers, sizeof(CustomDataLayer), data->totlayer, 0, rna_##collection_name##_check); \
+ } \
+ \
+ static int rna_Mesh_##collection_name##s_length(PointerRNA *ptr) \
+ { \
+ CustomData *data = rna_mesh_##customdata_type(ptr); \
+ return data ? CustomData_number_of_layers(data, layer_type) : 0; \
+ } \
+ \
+ static void rna_Mesh_##collection_name##_index_range(PointerRNA *ptr, int *min, int *max) \
+ { \
+ CustomData *data= rna_mesh_##customdata_type(ptr); \
+ \
+ *min= 0; \
+ *max= data ? CustomData_number_of_layers(data, layer_type) - 1 : 0; \
+ *max= MAX2(0, *max); \
+ }
+
+/* Define the accessors for special CustomDataLayers in the collection
+ (active, render, clone, stencil, etc) */
+#define DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(collection_name, customdata_type, layer_type, active_type, layer_rna_type) \
+ \
+ static PointerRNA rna_Mesh_##collection_name##_##active_type##_get(PointerRNA *ptr) \
+ { \
+ CustomData *data = rna_mesh_##customdata_type(ptr); \
+ int index= CustomData_get_##active_type##_layer_index(data, layer_type); \
+ CustomDataLayer *cdl= (index == -1)? NULL: &data->layers[index]; \
+ \
+ return rna_pointer_inherit_refine(ptr, &RNA_##layer_rna_type, cdl); \
+ } \
+ \
+ static void rna_Mesh_##collection_name##_##active_type##_set(PointerRNA *ptr, PointerRNA value) \
+ { \
+ Mesh *me = rna_mesh(ptr); \
+ CustomData *data = rna_mesh_##customdata_type(ptr); \
+ CustomDataLayer *cdl; \
+ int a; \
+ \
+ for(cdl=data->layers, a=0; a<data->totlayer; cdl++, a++) { \
+ if(value.data == cdl) { \
+ CustomData_set_layer_##active_type##_index(data, layer_type, a); \
+ mesh_update_customdata_pointers(me, TRUE); \
+ return; \
+ } \
+ } \
+ } \
+ \
+ static int rna_Mesh_##collection_name##_##active_type##_index_get(PointerRNA *ptr) \
+ { \
+ CustomData *data = rna_mesh_##customdata_type(ptr); \
+ return CustomData_get_##active_type##_layer(data, layer_type); \
+ } \
+ \
+ static void rna_Mesh_##collection_name##_##active_type##_index_set(PointerRNA *ptr, int value) \
+ { \
+ Mesh *me = rna_mesh(ptr); \
+ CustomData *data = rna_mesh_##customdata_type(ptr); \
+ \
+ CustomData_set_layer_##active_type(data, layer_type, value); \
+ mesh_update_customdata_pointers(me, TRUE); \
+ }
+
+#endif /* __RNA_MESH_UTILS_H__ */
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 6d16937acad..6bcd8c0a5bc 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -73,6 +73,7 @@ EnumPropertyItem modifier_type_items[] ={
{eModifierType_Screw, "SCREW", ICON_MOD_SCREW, "Screw", ""},
{eModifierType_Solidify, "SOLIDIFY", ICON_MOD_SOLIDIFY, "Solidify", ""},
{eModifierType_Subsurf, "SUBSURF", ICON_MOD_SUBSURF, "Subdivision Surface", ""},
+ {eModifierType_NgonInterp, "NGONINTERP", ICON_MOD_LATTICE, "Precision UV Interpolation", ""},
{0, "", 0, "Deform", ""},
{eModifierType_Armature, "ARMATURE", ICON_MOD_ARMATURE, "Armature", ""},
{eModifierType_Cast, "CAST", ICON_MOD_CAST, "Cast", ""},
@@ -182,6 +183,8 @@ static StructRNA* rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_MultiresModifier;
case eModifierType_Surface:
return &RNA_SurfaceModifier;
+ case eModifierType_NgonInterp:
+ return &RNA_NgonInterpModifier;
case eModifierType_Smoke:
return &RNA_SmokeModifier;
case eModifierType_Solidify:
@@ -483,7 +486,7 @@ static int rna_MultiresModifier_external_get(PointerRNA *ptr)
Object *ob= (Object*)ptr->id.data;
Mesh *me= ob->data;
- return CustomData_external_test(&me->fdata, CD_MDISPS);
+ return CustomData_external_test(&me->ldata, CD_MDISPS);
}
static void rna_MultiresModifier_filepath_get(PointerRNA *ptr, char *value)
@@ -2136,6 +2139,19 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
#endif
RNA_def_property_ui_text(prop, "Angle", "Angle above which to bevel edges");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ /* BMESH_BRANCH ONLY */
+ prop= RNA_def_property(srna, "use_even_offset", PROP_BOOLEAN, PROP_NONE); /* name matches solidify */
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", BME_BEVEL_EVEN);
+ RNA_def_property_ui_text(prop, "Even", "Use even bevel distance correction");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ /* BMESH_BRANCH ONLY */
+ prop= RNA_def_property(srna, "use_distance_offset", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", BME_BEVEL_DIST);
+ RNA_def_property_ui_text(prop, "Distance", "Use the width as a distance in rather then a factor of the face size");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ /* END BMESH_BRANCH ONLY */
+
}
static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
@@ -3066,6 +3082,27 @@ static void rna_def_modifier_ocean(BlenderRNA *brna)
}
+
+static void rna_def_modifier_ngoninterp(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna= RNA_def_struct(brna, "NgonInterpModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "Precision UV Modifier", "Precision UV interpolation");
+ RNA_def_struct_sdna(srna, "NgonInterpModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_SCREW);
+
+ prop= RNA_def_property(srna, "resolution", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_range(prop, 1, 10000);
+ RNA_def_property_ui_range(prop, 1, 100, 1, 0);
+ RNA_def_property_ui_text(prop, "Resolution", "Size of interpolation grids");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+}
+
+
+
void RNA_def_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3169,6 +3206,9 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_dynamic_paint(brna);
rna_def_modifier_ocean(brna);
rna_def_modifier_remesh(brna);
+
+ /* BMESH_ONLY */
+ rna_def_modifier_ngoninterp(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 3ec01e56ab3..a5eb610dd29 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -46,6 +46,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 */
@@ -227,8 +228,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:
@@ -608,8 +609,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;
}
}
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index 9a90499d7df..d736a18068d 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -169,7 +169,7 @@ Mesh *rna_Object_to_mesh(Object *ob, ReportList *reports, Scene *sce, int apply_
dm = mesh_create_derived_view( sce, ob, mask );
tmpmesh = add_mesh( "Mesh" );
- DM_to_mesh( dm, tmpmesh );
+ DM_to_mesh( dm, tmpmesh, ob );
dm->release( dm );
}
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 1614dc58023..225351a2e5a 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -40,6 +40,8 @@
#include "DNA_linestyle_types.h"
#include "BLI_math.h"
+#include "BKE_tessmesh.h"
+
/* Include for Bake Options */
#include "RE_engine.h"
#include "RE_pipeline.h"
@@ -1152,9 +1154,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);
}
}
}
@@ -1166,7 +1168,7 @@ static void rna_Scene_editmesh_select_mode_update(Main *UNUSED(bmain), Scene *sc
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_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index 96667c95042..52ffdec7174 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -334,7 +334,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_return(func, parm);
func= RNA_def_function(srna, "template_preview", "uiTemplatePreview");
- RNA_def_function_ui_description(func, "Item. A preview window for materials, textures, lamps, etc.");
+ RNA_def_function_ui_description(func, "Item. A preview window for materials, textures, lamps, etc");
parm= RNA_def_pointer(func, "id", "ID", "", "ID datablock");
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_boolean(func, "show_buttons", 1, "", "Show preview buttons?");
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index fabaa6624d4..8170481cfd6 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -33,6 +33,7 @@ set(INC
../blenloader
../makesdna
../makesrna
+ ../bmesh
../render/extern/include
../../../intern/elbeem/extern
../../../intern/guardedalloc
@@ -66,6 +67,7 @@ set(SRC
intern/MOD_meshdeform.c
intern/MOD_mirror.c
intern/MOD_multires.c
+ intern/MOD_ngoninterp.c
intern/MOD_none.c
intern/MOD_ocean.c
intern/MOD_particleinstance.c
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index ea5574a378e..ba2ec56d76a 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -74,6 +74,7 @@ extern ModifierTypeInfo modifierType_WeightVGMix;
extern ModifierTypeInfo modifierType_WeightVGProximity;
extern ModifierTypeInfo modifierType_DynamicPaint;
extern ModifierTypeInfo modifierType_Remesh;
+extern ModifierTypeInfo modifierType_NgonInterp;
/* MOD_util.c */
void modifier_type_init(ModifierTypeInfo *types[]);
diff --git a/source/blender/modifiers/SConscript b/source/blender/modifiers/SConscript
index 03fcee399bd..4ab3874d6fe 100644
--- a/source/blender/modifiers/SConscript
+++ b/source/blender/modifiers/SConscript
@@ -5,7 +5,7 @@ sources = env.Glob('intern/*.c')
incs = '. ./intern'
incs += ' #/intern/guardedalloc #/intern/decimation/extern #/intern/bsp/extern #/intern/elbeem/extern #/extern/glew/include'
-incs += ' ../render/extern/include ../blenloader'
+incs += ' ../render/extern/include ../blenloader ../bmesh'
incs += ' ../include ../blenlib ../makesdna ../makesrna ../blenkernel ../blenkernel/intern'
incs += ' ../gpu'
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index 8c8523f8d2c..7260e39e982 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -136,13 +136,13 @@ static void deformVerts(ModifierData *md, Object *ob,
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct EditMesh *editData,
+ ModifierData *md, Object *ob, struct BMEditMesh *editData,
DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
ArmatureModifierData *amd = (ArmatureModifierData*) md;
DerivedMesh *dm = derivedData;
- if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data);
+ if(!derivedData) dm = CDDM_from_BMEditMesh(editData, ob->data, FALSE, FALSE);
modifier_vgroup_cache(md, vertexCos); /* if next modifier needs original vertices */
@@ -159,14 +159,14 @@ static void deformVertsEM(
}
static void deformMatricesEM(
- ModifierData *md, Object *ob, struct EditMesh *editData,
+ ModifierData *md, Object *ob, struct BMEditMesh *editData,
DerivedMesh *derivedData, float (*vertexCos)[3],
float (*defMats)[3][3], int numVerts)
{
ArmatureModifierData *amd = (ArmatureModifierData*) md;
DerivedMesh *dm = derivedData;
- if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data);
+ if(!derivedData) dm = CDDM_from_BMEditMesh(editData, ob->data, FALSE, FALSE);
armature_deform_verts(amd->object, ob, dm, vertexCos, defMats, numVerts,
amd->deformflag, NULL, amd->defgrp_name);
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 4602600889c..dd40dc6f59b 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -39,22 +39,27 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_string.h"
#include "BLI_ghash.h"
#include "BLI_edgehash.h"
#include "DNA_curve_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_displist.h"
#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)
{
@@ -157,108 +162,60 @@ 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)
+/* Used for start/end cap.
+ *
+ * this function expects all existing vertices to be tagged,
+ * so we can know new verts are not tagged.
+ *
+ * All verts will be tagged on exit.
+ */
+static void bmesh_merge_dm_transform(BMesh* bm, DerivedMesh *dm, float mat[4][4])
{
- if(mface->v1 >= maxvert) {
- // printf("bad index in array\n");
- mface->v1= maxvert - 1;
- }
- if(mface->v2 >= maxvert) {
- // printf("bad index in array\n");
- mface->v2= maxvert - 1;
- }
- if(mface->v3 >= maxvert) {
- // printf("bad index in array\n");
- mface->v3= maxvert - 1;
- }
- if(mface->v4 >= maxvert) {
- // printf("bad index in array\n");
- mface->v4= maxvert - 1;
- }
-
- return test_index_face(mface, fdata, mfindex, nr);
-}
+ BMVert *v;
+ BMIter iter;
-typedef struct IndexMapEntry {
- /* the new vert index that this old vert index maps to */
- int new;
- /* -1 if this vert isn't merged, otherwise the old vert index it
- * should be replaced with
- */
- int merge;
- /* 1 if this vert's first copy is merged with the last copy of its
- * merge target, otherwise 0
- */
- short merge_final;
-} IndexMapEntry;
+ DM_to_bmesh_ex(dm, bm);
-/* indexMap - an array of IndexMap entries
- * oldIndex - the old index to map
- * copyNum - the copy number to map to (original = 0, first copy = 1, etc.)
- */
-static int calc_mapping(IndexMapEntry *indexMap, int oldIndex, int copyNum)
-{
- if(indexMap[oldIndex].merge < 0) {
- /* vert wasn't merged, so use copy of this vert */
- return indexMap[oldIndex].new + copyNum;
- } else if(indexMap[oldIndex].merge == oldIndex) {
- /* vert was merged with itself */
- return indexMap[oldIndex].new;
- } else {
- /* vert was merged with another vert */
- /* follow the chain of merges to the end, or until we've passed
- * a number of vertices equal to the copy number
- */
- if(copyNum <= 0)
- return indexMap[oldIndex].new;
- else
- return calc_mapping(indexMap, indexMap[oldIndex].merge,
- copyNum - 1);
+ /* transform all verts */
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ mul_m4_v3(mat, v->co);
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ }
}
}
static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
- struct Scene *scene, Object *ob, DerivedMesh *dm,
- int initFlags)
+ Scene *scene, Object *ob, DerivedMesh *dm,
+ int UNUSED(initFlags))
{
- int i, j;
+ DerivedMesh *result;
+ BMEditMesh *em = DM_to_editbmesh(ob, dm, NULL, FALSE);
+ 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 finalVerts, finalEdges, finalFaces;
- DerivedMesh *result, *start_cap = NULL, *end_cap = NULL;
- MVert *mvert, *src_mvert;
- MEdge *medge;
- MFace *mface;
-
- IndexMapEntry *indexMap;
-
- EdgeHash *edges;
+ int count = amd->count, maxVerts;
+ 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);
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,
@@ -280,6 +237,14 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
copy_m4_m4(offset, result_mat);
}
+ /* calculate the offset matrix of the final copy (for merging) */
+ unit_m4(final_offset);
+
+ for(j=0; j < count - 1; j++) {
+ mult_m4_m4m4(tmp_mat, offset, final_offset);
+ copy_m4_m4(final_offset, tmp_mat);
+ }
+
if(amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) {
Curve *cu = amd->curve_ob->data;
if(cu) {
@@ -316,460 +281,138 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
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++) {
- mult_m4_m4m4(tmp_mat, offset, final_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;
- }
+ /* BMESH_TODO: bumping up the stack level avoids computing the normals
+ after every top-level operator execution (and this modifier has the
+ potential to execute a *lot* of top-level BMOps. There should be a
+ cleaner way to do this. One possibility: a "mirror" BMOp would
+ certainly help by compressing it all into one top-level BMOp that
+ executes a lot of second-level BMOps. */
+ BMO_push(em->bm, NULL);
+ bmesh_begin_edit(em->bm, 0);
+
+ BMO_op_init(em->bm, &weldop, "weldverts");
+ BMO_op_initf(em->bm, &op, "dupe geom=%avef");
+ oldop = op;
+ for (j=0; j < count - 1; j++) {
+ BMVert *v, *v2;
+ BMOpSlot *s1;
+ BMOpSlot *s2;
+
+ BMO_op_initf(em->bm, &op, "dupe geom=%s", &oldop, j==0 ? "geom" : "newout");
+ BMO_op_exec(em->bm, &op);
+
+ s1 = BMO_slot_get(&op, "geom");
+ s2 = BMO_slot_get(&op, "newout");
+
+ BMO_op_callf(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_op_initf(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) {
+ BM_elem_index_set(h, i); /* set_dirty */
+ i++;
}
- }
- /* 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);
+ BMO_ITER(h, &oiter, em->bm, &op, "newout", BM_ALL) {
+ BM_elem_index_set(h, i); /* set_dirty */
+ i++;
}
- } 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);
- }
- }
+ /* above loops over all, so set all to dirty, if this is somehow
+ * setting valid values, this line can be remvoed - campbell */
+ em->bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
- /* 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;
+ BMO_op_exec(em->bm, &findop);
- /* 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;
+ indexLen = i;
+ indexMap = MEM_callocN(sizeof(int)*indexLen, "indexMap");
- if (initFlags) {
- med.flag |= ME_EDGEDRAW | ME_EDGERENDER;
- }
+ /*element type argument doesn't do anything here*/
+ BMO_ITER(v, &oiter, em->bm, &findop, "targetmapout", 0) {
+ v2 = BMO_iter_map_value_p(&oiter);
- if(!BLI_edgehash_haskey(edges, med.v1, med.v2)) {
- DM_copy_edge_data(dm, result, i, numEdges, 1);
- medge[numEdges] = med;
- numEdges++;
+ indexMap[BM_elem_index_get(v)] = BM_elem_index_get(v2)+1;
+ }
- BLI_edgehash_insert(edges, med.v1, med.v2, NULL);
+ BMO_op_finish(em->bm, &findop);
}
- 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];
+ /*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)
- DM_copy_edge_data(dm, result, i, numEdges, 1);
- *med2 = med;
- numEdges++;
+ for (i=0; i<indexLen; i++) {
+ if (!indexMap[i]) continue;
- med2->v1 = vert1;
- med2->v2 = vert2;
+ v = E(i);
+ v2 = E(indexMap[i]-1);
- 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);
+ BMO_slot_map_ptr_insert(em->bm, &weldop, "targetmap", v, v2);
}
- 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);
+ #undef E
+ #undef _E
- 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);
- }
- }
+ BMO_op_finish(em->bm, &oldop);
+ oldop = op;
}
- /* 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;
+ if (j > 0) BMO_op_finish(em->bm, &op);
- vert_map[i] = numVerts;
+ /* BMESH_TODO - cap ends are not welded, even though weld is called after */
- numVerts++;
- }
- }
- origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
- for(i = 0; i < capEdges; i++) {
- int v1, v2;
+ /* start capping */
+ if ((start_cap || end_cap) &&
- v1 = vert_map[cap_medge[i].v1];
- v2 = vert_map[cap_medge[i].v2];
+ /* BMESH_TODO - theres a bug in DM_to_bmesh_ex() when in editmode!
+ * this needs investigation, but for now at least dont crash */
+ ob->mode != OB_MODE_EDIT
- 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;
+ )
+ {
+ BM_mesh_elem_flag_enable_all(em->bm, BM_VERT, BM_ELEM_TAG);
- numEdges++;
- }
+ if (start_cap) {
+ float startoffset[4][4];
+ invert_m4_m4(startoffset, offset);
+ bmesh_merge_dm_transform(em->bm, start_cap, startoffset);
}
- 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++;
+ if (end_cap) {
+ float endoffset[4][4];
+ mult_m4_m4m4(endoffset, offset, final_offset);
+ bmesh_merge_dm_transform(em->bm, end_cap, endoffset);
}
-
- MEM_freeN(vert_map);
- start_cap->release(start_cap);
}
+ /* done capping */
- 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);
-
- mult_m4_m4m4(endoffset, offset, final_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;
+ if (amd->flags & MOD_ARR_MERGE)
+ BMO_op_exec(em->bm, &weldop);
- v1 = vert_map[cap_medge[i].v1];
- v2 = vert_map[cap_medge[i].v2];
+ BMO_op_finish(em->bm, &weldop);
- 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;
+ /* Bump the stack level back down to match the adjustment up above */
+ BMO_pop(em->bm);
- 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;
+ BLI_assert(em->looptris == NULL);
+ result = CDDM_from_BMEditMesh(em, NULL, FALSE, FALSE);
- numFaces++;
- }
-
- MEM_freeN(vert_map);
- end_cap->release(end_cap);
- }
-
- BLI_edgehash_free(edges, NULL);
+ BMEdit_Free(em);
+ MEM_freeN(em);
MEM_freeN(indexMap);
- CDDM_lower_num_verts(result, numVerts);
- CDDM_lower_num_edges(result, numEdges);
- CDDM_lower_num_faces(result, numFaces);
-
return result;
}
@@ -783,14 +426,14 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
result = arrayModifier_doArray(amd, md->scene, ob, dm, 0);
- if(result != dm)
- CDDM_calc_normals(result);
+ //if(result != dm)
+ // CDDM_calc_normals_mapping(result);
return result;
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
- struct EditMesh *UNUSED(editData),
+ struct BMEditMesh *UNUSED(editData),
DerivedMesh *dm)
{
return applyModifier(md, ob, dm, 0, 1);
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index 160167808fc..91ff1ad0063 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -32,17 +32,20 @@
* \ingroup modifiers
*/
-#include "MEM_guardedalloc.h"
-
#include "BLI_utildefines.h"
+#include "BLI_math.h"
#include "BLI_string.h"
-#include "BKE_bmesh.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_modifier.h"
-#include "BKE_particle.h"
+#include "BKE_tessmesh.h"
+#include "BKE_mesh.h"
-#include "MOD_util.h"
+#include "BKE_bmesh.h" /* only for defines */
+
+#include "DNA_object_types.h"
+
+#include "MEM_guardedalloc.h"
static void initData(ModifierData *md)
@@ -85,6 +88,77 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
return dataMask;
}
+#define EDGE_MARK 1
+
+
+/* BMESH_TODO
+ *
+ * this bevel calls the operator which is missing many of the options
+ * which the bevel modifier in trunk has.
+ * - width is interpreted as percent (not distance)
+ * - no vertex bevel
+ * - no weight bevel
+ *
+ * These will need to be added to the bmesh operator.
+ * - campbell
+ *
+ * note: this code is very close to MOD_edgesplit.c.
+ * note: if 0'd code from trunk included below.
+ */
+static DerivedMesh *applyModifier(ModifierData *md, struct Object *ob,
+ DerivedMesh *dm,
+ int UNUSED(useRenderParams),
+ int UNUSED(isFinalCalc))
+{
+ DerivedMesh *result;
+ BMesh *bm;
+ BMEditMesh *em;
+ BMIter iter;
+ BMEdge *e;
+ BevelModifierData *bmd = (BevelModifierData*) md;
+ float threshold = cos((bmd->bevel_angle + 0.00001) * M_PI / 180.0);
+
+ em = DM_to_editbmesh(ob, dm, NULL, FALSE);
+ bm = em->bm;
+
+ BM_mesh_normals_update(bm);
+ BMO_push(bm, NULL);
+
+ if (bmd->lim_flags & BME_BEVEL_ANGLE) {
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ /* check for 1 edge having 2 face users */
+ BMLoop *l1, *l2;
+ if ( (l1= e->l) &&
+ (l2= e->l->radial_next) != l1)
+ {
+ if (dot_v3v3(l1->f->no, l2->f->no) < threshold) {
+ BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ }
+ }
+ }
+ }
+ else {
+ /* crummy, is there a way just to operator on all? - campbell */
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ }
+ }
+
+ BMO_op_callf(bm, "bevel geom=%fe percent=%f use_even=%i use_dist=%i",
+ EDGE_MARK, bmd->value, (bmd->flags & BME_BEVEL_EVEN)!=0, (bmd->flags & BME_BEVEL_DIST) != 0);
+ BMO_pop(bm);
+
+ BLI_assert(em->looptris == NULL);
+ result = CDDM_from_BMEditMesh(em, NULL, TRUE, FALSE);
+ BMEdit_Free(em);
+ MEM_freeN(em);
+
+ return result;
+}
+
+
+#if 0 /* from trunk, see note above */
+
static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
DerivedMesh *derivedData,
int UNUSED(useRenderParams),
@@ -116,8 +190,10 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
return result;
}
+#endif
+
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
- EditMesh *UNUSED(editData),
+ struct BMEditMesh *UNUSED(editData),
DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 2493b5e0f74..72e54754498 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -95,14 +95,14 @@ static DerivedMesh *get_quick_derivedMesh(DerivedMesh *derivedData, DerivedMesh
{
DerivedMesh *result = NULL;
- if(derivedData->getNumFaces(derivedData) == 0 || dm->getNumFaces(dm) == 0) {
+ if(derivedData->getNumPolys(derivedData) == 0 || dm->getNumPolys(dm) == 0) {
switch(operation) {
case eBooleanModifierOp_Intersect:
- result = CDDM_new(0, 0, 0);
+ result = CDDM_new(0, 0, 0, 0, 0);
break;
case eBooleanModifierOp_Union:
- if(derivedData->getNumFaces(derivedData)) result = derivedData;
+ if(derivedData->getNumPolys(derivedData)) result = derivedData;
else result = CDDM_copy(dm);
break;
@@ -138,6 +138,10 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
result = get_quick_derivedMesh(derivedData, dm, bmd->operation);
if(result == NULL) {
+
+ DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
+ DM_ensure_tessface(derivedData); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
+
// TIMEIT_START(NewBooleanDerivedMesh)
result = NewBooleanDerivedMesh(dm, bmd->object, derivedData, ob,
diff --git a/source/blender/modifiers/intern/MOD_boolean_util.c b/source/blender/modifiers/intern/MOD_boolean_util.c
index 4b380efa95b..510179c01d7 100644
--- a/source/blender/modifiers/intern/MOD_boolean_util.c
+++ b/source/blender/modifiers/intern/MOD_boolean_util.c
@@ -173,14 +173,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 */
@@ -254,7 +254,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;
}
@@ -304,8 +304,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;
@@ -353,7 +353,7 @@ static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh(
int i, *origindex_layer;
// 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,
@@ -379,7 +379,7 @@ static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh(
if (mat)
*totmat = 0;
- origindex_layer = result->getFaceDataArray(result, CD_ORIGINDEX);
+ origindex_layer = result->getTessFaceDataArray(result, CD_ORIGINDEX);
// step through the face iterators
for(i = 0; !face_it->Done(face_it->it); i++) {
@@ -395,16 +395,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];
@@ -463,8 +463,9 @@ static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh(
if (material_hash)
BLI_ghash_free(material_hash, NULL, NULL);
- CDDM_calc_edges(result);
- CDDM_calc_normals(result);
+ CDDM_calc_edges_tessface(result);
+
+ CDDM_tessfaces_to_faces(result); /*builds ngon faces from tess (mface) faces*/
return result;
}
@@ -499,7 +500,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),
@@ -531,7 +532,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();
@@ -585,7 +586,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;
@@ -602,7 +603,7 @@ int NewBooleanMesh(Scene *scene, Base *base, Base *base_select, int int_op_type)
ob_new= AddNewBlenderMesh(scene, base_select);
me_new= ob_new->data;
- DM_to_mesh(result, me_new);
+ DM_to_mesh(result, me_new, ob_new);
result->release(result);
dm->release(dm);
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index ebb5bd9ab9b..2399f6e8fc4 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -83,10 +83,12 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
DerivedMesh *dm = derivedData;
DerivedMesh *result;
BuildModifierData *bmd = (BuildModifierData*) md;
- int i;
- int numFaces_dst, numEdges_dst;
+ int i, j, k;
+ int numFaces_dst, numEdges_dst, numLoops_dst = 0;
int *vertMap, *edgeMap, *faceMap;
float frac;
+ MPoly *mpoly_dst;
+ MLoop *ml_dst, *ml_src, *mloop_dst;
GHashIterator *hashIter;
/* maps vert indices in old mesh to indices in new mesh */
GHash *vertHash = BLI_ghash_new(BLI_ghashutil_inthash,
@@ -94,106 +96,115 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
/* maps edge indices in new mesh to indices in old mesh */
GHash *edgeHash = BLI_ghash_new(BLI_ghashutil_inthash,
BLI_ghashutil_intcmp, "build ed apply gh");
+ GHash *edgeHash2 = BLI_ghash_new(BLI_ghashutil_inthash,
+ BLI_ghashutil_intcmp, "build ed apply gh");
+
+ const int numVert_src = dm->getNumVerts(dm);
+ const int numEdge_src = dm->getNumEdges(dm);
+ const int numPoly_src = dm->getNumPolys(dm);
+ MPoly *mpoly_src = dm->getPolyArray(dm);
+ MLoop *mloop_src = dm->getLoopArray(dm);
+ MEdge *medge_src = dm->getEdgeArray(dm);
+ MVert *mvert_src = dm->getVertArray(dm);
- const int numVert_src= dm->getNumVerts(dm);
- const int numEdge_src= dm->getNumEdges(dm);
- const int numFace_src= dm->getNumFaces(dm);
vertMap = MEM_callocN(sizeof(*vertMap) * numVert_src, "build modifier vertMap");
for (i = 0; i < numVert_src; i++) vertMap[i] = i;
edgeMap = MEM_callocN(sizeof(*edgeMap) * numEdge_src, "build modifier edgeMap");
for (i = 0; i < numEdge_src; i++) edgeMap[i] = i;
- faceMap = MEM_callocN(sizeof(*faceMap) * numFace_src, "build modifier faceMap");
- for (i = 0; i < numFace_src; i++) faceMap[i] = i;
+ faceMap = MEM_callocN(sizeof(*faceMap) * numPoly_src, "build modifier faceMap");
+ for (i = 0; i < numPoly_src; i++) faceMap[i] = i;
frac = (BKE_curframe(md->scene) - bmd->start) / bmd->length;
CLAMP(frac, 0.0f, 1.0f);
- numFaces_dst = dm->getNumFaces(dm) * frac;
- numEdges_dst = dm->getNumEdges(dm) * frac;
+ numFaces_dst = numPoly_src * frac;
+ numEdges_dst = numEdge_src * frac;
/* if there's at least one face, build based on faces */
if (numFaces_dst) {
+ MPoly *mpoly, *mp;
+ MLoop *ml, *mloop;
+ MEdge *medge;
+
if (bmd->randomize) {
BLI_array_randomize(faceMap, sizeof(*faceMap),
- numFace_src, bmd->seed);
+ numPoly_src, bmd->seed);
}
/* get the set of all vert indices that will be in the final mesh,
* mapped to the new indices
*/
+ mpoly = mpoly_src;
+ mloop = mloop_src;
for (i = 0; i < numFaces_dst; i++) {
- MFace mf;
- dm->getFace(dm, faceMap[i], &mf);
+ mp = mpoly + faceMap[i];
+ ml = mloop + mp->loopstart;
- if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1))) {
- BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v1),
- SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
- }
- if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v2))) {
- BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v2),
- SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
- }
- if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v3))) {
- BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v3),
- SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
- }
- if (mf.v4 && !BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v4))) {
- BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v4),
- SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
+ for (j=0; j<mp->totloop; j++, ml++) {
+ if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml->v)))
+ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(ml->v),
+ SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
}
+
+ numLoops_dst += mp->totloop;
}
/* get the set of edges that will be in the new mesh (i.e. all edges
* that have both verts in the new mesh)
*/
+ medge = medge_src;
for (i = 0; i < numEdge_src; i++) {
- MEdge me;
- dm->getEdge(dm, i, &me);
+ MEdge *me = medge + i;
- if ( BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1)) &&
- BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2)))
+ if ( BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v1)) &&
+ BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v2)))
{
- BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(BLI_ghash_size(edgeHash)),
+ j = BLI_ghash_size(edgeHash);
+
+ BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(j),
SET_INT_IN_POINTER(i));
+ BLI_ghash_insert(edgeHash2, SET_INT_IN_POINTER(i),
+ SET_INT_IN_POINTER(j));
}
}
}
else if (numEdges_dst) {
- if (bmd->randomize) {
+ MEdge *medge, *me;
+
+ if(bmd->randomize)
BLI_array_randomize(edgeMap, sizeof(*edgeMap),
numEdge_src, bmd->seed);
- }
/* get the set of all vert indices that will be in the final mesh,
* mapped to the new indices
*/
+ medge = medge_src;
for (i = 0; i < numEdges_dst; i++) {
- MEdge me;
- dm->getEdge(dm, edgeMap[i], &me);
+ me = medge + edgeMap[i];
- if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1))) {
- BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me.v1),
+ if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v1))) {
+ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me->v1),
SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
}
- if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2))) {
- BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me.v2),
- SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
+ if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v2))) {
+ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me->v2), SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
}
}
/* get the set of edges that will be in the new mesh
- */
+ */
for (i = 0; i < numEdges_dst; i++) {
- MEdge me;
- dm->getEdge(dm, edgeMap[i], &me);
-
- BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(BLI_ghash_size(edgeHash)),
+ j = BLI_ghash_size(edgeHash);
+
+ BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(j),
SET_INT_IN_POINTER(edgeMap[i]));
+ BLI_ghash_insert(edgeHash2, SET_INT_IN_POINTER(edgeMap[i]),
+ SET_INT_IN_POINTER(j));
}
}
else {
- int numVerts = dm->getNumVerts(dm) * frac;
+ int numVerts = numVert_src * frac;
if (bmd->randomize) {
BLI_array_randomize(vertMap, sizeof(*vertMap),
@@ -201,11 +212,10 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
}
/* get the set of all vert indices that will be in the final mesh,
- * mapped to the new indices
- */
+ * mapped to the new indices
+ */
for (i = 0; i < numVerts; i++) {
- BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(vertMap[i]),
- SET_INT_IN_POINTER(i));
+ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(vertMap[i]), SET_INT_IN_POINTER(i));
}
}
@@ -213,19 +223,20 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
* the mesh
*/
result = CDDM_from_template(dm, BLI_ghash_size(vertHash),
- BLI_ghash_size(edgeHash), numFaces_dst);
+ BLI_ghash_size(edgeHash), 0, numLoops_dst, numFaces_dst);
/* copy the vertices across */
for ( hashIter = BLI_ghashIterator_new(vertHash);
!BLI_ghashIterator_isDone(hashIter);
- BLI_ghashIterator_step(hashIter))
+ BLI_ghashIterator_step(hashIter)
+ )
{
MVert source;
MVert *dest;
int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
- dm->getVert(dm, oldIndex, &source);
+ source = mvert_src [oldIndex];
dest = CDDM_get_vert(result, newIndex);
DM_copy_vert_data(dm, result, oldIndex, newIndex, 1);
@@ -239,7 +250,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
MEdge *dest;
int oldIndex = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_INT_IN_POINTER(i)));
- dm->getEdge(dm, oldIndex, &source);
+ source = medge_src[oldIndex];
dest = CDDM_get_edge(result, i);
source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1)));
@@ -249,33 +260,34 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
*dest = source;
}
+ mpoly_dst = CDDM_get_polys(result);
+ mloop_dst = ml_dst = CDDM_get_loops(result);
+
/* copy the faces across, remapping indices */
+ k = 0;
for (i = 0; i < numFaces_dst; i++) {
- MFace source;
- MFace *dest;
- int orig_v4;
-
- dm->getFace(dm, faceMap[i], &source);
- dest = CDDM_get_face(result, i);
+ MPoly *source;
+ MPoly *dest;
- orig_v4 = source.v4;
+ source = mpoly_src + faceMap[i];
+ dest = mpoly_dst + i;
+ DM_copy_poly_data(dm, result, faceMap[i], i, 1);
- source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1)));
- source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2)));
- source.v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v3)));
- if (source.v4)
- source.v4 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v4)));
-
- DM_copy_face_data(dm, result, faceMap[i], i, 1);
- *dest = source;
+ *dest = *source;
+ dest->loopstart = k;
- test_index_face(dest, &result->faceData, i, (orig_v4 ? 4 : 3));
- }
+ DM_copy_loop_data(dm, result, source->loopstart, dest->loopstart, dest->totloop);
- CDDM_calc_normals(result);
+ ml_src = mloop_src + source->loopstart;
+ for (j=0; j<source->totloop; j++, k++, ml_src++, ml_dst++) {
+ ml_dst->v = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(ml_src->v)));
+ ml_dst->e = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash2, SET_INT_IN_POINTER(ml_src->e)));
+ }
+ }
BLI_ghash_free(vertHash, NULL, NULL);
BLI_ghash_free(edgeHash, NULL, NULL);
+ BLI_ghash_free(edgeHash2, NULL, NULL);
MEM_freeN(vertMap);
MEM_freeN(edgeMap);
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index 78bebc0b5e2..75aecc4f5af 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -585,7 +585,7 @@ static void deformVerts(ModifierData *md, Object *ob,
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct EditMesh *editData,
+ ModifierData *md, Object *ob, struct BMEditMesh *editData,
DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *dm = get_dm(ob, editData, derivedData, NULL, 0);
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index 0cd3481c899..92ef79b4a8e 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -166,8 +166,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_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index 5ce05e5e062..0ff37c6fa76 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -126,12 +126,12 @@ static void deformVerts(ModifierData *md, Object *ob,
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct EditMesh *editData,
+ ModifierData *md, Object *ob, struct BMEditMesh *editData,
DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *dm = derivedData;
- if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data);
+ if(!derivedData) dm = CDDM_from_BMEditMesh(editData, ob->data, FALSE, FALSE);
deformVerts(md, ob, dm, vertexCos, numVerts, 0, 0);
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index d1092345930..bc7771d86b0 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -81,10 +81,12 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
int totvert, totface;
int a, numTris;
+ DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
+
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++) {
@@ -96,7 +98,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
if(numTris<3) {
modifier_setError(md,
"Modifier requires more than 3 input faces (triangles).");
- goto exit;
+ dm = CDDM_copy(dm);
+ return dm;
}
lod.vertex_buffer= MEM_mallocN(3*sizeof(float)*totvert, "vertices");
@@ -140,11 +143,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++) {
@@ -155,7 +158,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];
@@ -166,8 +169,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
}
}
- CDDM_calc_edges(result);
- CDDM_calc_normals(result);
+ CDDM_calc_edges_tessface(result);
}
else
modifier_setError(md, "Out of memory.");
@@ -181,8 +183,14 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
MEM_freeN(lod.vertex_normal_buffer);
MEM_freeN(lod.triangle_index_buffer);
-exit:
+ if (result) {
+ CDDM_tessfaces_to_faces(result); /*builds ngon faces from tess (mface) faces*/
+
return result;
+ }
+ else {
+ 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 1ac11da25db..e0972ff2d32 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -251,7 +251,7 @@ static void deformVerts(ModifierData *md, Object *ob,
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct EditMesh *editData,
+ ModifierData *md, Object *ob, struct BMEditMesh *editData,
DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *dm= get_cddm(ob, editData, derivedData, vertexCos);
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 32ab2c82f90..14b54be8be1 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -36,1243 +36,112 @@
/* EdgeSplit modifier: Splits edges in the mesh according to sharpness flag
* or edge angle (can be used to achieve autosmoothing) */
-#include <assert.h>
-
-#include "DNA_meshdata_types.h"
-
-#include "BLI_listbase.h"
-#include "BLI_memarena.h"
-#include "BLI_edgehash.h"
-#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLI_linklist.h"
+#include "BLI_math.h"
#include "MEM_guardedalloc.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_modifier.h"
-#include "BKE_particle.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];
-
- assert(vert != NULL);
-
- if(mesh->num_verts >= mesh->max_verts) {
- printf("Attempted to add a SmoothMesh vert beyond end of array\n");
- 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)
-{
- 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");
- 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;
-}
-
-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");
-
- memcpy(tmp, mesh->verts, sizeof(*tmp) * mesh->num_verts);
-
- /* remap vert pointers in edges */
- for(i = 0; i < mesh->num_edges; ++i) {
- int j;
- SmoothEdge *edge = &mesh->edges[i];
-
- 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;
-}
-
-static void smoothmesh_resize_edges(SmoothMesh *mesh, int max_edges)
-{
- 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);
-
- /* 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;
-}
-
-#ifdef EDGESPLIT_DEBUG_0
-static void smoothmesh_print(SmoothMesh *mesh)
-{
- 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");
- }
-
- 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");
- }
-}
-#endif
-
-static SmoothMesh *smoothmesh_from_derivedmesh(DerivedMesh *dm)
-{
- 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;
- }
-}
-#endif
-
-/* returns 1 if the linked list contains the given pointer, 0 otherwise
- */
-static int linklist_contains(LinkNode *list, void *ptr)
-{
- LinkNode *node;
-
- for(node = list; node; node = node->next)
- if(node->link == ptr) return 1;
-
- return 0;
-}
-
-/* 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)
-{
- for(; list1; list1 = list1->next)
- if(!linklist_contains(list2, list1->link))
- return 0;
-
- return 1;
-}
-
-#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
-
-/* 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;
-
- while(node && node->link != value) {
- prev = node;
- node = node->next;
- }
-
- if(node) {
- if(prev)
- prev->next = node->next;
- else
- *list = node->next;
-
- if(freefunc)
- freefunc(node->link);
-
- MEM_freeN(node);
- }
-}
-
-/* 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;
- }
- }
-
-#ifdef EDGESPLIT_DEBUG_3
- printf(" -> {%4d, %4d}\n", edge->verts[0]->newIndex, edge->verts[1]->newIndex);
-#endif
-}
-
-static void face_replace_vert(void *ptr, void *userdata)
-{
- SmoothFace *face = ptr;
- int i;
-
- for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++)
- edge_replace_vert(face->edges[i], userdata);
-}
-
-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
+#include "BKE_tessmesh.h"
+#include "BKE_mesh.h"
- 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;
- }
- }
-
-#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
-}
-
-static int edge_is_loose(SmoothEdge *edge)
-{
- return !(edge->faces && edge->faces->next);
-}
-
-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;
- }
- }
-
-#ifdef EDGESPLIT_DEBUG_1
- printf("not sharp\n");
-#endif
- return 0;
-}
+#include "DNA_object_types.h"
-/* 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)
+/* EdgeSplit */
+/* EdgeSplit modifier: Splits edges in the mesh according to sharpness flag
+ * or edge angle (can be used to achieve autosmoothing)
+ *
+ * note: this code is very close to MOD_bevel.c
*/
-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
-
- /* get a face on which to start */
- if(edge->faces) face = edge->faces->link;
- else return NULL;
-
- /* record this edge as visited */
- BLI_linklist_prepend(&visited_edges, edge);
-
- /* get the next edge */
- edge2 = other_edge(face, vert, edge);
-
- /* record this face as visited */
- if(visited_faces)
- BLI_linklist_prepend(visited_faces, face);
-
- /* 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);
-#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);
-
- if(copy_vert == NULL) {
- /* bug [#26316], this prevents a segfault
- * but this still needs fixing */
- return;
- }
-
- 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);
-}
+#define EDGE_MARK 1
-static void pop_propagate_stack(SmoothEdge **edge, SmoothVert **vert, SmoothMesh *mesh)
+static DerivedMesh *doEdgeSplit(DerivedMesh *dm, EdgeSplitModifierData *emd, Object *ob)
{
- PropagateEdge *pedge = mesh->propagatestack.first;
-
- if(pedge) {
- *edge = pedge->edge;
- *vert = pedge->vert;
- BLI_remlink(&mesh->propagatestack, pedge);
- BLI_addhead(&mesh->reusestack, pedge);
- }
- else {
- *edge = NULL;
- *vert = NULL;
- }
-}
-
-static void split_edge(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh);
-
-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
-
- 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;
+ DerivedMesh *result;
+ BMesh *bm;
+ BMEditMesh *em;
+ BMIter iter;
+ BMEdge *e;
+ float threshold = cos((emd->split_angle + 0.00001) * M_PI / 180.0);
- /* 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);
+ em = DM_to_editbmesh(ob, dm, NULL, FALSE);
+ bm = em->bm;
- /* fails in rare cases, see [#26993] */
- if(vert2) {
- /* replace vert with its copy in visited_faces */
- repdata.find = vert;
- repdata.replace = vert2;
- BLI_linklist_apply(visited_faces, face_replace_vert, &repdata);
+ BM_mesh_normals_update(bm);
+ BMO_push(bm, NULL);
+
+ if (emd->flags & MOD_EDGESPLIT_FROMANGLE) {
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ /* check for 1 edge having 2 face users */
+ BMLoop *l1, *l2;
+ if ( (l1= e->l) &&
+ (l2= e->l->radial_next) != l1)
+ {
+ if (dot_v3v3(l1->f->no, l2->f->no) < threshold) {
+ BMO_elem_flag_enable(bm, e, EDGE_MARK);
}
}
- } else {
- /* edge is not loose, so it must be sharp; split it */
- split_edge(edge, vert, mesh);
}
}
-
- BLI_linklist_free(visited_faces, NULL);
-#ifdef EDGESPLIT_DEBUG_1
- printf("=== END === propagate_split(edge = %4d, vert = %4d)\n",
- edge->newIndex, vert->newIndex);
-#endif
-}
-
-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
-
- 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);
-
- /* bug [#29205] which is caused by exactly the same reason as [#26316]
- this check will only prevent crash without fixing actual issue and
- some vertices can stay unsplitted when they should (sergey) */
- if(vert2) {
- /* 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);
- }
-
- BLI_linklist_free(visited_faces, NULL);
-#ifdef EDGESPLIT_DEBUG_1
- printf("=== END === split_edge(edge = %4d, vert = %4d)\n",
- edge->newIndex, vert->newIndex);
-#endif
-}
-
-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.00001f) * (float)M_PI / 180.0f);
- 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)++;
- }
+
+ if (emd->flags & MOD_EDGESPLIT_FROMFLAG) {
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(e, BM_ELEM_SMOOTH)) {
+ BMO_elem_flag_enable(bm, e, EDGE_MARK);
}
}
-
- /* 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 = cosf((split_angle + 0.00001f) * (float)M_PI / 180.0f);
- 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);
+
+ BMO_op_callf(bm, "edgesplit edges=%fe", EDGE_MARK);
+
+ BMO_pop(bm);
- do {
- pop_propagate_stack(&edge, &vert, mesh);
- if(edge && smoothedge_has_vert(edge, vert))
- propagate_split(edge, vert, mesh);
- } while(edge);
- }
- }
+ BLI_assert(em->looptris == NULL);
+ result = CDDM_from_BMEditMesh(em, NULL, TRUE, FALSE);
+ BMEdit_Free(em);
+ MEM_freeN(em);
+
+ return result;
}
-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];
+ EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
+ EdgeSplitModifierData *temd = (EdgeSplitModifierData*) target;
- /* 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);
- }
- }
+ 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, ob);
}
-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 UNUSED(useRenderParams), int UNUSED(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);
@@ -1281,7 +150,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
- struct EditMesh *UNUSED(editData),
+ struct BMEditMesh *UNUSED(editData),
DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index d00d76f6f6b..afcfcc396ee 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -108,8 +108,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;
@@ -198,8 +198,8 @@ static const short add_faces[24] = {
static MFace *get_dface(DerivedMesh *dm, DerivedMesh *split, int cur, int i, MFace *mf)
{
- MFace *df = CDDM_get_face(split, cur);
- DM_copy_face_data(dm, split, i, cur, 1);
+ MFace *df = CDDM_get_tessface(split, cur);
+ DM_copy_tessface_data(dm, split, i, cur, 1);
*df = *mf;
return df;
}
@@ -545,12 +545,12 @@ 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");
@@ -629,7 +629,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??) */
@@ -644,7 +644,12 @@ static DerivedMesh * cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
}
/* override original facepa (original pointer is saved in caller function) */
- facepa= MEM_callocN(sizeof(int)*(totface+totfsplit),"explode_facepa");
+
+ /* BMESH_TODO, (totfsplit * 2) over allocation is used since the quads are
+ * later interpreted as tri's, for this to work right I think we probably
+ * have to stop using tessface - campbell */
+
+ facepa= MEM_callocN(sizeof(int)*(totface+(totfsplit * 2)),"explode_facepa");
//memcpy(facepa,emd->facepa,totface*sizeof(int));
emd->facepa=facepa;
@@ -671,7 +676,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:
@@ -761,7 +766,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));
}
@@ -769,8 +774,9 @@ static DerivedMesh * cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
MEM_freeN(facesplit);
MEM_freeN(vertpa);
- return splitdm;
+ CDDM_tessfaces_to_faces(splitdm); /*builds ngon faces from tess (mface) faces*/
+ return splitdm;
}
static DerivedMesh * explodeMesh(ExplodeModifierData *emd,
ParticleSystemModifierData *psmd, Scene *scene, Object *ob,
@@ -794,9 +800,9 @@ static DerivedMesh * explodeMesh(ExplodeModifierData *emd,
unsigned int ed_v1, ed_v2, 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;
@@ -850,7 +856,7 @@ static DerivedMesh * explodeMesh(ExplodeModifierData *emd,
BLI_edgehashIterator_free(ehi);
/* the final duplicated vertices */
- explode= CDDM_from_template(dm, totdup, 0,totface-delface);
+ explode= CDDM_from_template(dm, totdup, 0,totface-delface, 0, 0);
mtface = CustomData_get_layer_named(&explode->faceData, CD_MTFACE, emd->uvname);
/*dupvert= CDDM_get_verts(explode);*/
@@ -918,8 +924,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,u);
+ dm->getTessFace(dm,i,&source);
+ mf=CDDM_get_tessface(explode,u);
orig_v4 = source.v4;
@@ -934,7 +940,7 @@ static DerivedMesh * explodeMesh(ExplodeModifierData *emd,
if(source.v4)
source.v4 = edgecut_get(vertpahash, source.v4, mindex);
- DM_copy_face_data(dm,explode,i,u,1);
+ DM_copy_tessface_data(dm,explode,i,u,1);
*mf = source;
@@ -958,7 +964,8 @@ static DerivedMesh * explodeMesh(ExplodeModifierData *emd,
BLI_edgehash_free(vertpahash, NULL);
/* finalization */
- CDDM_calc_edges(explode);
+ CDDM_calc_edges_tessface(explode);
+ CDDM_tessfaces_to_faces(explode);
CDDM_calc_normals(explode);
if(psmd->psys->lattice){
@@ -989,6 +996,8 @@ static DerivedMesh * applyModifier(ModifierData *md, Object *ob,
ExplodeModifierData *emd= (ExplodeModifierData*) md;
ParticleSystemModifierData *psmd=findPrecedingParticlesystem(ob,md);
+ DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
+
if(psmd){
ParticleSystem * psys=psmd->psys;
@@ -1000,7 +1009,7 @@ static DerivedMesh * applyModifier(ModifierData *md, Object *ob,
if(emd->facepa == NULL
|| 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 0cdb2c8b057..9dc560afb0f 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c
@@ -166,20 +166,21 @@ void fluidsim_free(FluidsimModifierData *fluidmd)
#ifdef WITH_MOD_FLUID
/* read .bobj.gz file into a fluidsimDerivedMesh struct */
-static DerivedMesh *fluidsim_read_obj(const char *filename, const MFace *mf_example)
+static DerivedMesh *fluidsim_read_obj(const char *filename, const MPoly *mp_example)
{
int wri = 0,i;
int gotBytes;
gzFile gzf;
int numverts = 0, numfaces = 0;
DerivedMesh *dm = NULL;
- MFace *mf;
+ MPoly *mp;
+ MLoop *ml;
MVert *mv;
short *normals, *no_s;
float no[3];
- const short mf_mat_nr = mf_example->mat_nr;
- const char mf_flag = mf_example->flag;
+ const short mp_mat_nr = mp_example->mat_nr;
+ const char mp_flag = mp_example->flag;
// ------------------------------------------------
// get numverts + numfaces first
@@ -222,7 +223,7 @@ static DerivedMesh *fluidsim_read_obj(const char *filename, const MFace *mf_exam
return NULL;
}
- dm = CDDM_new(numverts, 0, numfaces);
+ dm = CDDM_new(numverts, 0, 0, numfaces * 3, numfaces);
if(!dm)
{
@@ -278,33 +279,25 @@ static DerivedMesh *fluidsim_read_obj(const char *filename, const MFace *mf_exam
}
// read triangles from file
- mf = CDDM_get_faces(dm);
- for(i=numfaces; i>0; i--, mf++)
+ mp = CDDM_get_polys(dm);
+ ml = CDDM_get_loops(dm);
+ for(i=0; i < numfaces; i++, mp++, ml += 3)
{
int face[3];
gotBytes = gzread(gzf, face, sizeof(int) * 3);
/* initialize from existing face */
- mf->mat_nr = mf_mat_nr;
- mf->flag = mf_flag;
+ mp->mat_nr = mp_mat_nr;
+ mp->flag = mp_flag;
- // check if 3rd vertex has index 0 (not allowed in blender)
- if(face[2])
- {
- mf->v1 = face[0];
- mf->v2 = face[1];
- mf->v3 = face[2];
- }
- else
- {
- mf->v1 = face[1];
- mf->v2 = face[2];
- mf->v3 = face[0];
- }
- mf->v4 = 0;
+ mp->loopstart = i * 3;
+ mp->totloop = 3;
+
+ ml[0].v = face[0];
+ ml[1].v = face[1];
+ ml[2].v = face[2];
- test_index_face(mf, NULL, 0, 3);
}
gzclose( gzf );
@@ -315,7 +308,6 @@ static DerivedMesh *fluidsim_read_obj(const char *filename, const MFace *mf_exam
MEM_freeN(normals);
// CDDM_calc_normals(result);
-
return dm;
}
@@ -453,9 +445,8 @@ static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, Fluidsim
char targetFile[FILE_MAX];
FluidsimSettings *fss = fluidmd->fss;
DerivedMesh *dm = NULL;
- MFace *mface;
- MFace mf_example = {0};
-
+ MPoly *mpoly;
+ MPoly mp_example = {0};
if(!useRenderParams) {
displaymode = fss->guiDisplayMode;
@@ -485,13 +476,13 @@ static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, Fluidsim
// assign material + flags to new dm
// if there's no faces in original dm, keep materials and flags unchanged
- mface = orgdm->getFaceArray(orgdm);
- if (mface) {
- mf_example = *mface;
+ mpoly = orgdm->getPolyArray(orgdm);
+ if (mpoly) {
+ mp_example = *mpoly;
}
/* else leave NULL'd */
- dm = fluidsim_read_obj(targetFile, &mf_example);
+ dm = fluidsim_read_obj(targetFile, &mp_example);
if(!dm)
{
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 9d5bc46810b..97e406c6960 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -260,7 +260,7 @@ static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData,
dm->release(dm);
}
-static void deformVertsEM(ModifierData *md, Object *ob, struct EditMesh *editData,
+static void deformVertsEM(ModifierData *md, Object *ob, struct BMEditMesh *editData,
DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
HookModifierData *hmd = (HookModifierData*) md;
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index ac0a3a0c052..00a634e8838 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -119,12 +119,12 @@ static void deformVerts(ModifierData *md, Object *ob,
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct EditMesh *editData,
+ ModifierData *md, Object *ob, struct BMEditMesh *editData,
DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *dm = derivedData;
- if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data);
+ if(!derivedData) dm = CDDM_from_BMEditMesh(editData, ob->data, FALSE, FALSE);
deformVerts(md, ob, dm, vertexCos, numVerts, 0, 0);
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index 1fbe0eef6f3..edef19fd032 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -101,13 +101,24 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
{
MaskModifierData *mmd= (MaskModifierData *)md;
DerivedMesh *dm= derivedData, *result= NULL;
- GHash *vertHash=NULL, *edgeHash, *faceHash;
+ GHash *vertHash=NULL, *edgeHash, *polyHash;
GHashIterator *hashIter;
MDeformVert *dvert= NULL, *dv;
- int numFaces=0, numEdges=0, numVerts=0;
- int maxVerts, maxEdges, maxFaces;
+ int numPolys=0, numLoops=0, numEdges=0, numVerts=0;
+ int maxVerts, maxEdges, maxPolys;
int i;
-
+
+ MPoly *mpoly;
+ MLoop *mloop;
+
+ MPoly *mpoly_new;
+ MLoop *mloop_new;
+ MEdge *medge_new;
+ MVert *mvert_new;
+
+
+ int *loop_mapping;
+
/* Overview of Method:
* 1. Get the vertices that are in the vertexgroup of interest
* 2. Filter out unwanted geometry (i.e. not in vertexgroup), by populating mappings with new vs old indices
@@ -117,7 +128,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);
+ maxPolys= dm->getNumPolys(dm);
/* check if we can just return the original mesh
* - must have verts and therefore verts assigned to vgroups to do anything useful
@@ -138,7 +149,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
char *bone_select_array;
int bone_select_tot= 0;
const int defbase_tot= BLI_countlist(&ob->defbase);
-
+
/* check that there is armature object with bones to use, otherwise return original mesh */
if (ELEM3(NULL, mmd->ob_arm, mmd->ob_arm->pose, ob->defbase.first))
return derivedData;
@@ -259,11 +270,16 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
numVerts++;
}
}
-
+
/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
edgeHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask ed2 gh");
- faceHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask fa2 gh");
+ polyHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask fa2 gh");
+ mpoly = dm->getPolyArray(dm);
+ mloop = dm->getLoopArray(dm);
+
+ loop_mapping = MEM_callocN(sizeof(int) * maxPolys, "mask loopmap"); /* overalloc, assume all polys are seen */
+
/* loop over edges and faces, and do the same thing to
* ensure that they only reference existing verts
*/
@@ -280,19 +296,27 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
numEdges++;
}
}
- for (i = 0; i < maxFaces; i++)
+ for (i = 0; i < maxPolys; i++)
{
- MFace mf;
- dm->getFace(dm, i, &mf);
+ MPoly *mp = &mpoly[i];
+ MLoop *ml = mloop + mp->loopstart;
+ int ok = TRUE;
+ int j;
+
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml->v))) {
+ ok = FALSE;
+ break;
+ }
+ }
/* all verts must be available */
- if ( BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1)) &&
- BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v2)) &&
- BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v3)) &&
- (mf.v4==0 || BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v4))) )
+ if (ok)
{
- BLI_ghash_insert(faceHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numFaces));
- numFaces++;
+ BLI_ghash_insert(polyHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numPolys));
+ loop_mapping[numPolys] = numLoops;
+ numPolys++;
+ numLoops += mp->totloop;
}
}
@@ -300,8 +324,12 @@ 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, 0, numLoops, numPolys);
+ mpoly_new = CDDM_get_polys(result);
+ mloop_new = CDDM_get_loops(result);
+ medge_new = CDDM_get_edges(result);
+ mvert_new = CDDM_get_verts(result);
/* using ghash-iterators, map data into new mesh */
/* vertices */
@@ -315,7 +343,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
dm->getVert(dm, oldIndex, &source);
- dest = CDDM_get_vert(result, newIndex);
+ dest = &mvert_new[newIndex];
DM_copy_vert_data(dm, result, oldIndex, newIndex, 1);
*dest = source;
@@ -333,7 +361,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
dm->getEdge(dm, oldIndex, &source);
- dest = CDDM_get_edge(result, newIndex);
+ dest = &medge_new[newIndex];
source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1)));
source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2)));
@@ -344,42 +372,43 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
BLI_ghashIterator_free(hashIter);
/* faces */
- for ( hashIter = BLI_ghashIterator_new(faceHash);
+ for ( hashIter = BLI_ghashIterator_new(polyHash);
!BLI_ghashIterator_isDone(hashIter);
BLI_ghashIterator_step(hashIter) )
{
- MFace source;
- MFace *dest;
int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
- int orig_v4;
+ MPoly *source = &mpoly[oldIndex];
+ MPoly *dest = &mpoly_new[newIndex];
+ int oldLoopIndex = source->loopstart;
+ int newLoopIndex = loop_mapping[newIndex];
+ MLoop *source_loop = &mloop[oldLoopIndex];
+ MLoop *dest_loop = &mloop_new[newLoopIndex];
- dm->getFace(dm, oldIndex, &source);
- dest = CDDM_get_face(result, newIndex);
-
- orig_v4 = source.v4;
-
- source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1)));
- source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2)));
- source.v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v3)));
- if (source.v4)
- source.v4 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v4)));
-
- DM_copy_face_data(dm, result, oldIndex, newIndex, 1);
- *dest = source;
-
- test_index_face(dest, &result->faceData, newIndex, (orig_v4 ? 4 : 3));
+ DM_copy_poly_data(dm, result, oldIndex, newIndex, 1);
+ DM_copy_loop_data(dm, result, oldLoopIndex, newLoopIndex, source->totloop);
+
+ *dest = *source;
+ dest->loopstart = newLoopIndex;
+ for (i = 0; i < source->totloop; i++) {
+ dest_loop[i].v = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source_loop[i].v)));
+ dest_loop[i].e = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_INT_IN_POINTER(source_loop[i].e)));
+ }
}
+
BLI_ghashIterator_free(hashIter);
-
+
+ MEM_freeN(loop_mapping);
+
+ /* why is this needed? - campbell */
/* recalculate normals */
CDDM_calc_normals(result);
/* free hashes */
BLI_ghash_free(vertHash, NULL, NULL);
BLI_ghash_free(edgeHash, NULL, NULL);
- BLI_ghash_free(faceHash, NULL, NULL);
-
+ BLI_ghash_free(polyHash, NULL, NULL);
+
/* return the new mesh */
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index d80c6715f9d..84d1b3c92ad 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -32,7 +32,7 @@
* \ingroup modifiers
*/
-
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -45,6 +45,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;
MDefInfluence *influences;
@@ -200,10 +201,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;
@@ -353,7 +353,7 @@ static void deformVerts(ModifierData *md, Object *ob,
}
static void deformVertsEM(ModifierData *md, Object *ob,
- struct EditMesh *UNUSED(editData),
+ struct BMEditMesh *UNUSED(editData),
DerivedMesh *derivedData,
float (*vertexCos)[3],
int numVerts)
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index c130af158bb..c382dfa7d14 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -37,19 +37,18 @@
#include "DNA_object_types.h"
#include "BLI_math.h"
-#include "BLI_utildefines.h"
+#include "BLI_array.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,10 +68,9 @@ static void copyData(ModifierData *md, ModifierData *target)
tmmd->mirror_ob = mmd->mirror_ob;
}
-static void foreachObjectLink(
- ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+static void foreachObjectLink(ModifierData *md, Object *ob,
+ void (*walk)(void *userData, Object *ob, Object **obpoin),
+ void *userData)
{
MirrorModifierData *mmd = (MirrorModifierData*) md;
@@ -80,9 +78,9 @@ static void foreachObjectLink(
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ DagNode *obNode)
{
MirrorModifierData *mmd = (MirrorModifierData*) md;
@@ -99,194 +97,201 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
DerivedMesh *dm,
int axis)
{
- int i;
- float tolerance = mmd->tolerance;
+ const float tolerance_sq = mmd->tolerance * mmd->tolerance;
+ const int do_vtargetmap = !(mmd->flag & MOD_MIR_NO_MERGE);
+ int is_vtargetmap = FALSE; /* true when it should be used */
+
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, flip_map_len= 0;
- int do_vgroup_mirr= (mmd->flag & MOD_MIR_VGROUP);
- unsigned int (*indexMap)[2];
- float mtx[4][4], imtx[4][4];
+ const int maxVerts = dm->getNumVerts(dm);
+ const int maxEdges = dm->getNumEdges(dm);
+ const int maxLoops = dm->getNumLoops(dm);
+ const int maxPolys = dm->getNumPolys(dm);
+ MVert *mv, *mv_prev;
+ MEdge *me;
+ MLoop *ml;
+ MPoly *mp;
+ float mtx[4][4];
+ int i, j;
+ int a, totshape;
+ int *vtargetmap, *vtmap_a = NULL, *vtmap_b = NULL;
+
+ /* mtx is the mirror transformation */
+ unit_m4(mtx);
+ mtx[axis][axis] = -1.0f;
- numVerts = numEdges = numFaces = 0;
+ if (mmd->mirror_ob) {
+ float tmp[4][4];
+ float itmp[4][4];
+
+ /* tmp is a transform from coords relative to the object's own origin,
+ * to coords relative to the mirror object origin */
+ invert_m4_m4(tmp, mmd->mirror_ob->obmat);
+ mult_m4_m4m4(tmp, tmp, ob->obmat);
+
+ /* itmp is the reverse transform back to origin-relative coordiantes */
+ invert_m4_m4(itmp, tmp);
+
+ /* combine matrices to get a single matrix that translates coordinates into
+ * mirror-object-relative space, does the mirror, and translates back to
+ * origin-relative space */
+ mult_m4_m4m4(mtx, mtx, tmp);
+ mult_m4_m4m4(mtx, itmp, mtx);
+ }
- indexMap = MEM_mallocN(sizeof(*indexMap) * maxVerts, "indexmap");
+ result = CDDM_from_template(dm, maxVerts*2, maxEdges*2, 0, maxLoops*2, maxPolys*2);
- result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2);
+ /*copy customdata to original geometry*/
+ DM_copy_vert_data(dm, result, 0, 0, maxVerts);
+ DM_copy_edge_data(dm, result, 0, 0, maxEdges);
+ DM_copy_loop_data(dm, result, 0, 0, maxLoops);
+ DM_copy_poly_data(dm, result, 0, 0, maxPolys);
- if (do_vgroup_mirr) {
- flip_map= defgroup_flip_map(ob, &flip_map_len, FALSE);
- if(flip_map == NULL)
- do_vgroup_mirr= 0;
+ /* subsurf for eg wont have mesh data in the */
+ /* now add mvert/medge/mface layers */
+
+ if (!CustomData_has_layer(&dm->vertData, CD_MVERT)) {
+ dm->copyVertArray(dm, CDDM_get_verts(result));
+ }
+ if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE)) {
+ dm->copyEdgeArray(dm, CDDM_get_edges(result));
+ }
+ if (!CustomData_has_layer(&dm->polyData, CD_MPOLY)) {
+ dm->copyLoopArray(dm, CDDM_get_loops(result));
+ dm->copyPolyArray(dm, CDDM_get_polys(result));
}
- if (mmd->mirror_ob) {
- float obinv[4][4];
-
- invert_m4_m4(obinv, mmd->mirror_ob->obmat);
- mult_m4_m4m4(mtx, obinv, ob->obmat);
- invert_m4_m4(imtx, mtx);
+ /* copy customdata to new geometry,
+ * copy from its self becayse this data may have been created in the checks above */
+ DM_copy_vert_data(result, result, 0, maxVerts, maxVerts);
+ DM_copy_edge_data(result, result, 0, maxEdges, maxEdges);
+ /* loops are copied later */
+ DM_copy_poly_data(result, result, 0, maxPolys, maxPolys);
+
+ if (do_vtargetmap) {
+ /* second half is filled with -1 */
+ vtargetmap = MEM_mallocN(sizeof(int) * maxVerts * 2, "MOD_mirror tarmap");
+
+ vtmap_a = vtargetmap;
+ vtmap_b = vtargetmap + maxVerts;
}
- 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;
-
- indexMap[i][0] = numVerts;
- indexMap[i][1] = !isShared;
-
- numVerts++;
-
- if(isShared ) {
- co[axis] = 0.0f;
- 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);
+ /* mirror vertex coordinates */
+ mv_prev = CDDM_get_verts(result);
+ mv = mv_prev + maxVerts;
+ for (i = 0; i < maxVerts; i++, mv++, mv_prev++) {
+ mul_m4_v3(mtx, mv->co);
+
+ if (do_vtargetmap) {
+ /* compare location of the original and mirrored vertex, to see if they
+ * should be mapped for merging */
+ if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
+ *vtmap_a = maxVerts + i;
+ is_vtargetmap = TRUE;
}
- 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, flip_map_len);
- }
+ else {
+ *vtmap_a = -1;
}
- numVerts++;
+ *vtmap_b = -1; /* fill here to avoid 2x loops */
+
+ vtmap_a++;
+ vtmap_b++;
}
}
-
- 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(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];
+
+ /* handle shape keys */
+ totshape = CustomData_number_of_layers(&result->vertData, CD_SHAPEKEY);
+ for (a = 0; a < totshape; a++) {
+ float (*cos)[3] = CustomData_get_layer_n(&result->vertData, CD_SHAPEKEY, a);
+ for (i = maxVerts; i < result->numVertData; i++) {
+ mul_m4_v3(mtx, cos[i]);
}
}
+
+ /* adjust mirrored edge vertex indices */
+ me = CDDM_get_edges(result) + maxEdges;
+ for (i = 0; i < maxEdges; i++, me++) {
+ me->v1 += maxVerts;
+ me->v2 += maxVerts;
+ }
+
+ /* adjust mirrored poly loopstart indices, and reverse loop order (normals) */
+ mp = CDDM_get_polys(result) + maxPolys;
+ ml = CDDM_get_loops(result);
+ for (i = 0; i < maxPolys; i++, mp++) {
+ MLoop *ml2;
+ int e;
+
+ /* reverse the loop */
+ for (j = 0; j < mp->totloop; j++) {
+ DM_copy_loop_data(result, result, mp->loopstart + j, mp->loopstart + maxLoops + mp->totloop - j - 1, 1);
+ }
- 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];
+ ml2 = ml + mp->loopstart + maxLoops;
+ e = ml2[0].e;
+ for (j = 0; j < mp->totloop-1; j++) {
+ ml2[j].e = ml2[j+1].e;
+ }
+ ml2[mp->totloop-1].e = e;
- 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];
- }
- }
+ mp->loopstart += maxLoops;
+ }
+
+ /* adjust mirrored loop vertex and edge indices */
+ ml = CDDM_get_loops(result) + maxLoops;
+ for (i = 0; i < maxLoops; i++, ml++) {
+ ml->v += maxVerts;
+ ml->e += maxEdges;
+ }
+
+ /* handle uvs,
+ * let tessface recalc handle updating the MTFace data */
+ if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) {
+ const int do_mirr_u= (mmd->flag & MOD_MIR_MIRROR_U) != 0;
+ const int do_mirr_v= (mmd->flag & MOD_MIR_MIRROR_V) != 0;
+
+ const int totuv = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV);
+
+ for (a = 0; a < totuv; a++) {
+ MLoopUV *dmloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, a);
+ int j = maxLoops;
+ dmloopuv += j; /* second set of loops only */
+ for ( ; i-- > 0; dmloopuv++) {
+ if (do_mirr_u) dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0];
+ if (do_mirr_v) dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1];
}
-
- /* Flip face normal */
- SWAP(unsigned 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);
+ /* handle vgroup stuff */
+ if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vertData, CD_MDEFORMVERT)) {
+ MDeformVert *dvert = CustomData_get_layer(&result->vertData, CD_MDEFORMVERT);
+ int *flip_map= NULL, flip_map_len= 0;
- MEM_freeN(indexMap);
+ flip_map= defgroup_flip_map(ob, &flip_map_len, FALSE);
+
+ for (i = maxVerts; i-- > 0; dvert++) {
+ defvert_flip(dvert, flip_map, flip_map_len);
+ }
+
+ MEM_freeN(flip_map);
+ }
- CDDM_lower_num_verts(result, numVerts);
- CDDM_lower_num_edges(result, numEdges);
- CDDM_lower_num_faces(result, numFaces);
+ if (do_vtargetmap) {
+ /* slow - so only call if one or more merge verts are found,
+ * users may leave this on and not realize there is nothing to merge - campbell */
+ if (is_vtargetmap) {
+ result = CDDM_merge_verts(result, vtargetmap);
+ }
+ MEM_freeN(vtargetmap);
+ }
return result;
}
static DerivedMesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
- Object *ob, DerivedMesh *dm)
+ Object *ob, DerivedMesh *dm)
{
DerivedMesh *result = dm;
@@ -309,9 +314,9 @@ static DerivedMesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
}
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
- int UNUSED(useRenderParams),
- int UNUSED(isFinalCalc))
+ DerivedMesh *derivedData,
+ int UNUSED(useRenderParams),
+ int UNUSED(isFinalCalc))
{
DerivedMesh *result;
MirrorModifierData *mmd = (MirrorModifierData*) md;
@@ -325,8 +330,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
- struct EditMesh *UNUSED(editData),
- DerivedMesh *derivedData)
+ struct BMEditMesh *UNUSED(editData),
+ DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
}
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index 55f29137eb9..769ad864d98 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -78,9 +78,9 @@ 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);
+ CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop);
}
}
diff --git a/source/blender/modifiers/intern/MOD_ngoninterp.c b/source/blender/modifiers/intern/MOD_ngoninterp.c
new file mode 100644
index 00000000000..498e5d3bdea
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_ngoninterp.c
@@ -0,0 +1,331 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 by the Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Daniel Dunbar
+ * Ton Roosendaal,
+ * Ben Batt,
+ * Brecht Van Lommel,
+ * Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_mask.c
+ * \ingroup modifiers
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_array.h"
+#include "BLI_edgehash.h"
+#include "BLI_math.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_deform.h"
+
+#include "depsgraph_private.h"
+
+#include "MOD_util.h"
+
+static void copyData(ModifierData *md, ModifierData *target)
+{
+ NgonInterpModifierData *mmd = (NgonInterpModifierData*) md;
+ NgonInterpModifierData *tmmd = (NgonInterpModifierData*) target;
+
+ tmmd->resolution = mmd->resolution;
+}
+
+static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
+ DerivedMesh *derivedData,
+ int UNUSED(useRenderParams),
+ int UNUSED(isFinalCalc))
+{
+ NgonInterpModifierData *nmd= (NgonInterpModifierData *)md;
+ DerivedMesh *dm= derivedData;
+ DerivedMesh *cddm, *dummy;
+ MFace *mf;
+ MPoly *mpoly;
+ MLoop *mloop;
+ MFace *mface = NULL, *mf2;
+ MVert *mvert = NULL, *omvert;
+ BLI_array_declare(mface);
+ BLI_array_declare(mvert);
+ int *verts=NULL, *loops=NULL;
+ BLI_array_declare(verts);
+ BLI_array_declare(loops);
+ float *w = NULL, (*cos)[3] = NULL;
+ BLI_array_declare(w);
+ BLI_array_declare(cos);
+ int *origv = NULL, *origf = NULL, *of, *ov;
+ BLI_array_declare(origv);
+ BLI_array_declare(origf);
+ DerivedMesh *copy = NULL;
+ int i;
+
+ int numTex;
+ int numCol;
+ int hasWCol;
+ int hasOrigSpace;
+
+ if (nmd->resolution <= 0)
+ return dm;
+
+ if (!CDDM_Check(dm)) {
+ dm = copy = CDDM_copy(dm);
+ }
+
+ CDDM_recalc_tesselation(dm);
+
+ mf = dm->getTessFaceArray(dm);
+ of = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ mpoly = CDDM_get_polys(dm);
+ mloop = CDDM_get_loops(dm);
+
+ /*eek!*/
+ if (!of)
+ return dm;
+
+ /*create a dummy mesh to compute interpolated loops on*/
+ dummy = CDDM_from_template(dm, 0, 0, 0, 3, 0);
+
+ /* CustomData we check must match what is passed to mesh_loops_to_mface_corners() */
+ numTex = CustomData_number_of_layers(&dm->polyData, CD_MTEXPOLY);
+ numCol = CustomData_number_of_layers(&dummy->loopData, CD_MLOOPCOL);
+ hasWCol = CustomData_has_layer(&dummy->loopData, CD_WEIGHT_MLOOPCOL);
+ hasOrigSpace = CustomData_has_layer(&dummy->loopData, CD_ORIGSPACE_MLOOP);
+
+ /*copy original verts here, so indices stay correct*/
+ omvert = dm->getVertArray(dm);
+ ov = dm->getVertDataArray(dm, CD_ORIGINDEX);
+ for (i=0; i<dm->numVertData; i++) {
+ BLI_array_append(mvert, omvert[i]);
+ BLI_array_append(origv, ov ? ov[i] : i);
+ }
+
+ for (i=0; i<dm->numTessFaceData; i++, mf++, of++) {
+ int x, y, x2;
+ float fac;
+
+ BLI_array_empty(verts);
+
+#define NG_MAKE_VERT(orig)\
+ BLI_array_append(mvert, omvert[orig]);\
+ BLI_array_append(origv, ov ? ov[orig] : orig);\
+ BLI_array_append(verts, BLI_array_count(mvert)-1);
+
+#define NG_MAKE_VERTCO(orig, coord) NG_MAKE_VERT(orig); copy_v3_v3(mvert[BLI_array_count(mvert)-1].co, coord)
+
+ y = 0;
+ fac = 1.0f / (float)(nmd->resolution + 1);
+ for (x=0; x<nmd->resolution+2; x++) {
+ float co1[3], co2[3], co3[3];
+
+ sub_v3_v3v3(co1, omvert[mf->v1].co, omvert[mf->v3].co);
+ sub_v3_v3v3(co2, omvert[mf->v2].co, omvert[mf->v3].co);
+
+ mul_v3_fl(co1, 1.0f - fac*x);
+ mul_v3_fl(co2, 1.0f - fac*x);
+
+ add_v3_v3(co1, omvert[mf->v3].co);
+ add_v3_v3(co2, omvert[mf->v3].co);
+
+ if (x == 0) {
+ BLI_array_append(verts, mf->v1);
+ } else if (x == nmd->resolution+1) {
+ BLI_array_append(verts, mf->v3);
+ } else {
+ NG_MAKE_VERTCO(mf->v1, co1);
+ }
+
+ for (x2=0; x2<(nmd->resolution-x); x2++) {
+ sub_v3_v3v3(co3, co1, co2);
+ mul_v3_fl(co3, 1.0f - (1.0f/(float)(nmd->resolution-x+1))*(x2+1));
+ add_v3_v3(co3, co2);
+
+ NG_MAKE_VERTCO(mf->v2, co3);
+ }
+
+ if (x == 0) {
+ BLI_array_append(verts, mf->v2);
+ } else if (x != nmd->resolution+1) {
+ NG_MAKE_VERTCO(mf->v1, co2);
+ }
+ }
+
+ y = 0;
+ for (x=0; x<BLI_array_count(verts)-2; x++) {
+ int v1, v2, v3;
+
+ if (x2 == nmd->resolution-y+1) {
+ x2 = 0;
+ y++;
+ continue;
+ } else {
+ /*int lindex[3] = {0, 1, 2};*/ /*UNUSED*/
+
+ v1 = verts[x];
+ v2 = verts[x+1];
+ v3 = verts[x+(nmd->resolution-y)+2];
+
+ BLI_array_growone(mface);
+ BLI_array_growone(origf);
+
+ /*make first face*/
+ origf[BLI_array_count(origf)-1] = *of;
+ mf2 = mface + BLI_array_count(mface)-1;
+ *mf2 = *mf;
+
+ mf2->v1 = v1;
+ mf2->v2 = v2;
+ mf2->v3 = v3;
+ mf2->v4 = 0;
+
+ if (x2 != nmd->resolution-y) {
+ /*make second face*/
+ BLI_array_growone(mface);
+ BLI_array_growone(origf);
+
+ origf[BLI_array_count(origf)-1] = *of;
+ mf2 = mface + BLI_array_count(mface)-1;
+ *mf2 = *mf;
+
+ mf2->v1 = verts[x+(nmd->resolution-y)+3];
+ mf2->v2 = v3;
+ mf2->v3 = v2;
+ mf2->v4 = 0;
+ }
+ }
+
+ x2++;
+ }
+ }
+
+ cddm = CDDM_from_template(dm, BLI_array_count(mvert), dm->numEdgeData, BLI_array_count(mface), 0, 0);
+
+ mf2 = mface;
+ for (i=0; i<BLI_array_count(mface); i++, mf2++) {
+ MPoly *mp = mpoly + *of;
+ MLoop *ml;
+ float co[3], cent[3] = {0.0f, 0.0f, 0.0f};
+ int j, lindex[4] = {0, 1, 2}; /* only ever use 3 in this case */
+
+ BLI_array_empty(w);
+ BLI_array_empty(cos);
+ BLI_array_empty(loops);
+
+ mp = mpoly + origf[i];
+ ml = mloop + mp->loopstart;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ BLI_array_growone(cos);
+ BLI_array_growone(w);
+ BLI_array_append(loops, j+mp->loopstart);
+ copy_v3_v3(cos[j], mvert[ml->v].co);
+ }
+
+ /*scale source face coordinates a bit, so points sitting directly on an
+ edge will work.*/
+ mul_v3_fl(cent, 1.0f/(float)(mp->totloop));
+ for (j=0; j<mp->totloop; j++) {
+ sub_v3_v3(cos[j], cent);
+ mul_v3_fl(cos[j], 1.0f+FLT_EPSILON*1500.0f);
+ add_v3_v3(cos[j], cent);
+ }
+
+ copy_v3_v3(co, (mvert + mf2->v1)->co);
+ interp_weights_poly_v3(w, cos, mp->totloop, co);
+ CustomData_interp(&dm->loopData, &dummy->loopData, loops, w, NULL, mp->totloop, 0);
+
+ copy_v3_v3(co, (mvert + mf2->v2)->co);
+ interp_weights_poly_v3(w, cos, mp->totloop, co);
+ CustomData_interp(&dm->loopData, &dummy->loopData, loops, w, NULL, mp->totloop, 1);
+
+ copy_v3_v3(co, (mvert + mf2->v3)->co);
+ interp_weights_poly_v3(w, cos, mp->totloop, co);
+ CustomData_interp(&dm->loopData, &dummy->loopData, loops, w, NULL, mp->totloop, 2);
+
+ mesh_loops_to_mface_corners(&cddm->faceData, &dummy->loopData, &dm->polyData,
+ lindex, i, origf[i], 3,
+ numTex, numCol, hasWCol, hasOrigSpace);
+ }
+
+ CustomData_copy_data(&dm->vertData, &cddm->vertData, 0, 0, dm->numVertData);
+ CustomData_copy_data(&dm->edgeData, &cddm->edgeData, 0, 0, dm->numEdgeData);
+
+ CDDM_set_mface(cddm, mface);
+ CDDM_set_mvert(cddm, mvert);
+
+ /*set origindex pointer*/
+ MEM_freeN(CustomData_get_layer(&cddm->faceData, CD_ORIGINDEX));
+ CustomData_set_layer(&cddm->faceData, CD_MFACE, mface);
+
+ if (CustomData_has_layer(&cddm->vertData, CD_ORIGINDEX))
+ CustomData_set_layer(&cddm->vertData, CD_ORIGINDEX, origv);
+
+ CustomData_set_layer(&cddm->faceData, CD_ORIGINDEX, origf);
+
+ BLI_array_free(cos);
+ BLI_array_free(w);
+
+ dummy->needsFree = 1;
+ dummy->release(dummy);
+
+ /*create polys from mface triangles*/
+ CDDM_tessfaces_to_faces(cddm); /*builds ngon faces from tess (mface) faces*/
+
+ return cddm;
+}
+
+
+ModifierTypeInfo modifierType_NgonInterp = {
+ /* name */ "NgonInterp",
+ /* structName */ "NgonInterpModifierData",
+ /* structSize */ sizeof(NgonInterpModifierData),
+ /* type */ eModifierTypeType_Constructive,
+ /* flags */ eModifierTypeFlag_AcceptsMesh|eModifierTypeFlag_SupportsMapping|eModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+ /* deformVerts */ 0,
+ /* deformMatrices */ 0,
+ /* deformVertsEM */ 0,
+ /* deformMatricesEM */ 0,
+ /* applyModifier */ applyModifier,
+ /* applyModifierEM */ 0,
+ /* initData */ 0,
+ /* requiredDataMask */ 0,
+ /* freeData */ 0,
+ /* isDisabled */ 0,
+ /* updateDepgraph */ 0,
+ /* dependsOnTime */ 0,
+ /* dependsOnNormals */ 0,
+ /* foreachObjectLink */ 0,
+ /* foreachIDLink */ 0,
+};
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index f79ee0ca5fb..b3553c04cf4 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -269,7 +269,8 @@ static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
DerivedMesh *result;
MVert *mverts;
- MFace *mfaces;
+ MPoly *mpolys;
+ MLoop *mloops;
int *origindex;
int cdlayer;
@@ -280,7 +281,7 @@ static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
const int res_y = ry * omd->repeat_y;
const int num_verts = (res_x + 1) * (res_y + 1);
- const int num_edges = (res_x * res_y * 2) + res_x + res_y;
+ /* const int num_edges = (res_x * res_y * 2) + res_x + res_y; */ /* UNUSED BMESH */
const int num_faces = res_x * res_y;
float sx = omd->size * omd->spatial_size;
@@ -295,11 +296,17 @@ static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
sx /= rx;
sy /= ry;
- result = CDDM_new(num_verts, num_edges, num_faces);
+ result = CDDM_new(num_verts, 0, 0, num_faces * 4, num_faces);
mverts = CDDM_get_verts(result);
- mfaces = CDDM_get_faces(result);
+ mpolys = CDDM_get_polys(result);
+ mloops = CDDM_get_loops(result);
+
+#if 0 // trunk
origindex= result->getFaceDataArray(result, CD_ORIGINDEX);
+#else // bmesh
+ origindex= CustomData_get_layer(&result->polyData, CD_ORIGINDEX);
+#endif
/* create vertices */
#pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
@@ -319,13 +326,22 @@ static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
for (x=0; x < res_x; x++) {
const int fi = y*res_x + x;
const int vi = y*(res_x+1) + x;
- MFace *mf= &mfaces[fi];
- mf->v1 = vi;
- mf->v2 = vi + 1;
- mf->v3 = vi + 1 + res_x+1;
- mf->v4 = vi + res_x+1;
+ MPoly *mp= &mpolys[fi];
+ MLoop *ml= &mloops[fi * 4];
+
+ ml->v = vi;
+ ml++;
+ ml->v = vi + 1;
+ ml++;
+ ml->v = vi + 1 + res_x + 1;
+ ml++;
+ ml->v = vi + res_x + 1;
+ ml++;
+
+ mp->loopstart= fi * 4;
+ mp->totloop= 4;
- mf->flag |= ME_SMOOTH;
+ mp->flag |= ME_SMOOTH;
/* generated geometry does not map to original faces */
origindex[fi] = ORIGINDEX_NONE;
@@ -335,28 +351,35 @@ static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
CDDM_calc_edges(result);
/* add uvs */
- cdlayer= CustomData_number_of_layers(&result->faceData, CD_MTFACE);
+ cdlayer= CustomData_number_of_layers(&result->loopData, CD_MLOOPUV);
if(cdlayer < MAX_MTFACE) {
- MTFace *tfaces= CustomData_add_layer(&result->faceData, CD_MTFACE, CD_CALLOC, NULL, num_faces);
+ MLoopUV *mloopuvs= CustomData_add_layer(&result->loopData, CD_MLOOPUV, CD_CALLOC, NULL, num_faces * 4);
- if (tfaces) { /* unlikely to fail */
+ if (mloopuvs) { /* unlikely to fail */
ix = 1.0 / rx;
iy = 1.0 / ry;
#pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
for (y=0; y < res_y; y++) {
for (x=0; x < res_x; x++) {
const int i = y*res_x + x;
- tfaces[i].uv[0][0] = x * ix;
- tfaces[i].uv[0][1] = y * iy;
+ MLoopUV *luv= &mloopuvs[i * 4];
- tfaces[i].uv[1][0] = (x+1) * ix;
- tfaces[i].uv[1][1] = y * iy;
+ luv->uv[0] = x * ix;
+ luv->uv[1] = y * iy;
+ luv++;
- tfaces[i].uv[2][0] = (x+1) * ix;
- tfaces[i].uv[2][1] = (y+1) * iy;
+ luv->uv[0] = (x+1) * ix;
+ luv->uv[1] = y * iy;
+ luv++;
+
+ luv->uv[0] = (x+1) * ix;
+ luv->uv[1] = (y+1) * iy;
+ luv++;
+
+ luv->uv[0] = x * ix;
+ luv->uv[1] = (y+1) * iy;
+ luv++;
- tfaces[i].uv[3][0] = x * ix;
- tfaces[i].uv[3][1] = (y+1) * iy;
}
}
}
@@ -375,6 +398,7 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
OceanResult ocr;
MVert *mverts, *mv;
+ MLoop *mloops;
int i, j;
@@ -421,29 +445,34 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
cfra -= omd->bakestart; // shift to 0 based
num_verts = dm->getNumVerts(dm);
- num_faces = dm->getNumFaces(dm);
+ num_faces = dm->getNumPolys(dm);
mverts = dm->getVertArray(dm);
+ mloops = dm->getLoopArray(dm);
/* add vcols before displacement - allows lookup based on position */
if (omd->flag & MOD_OCEAN_GENERATE_FOAM) {
- int cdlayer= CustomData_number_of_layers(&dm->faceData, CD_MCOL);
+ int cdlayer= CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL);
if(cdlayer < MAX_MCOL) {
- MCol *mcols= CustomData_add_layer_named(&dm->faceData, CD_MCOL, CD_CALLOC, NULL, num_faces, omd->foamlayername);
+ MLoopCol *mloopcols= CustomData_add_layer_named(&dm->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, num_faces * 4, omd->foamlayername);
- if (mcols) { /* unlikely to fail */
- MCol *mc;
- MFace *mfaces= dm->getFaceArray(dm);
- MFace *mf;
+ if (mloopcols) { /* unlikely to fail */
+ MLoopCol *mlcol;
+ MPoly *mpolys= dm->getPolyArray(dm);
+ MPoly *mp;
float foam;
- for (i = 0, mf= mfaces; i < num_faces; i++, mf++) {
- j= mf->v4 ? 3 : 2;
+ for (i = 0, mp= mpolys; i < num_faces; i++, mp++) {
+ j= mp->totloop - 1;
+
+ /* highly unlikely */
+ if (j <= 0) continue;
+
do {
- const float *co= mverts[*(&mf->v1 + j)].co;
+ const float *co= mverts[mloops[mp->loopstart + j].v].co;
const float u = OCEAN_CO(size_co_inv, co[0]);
const float v = OCEAN_CO(size_co_inv, co[1]);
@@ -457,8 +486,8 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage);
}
- mc= &mcols[i*4 + j];
- mc->r = mc->g = mc->b = (char)(foam * 255);
+ mlcol= &mloopcols[mp->loopstart + j];
+ mlcol->r = mlcol->g = mlcol->b = (char)(foam * 255);
/* mc->a = 255; */ /* no need to set */
} while (j--);
}
@@ -518,7 +547,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
- struct EditMesh *UNUSED(editData),
+ struct BMEditMesh *UNUSED(editData),
DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 509c916941f..3f600947b1a 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -122,6 +122,8 @@ static DerivedMesh * applyModifier(ModifierData *md, Object *ob,
float max_co=0.0, min_co=0.0, temp_co[3], cross[3];
float *size=NULL;
+ DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
+
trackneg=((ob->trackflag>2)?1:0);
if(pimd->ob==ob){
@@ -174,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;
@@ -190,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);
@@ -260,8 +262,8 @@ static DerivedMesh * applyModifier(ModifierData *md, Object *ob,
add_v3_v3(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;
@@ -291,7 +293,7 @@ static DerivedMesh * applyModifier(ModifierData *md, Object *ob,
}
inMF = orig_mface + i%totface;
- DM_copy_face_data(dm, result, i%totface, i, 1);
+ DM_copy_poly_data(dm, result, i%totface, i, 1);
*mf = *inMF;
mf->v1+=(i/totface)*totvert;
@@ -301,8 +303,7 @@ static DerivedMesh * applyModifier(ModifierData *md, Object *ob,
mf->v4+=(i/totface)*totvert;
}
- CDDM_calc_edges(result);
- CDDM_calc_normals(result);
+ CDDM_calc_edges_tessface(result);
if(psys->lattice){
end_latt_deform(psys->lattice);
@@ -312,10 +313,13 @@ static DerivedMesh * applyModifier(ModifierData *md, Object *ob,
if(size)
MEM_freeN(size);
+ CDDM_tessfaces_to_faces(result); /*builds ngon faces from tess (mface) faces*/
+ CDDM_calc_normals(result);
+
return result;
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
- struct EditMesh *UNUSED(editData),
+ struct BMEditMesh *UNUSED(editData),
DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index 5ce2437b8ea..10e43afebe2 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -112,7 +112,7 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
/* particles only need this if they are after a non deform modifier, and
* the modifier stack will only create them in that case. */
- dataMask |= CD_MASK_ORIGSPACE|CD_MASK_ORIGINDEX;
+ dataMask |= CD_MASK_ORIGSPACE_MLOOP|CD_MASK_ORIGINDEX;
dataMask |= CD_MASK_ORCO;
@@ -179,13 +179,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_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index bc67237fb40..ec893a3bf44 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -82,9 +82,9 @@ static void init_dualcon_mesh(DualConInput *mesh, DerivedMesh *dm)
mesh->co_stride = sizeof(MVert);
mesh->totco = dm->getNumVerts(dm);
- mesh->faces = (void*)dm->getFaceArray(dm);
+ mesh->faces = (void*)dm->getTessFaceArray(dm);
mesh->face_stride = sizeof(MFace);
- mesh->totface = dm->getNumFaces(dm);
+ mesh->totface = dm->getNumTessFaces(dm);
dm->getMinMax(dm, mesh->min, mesh->max);
}
@@ -105,7 +105,7 @@ static void *dualcon_alloc_output(int totvert, int totquad)
"DualConOutput")))
return NULL;
- output->dm = CDDM_new(totvert, 0, totquad);
+ output->dm = CDDM_new(totvert, 0, 0, 4*totquad, totquad);
return output;
}
@@ -124,18 +124,21 @@ static void dualcon_add_quad(void *output_v, const int vert_indices[4])
{
DualConOutput *output = output_v;
DerivedMesh *dm = output->dm;
- MFace *mface;
+ MLoop *mloop;
+ MPoly *cur_poly;
+ int i;
- assert(output->curface < dm->getNumFaces(dm));
+ assert(output->curface < dm->getNumPolys(dm));
- mface = &CDDM_get_faces(dm)[output->curface];
- mface->v1 = vert_indices[0];
- mface->v2 = vert_indices[1];
- mface->v3 = vert_indices[2];
- mface->v4 = vert_indices[3];
+ mloop = CDDM_get_loops(dm);
+ cur_poly = CDDM_get_poly(dm, output->curface);
- if(test_index_face(mface, NULL, 0, 4))
- output->curface++;
+ cur_poly->loopstart = output->curface * 4;
+ cur_poly->totloop = 4;
+ for(i = 0; i < 4; i++)
+ mloop[output->curface * 4 + i].v = vert_indices[i];
+
+ output->curface++;
}
static DerivedMesh *applyModifier(ModifierData *md,
@@ -151,6 +154,8 @@ static DerivedMesh *applyModifier(ModifierData *md,
DualConFlags flags = 0;
DualConMode mode = 0;
+ DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
+
rmd = (RemeshModifierData*)md;
init_dualcon_mesh(&input, dm);
@@ -181,12 +186,10 @@ static DerivedMesh *applyModifier(ModifierData *md,
rmd->scale,
rmd->depth);
result = output->dm;
- CDDM_lower_num_faces(result, output->curface);
MEM_freeN(output);
CDDM_calc_edges(result);
CDDM_calc_normals(result);
-
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 93abbb1780c..8ff4080b99b 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -132,6 +132,23 @@ static void copyData(ModifierData *md, ModifierData *target)
tltmd->iter= sltmd->iter;
}
+#if 0
+static int findEd(MEdge *medge_new, int toted, int v1, int v2)
+{
+ int i;
+
+ for (i = 0; i < toted; i++) {
+ if ( (medge_new[i].v1 == v1 && medge_new[i].v2 == v2) ||
+ (medge_new[i].v1 == v2 && medge_new[i].v2 == v1) )
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+#endif
+
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
int useRenderParams,
@@ -142,13 +159,13 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
ScrewModifierData *ltmd= (ScrewModifierData*) md;
int *origindex;
- int mface_index=0;
+ int mpoly_index=0;
int step;
int i, j;
unsigned int i1, i2;
int step_tot= useRenderParams ? ltmd->render_steps : ltmd->steps;
const int do_flip = ltmd->flag & MOD_SCREW_NORMAL_FLIP ? 1 : 0;
- int maxVerts=0, maxEdges=0, maxFaces=0;
+ int maxVerts=0, maxEdges=0, maxPolys=0;
const unsigned int totvert= dm->getNumVerts(dm);
const unsigned int totedge= dm->getNumEdges(dm);
@@ -165,8 +182,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
int vc_tot_linked= 0;
short other_axis_1, other_axis_2;
float *tmpf1, *tmpf2;
+
+ int edge_offset;
- MFace *mface_new, *mf_new;
+ MPoly *mpoly_new, *mp_new;
+ MLoop *mloop_new, *ml_new;
MEdge *medge_orig, *med_orig, *med_new, *med_new_firstloop, *medge_new;
MVert *mvert_new, *mvert_orig, *mv_orig, *mv_new, *mv_new_base;
@@ -174,7 +194,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:
@@ -278,7 +298,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
maxVerts = totvert * step_tot; /* -1 because we're joining back up */
maxEdges = (totvert * step_tot) + /* these are the edges between new verts */
(totedge * step_tot); /* -1 because vert edges join */
- maxFaces = totedge * step_tot;
+ maxPolys = totedge * step_tot;
screw_ofs= 0.0f;
}
@@ -289,20 +309,29 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
maxVerts = totvert * step_tot; /* -1 because we're joining back up */
maxEdges = (totvert * (step_tot-1)) + /* these are the edges between new verts */
(totedge * step_tot); /* -1 because vert edges join */
- maxFaces = totedge * (step_tot-1);
+ maxPolys = totedge * (step_tot-1);
}
- result= CDDM_from_template(dm, maxVerts, maxEdges, maxFaces);
+ result= CDDM_from_template(dm, maxVerts, maxEdges, 0, maxPolys * 4, maxPolys);
/* copy verts from mesh */
mvert_orig = dm->getVertArray(dm);
medge_orig = dm->getEdgeArray(dm);
mvert_new = result->getVertArray(result);
- mface_new = result->getFaceArray(result);
+ mpoly_new = result->getPolyArray(result);
+ mloop_new = result->getLoopArray(result);
medge_new = result->getEdgeArray(result);
-
- origindex= result->getFaceDataArray(result, CD_ORIGINDEX);
+
+ if (!CustomData_has_layer(&result->polyData, CD_ORIGINDEX)) {
+ CustomData_add_layer(&result->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, maxPolys);
+ }
+
+#if 0 // trunk
+ origindex = result->getPolyDataArray(result, CD_ORIGINDEX);
+#else // bmesh
+ origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);
+#endif
DM_copy_vert_data(dm, result, 0, 0, totvert); /* copy first otherwise this overwrites our own vertex normals */
@@ -746,9 +775,13 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
}
- mf_new= mface_new;
+ mp_new= mpoly_new;
+ ml_new= mloop_new;
med_new_firstloop= medge_new;
+ /* more of an offset in this case */
+ edge_offset = totedge + (totvert * (step_tot - (close ? 0 : 1)));
+
for (i=0; i < totedge; i++, med_new_firstloop++) {
/* for each edge, make a cylinder of quads */
i1= med_new_firstloop->v1;
@@ -758,26 +791,36 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
/* new face */
if(do_flip) {
- mf_new->v4= i1;
- mf_new->v3= i2;
- mf_new->v2= i2 + totvert;
- mf_new->v1= i1 + totvert;
+ ml_new[3].v = i1;
+ ml_new[2].v = i2;
+ ml_new[1].v = i2 + totvert;
+ ml_new[0].v = i1 + totvert;
+
+ ml_new[2].e = step == 0 ? i : (edge_offset + step + (i * (step_tot - 1))) - 1;
+ ml_new[1].e = totedge + i2;
+ ml_new[0].e = edge_offset + step + (i * (step_tot - 1));
+ ml_new[3].e = totedge + i1;
}
else {
- mf_new->v1= i1;
- mf_new->v2= i2;
- mf_new->v3= i2 + totvert;
- mf_new->v4= i1 + totvert;
- }
-
- if( !mf_new->v3 || !mf_new->v4 ) {
- SWAP(unsigned int, mf_new->v1, mf_new->v3);
- SWAP(unsigned int, mf_new->v2, mf_new->v4);
+ ml_new[0].v = i1;
+ ml_new[1].v = i2;
+ ml_new[2].v = i2 + totvert;
+ ml_new[3].v = i1 + totvert;
+
+ ml_new[0].e = step == 0 ? i : (edge_offset + step + (i * (step_tot - 1))) - 1;
+ ml_new[1].e = totedge + i2;
+ ml_new[2].e = edge_offset + step + (i * (step_tot - 1));
+ ml_new[3].e = totedge + i1;
}
- mf_new->flag= ME_SMOOTH;
- origindex[mface_index]= ORIGINDEX_NONE;
- mf_new++;
- mface_index++;
+
+
+ mp_new->loopstart = mpoly_index * 4;
+ mp_new->totloop = 4;
+ mp_new->flag= ME_SMOOTH;
+ origindex[mpoly_index]= ORIGINDEX_NONE;
+ mp_new++;
+ ml_new += 4;
+ mpoly_index++;
/* new vertical edge */
if (step) { /* The first set is already dome */
@@ -794,26 +837,35 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
/* close the loop*/
if (close) {
if(do_flip) {
- mf_new->v4= i1;
- mf_new->v3= i2;
- mf_new->v2= med_new_firstloop->v2;
- mf_new->v1= med_new_firstloop->v1;
+ ml_new[3].v = i1;
+ ml_new[2].v = i2;
+ ml_new[1].v = med_new_firstloop->v2;
+ ml_new[0].v = med_new_firstloop->v1;
+
+ ml_new[2].e = (edge_offset + step + (i * (step_tot - 1))) - 1;
+ ml_new[1].e = totedge + i2;
+ ml_new[0].e = i;
+ ml_new[3].e = totedge + i1;
}
else {
- mf_new->v1= i1;
- mf_new->v2= i2;
- mf_new->v3= med_new_firstloop->v2;
- mf_new->v4= med_new_firstloop->v1;
+ ml_new[0].v = i1;
+ ml_new[1].v = i2;
+ ml_new[2].v = med_new_firstloop->v2;
+ ml_new[3].v = med_new_firstloop->v1;
+
+ ml_new[0].e = (edge_offset + step + (i * (step_tot - 1))) - 1;
+ ml_new[1].e = totedge + i2;
+ ml_new[2].e = i;
+ ml_new[3].e = totedge + i1;
}
- if( !mf_new->v3 || !mf_new->v4 ) {
- SWAP(unsigned int, mf_new->v1, mf_new->v3);
- SWAP(unsigned int, mf_new->v2, mf_new->v4);
- }
- mf_new->flag= ME_SMOOTH;
- origindex[mface_index]= ORIGINDEX_NONE;
- mf_new++;
- mface_index++;
+ mp_new->loopstart = mpoly_index * 4;
+ mp_new->totloop = 4;
+ mp_new->flag= ME_SMOOTH;
+ origindex[mpoly_index]= ORIGINDEX_NONE;
+ mp_new++;
+ ml_new += 4;
+ mpoly_index++;
}
/* new vertical edge */
@@ -823,8 +875,37 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
med_new->crease= med_new_firstloop->crease;
med_new++;
}
-
+
+ /* validate loop edges */
+#if 0
+ {
+ i = 0;
+ printf("\n");
+ for ( ; i < maxPolys * 4; i += 4) {
+ int ii;
+ ml_new = mloop_new + i;
+ ii = findEd(medge_new, maxEdges, ml_new[0].v, ml_new[1].v);
+ printf("%d %d -- ", ii, ml_new[0].e);
+ ml_new[0].e = ii;
+
+ ii = findEd(medge_new, maxEdges, ml_new[1].v, ml_new[2].v);
+ printf("%d %d -- ", ii, ml_new[1].e);
+ ml_new[1].e = ii;
+
+ ii = findEd(medge_new, maxEdges, ml_new[2].v, ml_new[3].v);
+ printf("%d %d -- ", ii, ml_new[2].e);
+ ml_new[2].e = ii;
+
+ ii = findEd(medge_new, maxEdges, ml_new[3].v, ml_new[0].v);
+ printf("%d %d\n", ii, ml_new[3].e);
+ ml_new[3].e = ii;
+
+ }
+ }
+#endif
+
if((ltmd->flag & MOD_SCREW_NORMAL_CALC) == 0) {
+ /* BMESH_TODO, we only need to get vertex normals here, this is way overkill */
CDDM_calc_normals(result);
}
@@ -862,7 +943,7 @@ static void foreachObjectLink(
static DerivedMesh *applyModifierEM(
ModifierData *md,
Object *ob,
- struct EditMesh *UNUSED(editData),
+ struct BMEditMesh *UNUSED(editData),
DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c
index 9080ca39ebf..8a93a8a6d6f 100644
--- a/source/blender/modifiers/intern/MOD_shapekey.c
+++ b/source/blender/modifiers/intern/MOD_shapekey.c
@@ -90,7 +90,7 @@ static void deformMatrices(ModifierData *md, Object *ob, DerivedMesh *derivedDat
}
static void deformVertsEM(ModifierData *md, Object *ob,
- struct EditMesh *UNUSED(editData),
+ struct BMEditMesh *UNUSED(editData),
DerivedMesh *derivedData,
float (*vertexCos)[3],
int numVerts)
@@ -102,7 +102,7 @@ static void deformVertsEM(ModifierData *md, Object *ob,
}
static void deformMatricesEM(ModifierData *UNUSED(md), Object *ob,
- struct EditMesh *UNUSED(editData),
+ struct BMEditMesh *UNUSED(editData),
DerivedMesh *UNUSED(derivedData),
float (*vertexCos)[3],
float (*defMats)[3][3],
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index e8f099785f9..1d68e201dc0 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -128,7 +128,7 @@ static void deformVerts(ModifierData *md, Object *ob,
dm->release(dm);
}
-static void deformVertsEM(ModifierData *md, Object *ob, struct EditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+static void deformVertsEM(ModifierData *md, Object *ob, struct BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *dm = derivedData;
CustomDataMask dataMask = requiredDataMask(ob, md);
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index 2c056ad4021..4485346bf55 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -336,7 +336,7 @@ static void deformVerts(ModifierData *md, Object *ob,
}
static void deformVertsEM(ModifierData *md, Object *ob,
- struct EditMesh *editData,
+ struct BMEditMesh *editData,
DerivedMesh *derivedData,
float (*vertexCos)[3],
int numVerts)
diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c
index e43304bc4b9..01b012655d0 100644
--- a/source/blender/modifiers/intern/MOD_smooth.c
+++ b/source/blender/modifiers/intern/MOD_smooth.c
@@ -226,7 +226,7 @@ static void deformVerts(
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct EditMesh *editData,
+ ModifierData *md, Object *ob, struct BMEditMesh *editData,
DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *dm= get_dm(ob, editData, derivedData, NULL, 0);
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index d16fa0c503c..fd6d0f602a9 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -35,13 +35,14 @@
#include "DNA_meshdata_types.h"
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_edgehash.h"
-#include "BLI_utildefines.h"
+#include "BLI_array.h"
#include "BLI_string.h"
-#include "MEM_guardedalloc.h"
-
#include "BKE_cdderivedmesh.h"
#include "BKE_mesh.h"
#include "BKE_particle.h"
@@ -59,7 +60,8 @@ typedef struct EdgeFaceRef {
static void dm_calc_normal(DerivedMesh *dm, float (*temp_nors)[3])
{
int i, numVerts, numEdges, numFaces;
- MFace *mface, *mf;
+ MPoly *mpoly, *mp;
+ MLoop *mloop, *ml;
MVert *mvert, *mv;
float (*face_nors)[3];
@@ -68,10 +70,11 @@ 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);
+ numFaces = dm->getNumPolys(dm);
+ mpoly = dm->getPolyArray(dm);
mvert = dm->getVertArray(dm);
-
+ mloop = dm->getLoopArray(dm);
+
/* we don't want to overwrite any referenced layers */
/*
@@ -80,14 +83,14 @@ static void dm_calc_normal(DerivedMesh *dm, float (*temp_nors)[3])
cddm->mvert = mv;
*/
- face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
+ face_nors = CustomData_get_layer(&dm->polyData, CD_NORMAL);
if(!face_nors) {
calc_face_nors = 1;
- face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC, NULL, numFaces);
+ face_nors = CustomData_add_layer(&dm->polyData, CD_NORMAL, CD_CALLOC, NULL, numFaces);
}
mv = mvert;
- mf = mface;
+ mp = mpoly;
{
EdgeHash *edge_hash = BLI_edgehash_new();
@@ -116,24 +119,16 @@ static void dm_calc_normal(DerivedMesh *dm, float (*temp_nors)[3])
}
/* --- end define --- */
- for(i = 0; i < numFaces; i++, mf++) {
+ for(i = 0; i < numFaces; i++, mp++) {
+ int j;
+
f_no = face_nors[i];
+ if(calc_face_nors)
+ mesh_calc_poly_normal(mp, mloop+mp->loopstart, mvert, f_no);
- if(mf->v4) {
- if(calc_face_nors)
- normal_quad_v3(f_no, mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co, mv[mf->v4].co);
-
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v1, mf->v2);
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v2, mf->v3);
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v3, mf->v4);
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v4, mf->v1);
- } else {
- if(calc_face_nors)
- normal_tri_v3(f_no, mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co);
-
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v1, mf->v2);
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v2, mf->v3);
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(mf->v3, mf->v1);
+ ml = mloop + mp->loopstart;
+ for (j=0; j<mp->totloop; j++, ml++) {
+ NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(ml->v, ME_POLY_LOOP_NEXT(mloop, mp, j)->v);
}
}
@@ -212,14 +207,16 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DerivedMesh *result;
const SolidifyModifierData *smd = (SolidifyModifierData*) md;
- MFace *mf, *mface, *orig_mface;
- MEdge *ed, *medge, *orig_medge;
MVert *mv, *mvert, *orig_mvert;
-
+ MEdge *ed, *medge, *orig_medge;
+ MLoop *ml, *mloop, *orig_mloop;
+ MPoly *mp, *mpoly, *orig_mpoly;
const int numVerts = dm->getNumVerts(dm);
const int numEdges = dm->getNumEdges(dm);
- const int numFaces = dm->getNumFaces(dm);
-
+ const int numFaces = dm->getNumPolys(dm);
+ int numLoops=0, newLoops=0, newFaces=0, newEdges=0;
+ int j;
+
/* only use material offsets if we have 2 or more materials */
const short mat_nr_max= ob->totcol > 1 ? ob->totcol - 1 : 0;
const short mat_ofs= mat_nr_max ? smd->mat_ofs : 0;
@@ -227,14 +224,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
/* use for edges */
int *new_vert_arr= NULL;
- int newFaces = 0;
-
+ BLI_array_declare(new_vert_arr);
int *new_edge_arr= NULL;
- int newEdges = 0;
+ BLI_array_declare(new_edge_arr);
+ int *old_vert_arr = MEM_callocN(sizeof(int)*numVerts, "old_vert_arr in solidify");
int *edge_users= NULL;
char *edge_order= NULL;
-
+ int *edge_origIndex;
+
float (*vert_nors)[3]= NULL;
const float ofs_orig= - (((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
@@ -249,9 +247,13 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
- orig_mface = dm->getFaceArray(dm);
- orig_medge = dm->getEdgeArray(dm);
+ numLoops = dm->numLoopData;
+ newLoops = 0;
+
orig_mvert = dm->getVertArray(dm);
+ orig_medge = dm->getEdgeArray(dm);
+ orig_mloop = dm->getLoopArray(dm);
+ orig_mpoly = dm->getPolyArray(dm);
if(smd->flag & MOD_SOLIDIFY_RIM) {
EdgeHash *edgehash = BLI_edgehash_new();
@@ -289,28 +291,19 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
edge_users= MEM_mallocN(sizeof(int) * numEdges, "solid_mod edges");
edge_order= MEM_mallocN(sizeof(char) * numEdges, "solid_mod eorder");
memset(edge_users, INVALID_UNUSED, sizeof(int) * numEdges);
-
- for(i=0, mf=orig_mface; i<numFaces; i++, mf++) {
- if(mf->v4) {
- ADD_EDGE_USER(mf->v1, mf->v2, 0);
- ADD_EDGE_USER(mf->v2, mf->v3, 1);
- ADD_EDGE_USER(mf->v3, mf->v4, 2);
- ADD_EDGE_USER(mf->v4, mf->v1, 3);
- }
- else {
- ADD_EDGE_USER(mf->v1, mf->v2, 0);
- ADD_EDGE_USER(mf->v2, mf->v3, 1);
- ADD_EDGE_USER(mf->v3, mf->v1, 2);
- }
+
+ for (i=0, mp=orig_mpoly; i<numFaces; i++, mp++) {
+ MLoop *ml;
+
+ for (ml=orig_mloop + mp->loopstart, j=0; j<mp->totloop; ml++, j++) {
+ ADD_EDGE_USER(ml->v, ME_POLY_LOOP_NEXT(orig_mloop, mp, j)->v, j);
+ }
}
#undef ADD_EDGE_USER
#undef INVALID_UNUSED
#undef INVALID_PAIR
-
- new_edge_arr= MEM_callocN(sizeof(int) * numEdges, "solid_mod arr");
-
ehi= BLI_edgehashIterator_new(edgehash);
for(; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
eidx= GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi));
@@ -318,18 +311,17 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
BLI_edgehashIterator_getKey(ehi, &v1, &v2);
orig_mvert[v1].flag |= ME_VERT_TMP_TAG;
orig_mvert[v2].flag |= ME_VERT_TMP_TAG;
- new_edge_arr[newFaces]= eidx;
+ BLI_array_append(new_edge_arr, eidx);
newFaces++;
+ newLoops += 4;
}
}
BLI_edgehashIterator_free(ehi);
-
-
- new_vert_arr= MEM_callocN(sizeof(int) * numVerts, "solid_mod new_varr");
for(i=0, mv=orig_mvert; i<numVerts; i++, mv++) {
if(mv->flag & ME_VERT_TMP_TAG) {
- new_vert_arr[newEdges] = i;
+ old_vert_arr[i] = BLI_array_count(new_vert_arr);
+ BLI_array_append(new_vert_arr, i);
newEdges++;
mv->flag &= ~ME_VERT_TMP_TAG;
@@ -344,14 +336,12 @@ 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, 0, (numLoops*2) + newLoops, (numFaces * 2) + newFaces);
- mface = result->getFaceArray(result);
- medge = result->getEdgeArray(result);
- mvert = result->getVertArray(result);
-
- DM_copy_face_data(dm, result, 0, 0, numFaces);
- DM_copy_face_data(dm, result, 0, numFaces, numFaces);
+ mpoly = CDDM_get_polys(result);
+ mloop = CDDM_get_loops(result);
+ medge = CDDM_get_edges(result);
+ mvert = CDDM_get_verts(result);
DM_copy_edge_data(dm, result, 0, 0, numEdges);
DM_copy_edge_data(dm, result, 0, numEdges, numEdges);
@@ -359,29 +349,40 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DM_copy_vert_data(dm, result, 0, 0, numVerts);
DM_copy_vert_data(dm, result, 0, numVerts, numVerts);
- {
- static int corner_indices[4] = {2, 1, 0, 3};
- unsigned int is_quad;
-
- for(i=0, mf=mface+numFaces; i<numFaces; i++, mf++) {
- mf->v1 += numVerts;
- mf->v2 += numVerts;
- mf->v3 += numVerts;
- if(mf->v4)
- mf->v4 += numVerts;
-
- /* Flip face normal */
- {
- is_quad = mf->v4;
- SWAP(unsigned int, mf->v1, mf->v3);
- DM_swap_face_data(result, i+numFaces, corner_indices);
- test_index_face(mf, &result->faceData, numFaces, is_quad ? 4:3);
- }
+ DM_copy_loop_data(dm, result, 0, 0, numLoops);
+ DM_copy_loop_data(dm, result, 0, numLoops, numLoops);
+
+ DM_copy_poly_data(dm, result, 0, 0, numFaces);
+ DM_copy_poly_data(dm, result, 0, numFaces, numFaces);
+
+ /*flip normals*/
+ mp = mpoly + numFaces;
+ for (i=0; i<dm->numPolyData; i++, mp++) {
+ MLoop *ml2;
+ int e;
+
+ ml2 = mloop + mp->loopstart + dm->numLoopData;
+ for (j=0; j<mp->totloop; j++) {
+ CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart+j,
+ mp->loopstart+(mp->totloop-j-1)+dm->numLoopData, 1);
+ }
- if(mat_ofs) {
- mf->mat_nr += mat_ofs;
- CLAMP(mf->mat_nr, 0, mat_nr_max);
- }
+ if(mat_ofs) {
+ mp->mat_nr += mat_ofs;
+ CLAMP(mp->mat_nr, 0, mat_nr_max);
+ }
+
+ e = ml2[0].e;
+ for (j=0; j<mp->totloop-1; j++) {
+ ml2[j].e = ml2[j+1].e;
+ }
+ ml2[mp->totloop-1].e = e;
+
+ mp->loopstart += dm->numLoopData;
+
+ for (j=0; j<mp->totloop; j++) {
+ ml2[j].e += numEdges;
+ ml2[j].v += numVerts;
}
}
@@ -436,12 +437,13 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
/* same as EM_solidify() in editmesh_lib.c */
float *vert_angles= MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */
float *vert_accum= vert_angles + numVerts;
- float face_angles[4];
+ float *face_angles = NULL;
+ BLI_array_staticdeclare(face_angles, 16); /* BM_NGON_STACK_SIZE */
int j, vidx;
- face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
+ face_nors = CustomData_get_layer(&dm->polyData, CD_NORMAL);
if(!face_nors) {
- face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC, NULL, dm->numFaceData);
+ face_nors = CustomData_add_layer(&dm->polyData, CD_NORMAL, CD_CALLOC, NULL, dm->numPolyData);
face_nors_calc= 1;
}
@@ -452,31 +454,31 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
}
- for(i=0, mf=mface; i<numFaces; i++, mf++) {
-
+ for (i=0, mp=mpoly; i<numFaces; i++, mp++) {
+ mesh_calc_poly_normal(mp, &mloop[mp->loopstart], mvert, face_nors[i]);
+
/* just added, calc the normal */
- if(face_nors_calc) {
- if(mf->v4)
- normal_quad_v3(face_nors[i], mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co);
- else
- normal_tri_v3(face_nors[i] , mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co);
+ BLI_array_empty(face_angles);
+ for (j=0, ml=mloop+mp->loopstart; j<mp->totloop; j++, ml++) {
+ MLoop *ml_prev = ME_POLY_LOOP_PREV(mloop, mp, j);
+ MLoop *ml_next = ME_POLY_LOOP_NEXT(mloop, mp, j);
+
+ float e1[3], e2[3], angle;
+
+ sub_v3_v3v3(e1, mvert[ml_next->v].co, mvert[ml->v].co);
+ sub_v3_v3v3(e2, mvert[ml_prev->v].co, mvert[ml->v].co);
+ angle = M_PI - angle_normalized_v3v3(e1, e2);
+ BLI_array_append(face_angles, angle);
}
-
- if(mf->v4) {
- angle_quad_v3(face_angles, mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co);
- j= 3;
- }
- else {
- angle_tri_v3(face_angles, mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co);
- j= 2;
- }
-
- do {
- vidx = *(&mf->v1 + j);
+
+ for (j=0, ml=mloop+mp->loopstart; j<mp->totloop; j++, ml++) {
+ vidx = ml->v;
vert_accum[vidx] += face_angles[j];
vert_angles[vidx]+= shell_angle_to_dist(angle_normalized_v3v3(vert_nors[vidx], face_nors[i])) * face_angles[j];
- } while(j--);
+ }
}
+
+ BLI_array_free(face_angles);
/* vertex group support */
if(dvert) {
@@ -554,19 +556,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
const unsigned char crease_outer= smd->crease_outer * 255.0f;
const unsigned char crease_inner= smd->crease_inner * 255.0f;
- const int edge_indices[2][4][4] = {
- /* quad */
- {{1, 0, 0, 1},
- {2, 1, 1, 2},
- {3, 2, 2, 3},
- {0, 3, 3, 0}},
- /* tri */
- {{1, 0, 0, 1},
- {2, 1, 1, 2},
- {0, 2, 2, 0},
- {0, 0, 0, 0}} /* unused for tris */
- };
-
/* add faces & edges */
origindex= result->getEdgeDataArray(result, CD_ORIGINDEX);
ed= medge + (numEdges * 2);
@@ -582,13 +571,16 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
/* faces */
- mf= mface + (numFaces * 2);
-
- for(i=0; i<newFaces; i++, mf++) {
+ edge_origIndex = origindex;
+ origindex = DM_get_poly_data_layer(result, CD_ORIGINDEX);
+
+ mp = mpoly + (numFaces * 2);
+ ml = mloop + (numLoops * 2);
+ j = 0;
+ for(i=0; i<newFaces; i++, mp++) {
int eidx= new_edge_arr[i];
int fidx= edge_users[eidx];
- int flip;
- int is_tri;
+ int flip, k1, k2;
if(fidx >= numFaces) {
fidx -= numFaces;
@@ -601,31 +593,59 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
ed= medge + eidx;
/* copy most of the face settings */
- DM_copy_face_data(dm, result, fidx, (numFaces * 2) + i, 1);
+ DM_copy_poly_data(dm, result, fidx, (numFaces * 2) + i, 1);
+ mp->loopstart = j+numLoops*2;
+ mp->flag = mpoly[fidx].flag;
- is_tri = (orig_mface[fidx].v4 == 0);
+ /* notice we use 'mp->totloop' which is later overwritten,
+ * we could lookup the original face but theres no point since this is a copy
+ * and will have the same value, just take care when changing order of assignment */
+ k1 = mpoly[fidx].loopstart + ((edge_order[eidx] + 1) % mp->totloop);
+ k2 = mpoly[fidx].loopstart + (edge_order[eidx]);
- if(flip) {
- DM_swap_face_data(result, (numFaces * 2) + i, edge_indices[is_tri][edge_order[eidx]]);
+ mp->totloop = 4;
+
+ CustomData_copy_data(&dm->loopData, &result->loopData, k1, numLoops*2+j+0, 1);
+ CustomData_copy_data(&dm->loopData, &result->loopData, k2, numLoops*2+j+1, 1);
+ CustomData_copy_data(&dm->loopData, &result->loopData, k2, numLoops*2+j+2, 1);
+ CustomData_copy_data(&dm->loopData, &result->loopData, k1, numLoops*2+j+3, 1);
- mf->v1= ed->v1;
- mf->v2= ed->v2;
- mf->v3= ed->v2 + numVerts;
- mf->v4= ed->v1 + numVerts;
+ if(flip) {
+ ml[j].v = ed->v1;
+ ml[j++].e = eidx;
+
+ ml[j].v = ed->v2;
+ ml[j++].e = numEdges*2 + old_vert_arr[ed->v2];
+
+ ml[j].v = ed->v2+numVerts;
+ ml[j++].e = eidx+numEdges;
+
+ ml[j].v = ed->v1+numVerts;
+ ml[j++].e = numEdges*2 + old_vert_arr[ed->v1];
}
else {
- DM_swap_face_data(result, (numFaces * 2) + i, edge_indices[is_tri][edge_order[eidx]]);
+ ml[j].v = ed->v2;
+ ml[j++].e = eidx;
+
+ ml[j].v = ed->v1;
+ ml[j++].e = numEdges*2 + old_vert_arr[ed->v1];
- mf->v1= ed->v2;
- mf->v2= ed->v1;
- mf->v3= ed->v1 + numVerts;
- mf->v4= ed->v2 + numVerts;
+ ml[j].v = ed->v1+numVerts;
+ ml[j++].e = eidx+numEdges;
+
+ ml[j].v = ed->v2+numVerts;
+ ml[j++].e = numEdges*2 + old_vert_arr[ed->v2];
}
+ if (edge_origIndex) {
+ edge_origIndex[ml[j-3].e] = ORIGINDEX_NONE;
+ edge_origIndex[ml[j-1].e] = ORIGINDEX_NONE;
+ }
+
/* use the next material index if option enabled */
if(mat_ofs_rim) {
- mf->mat_nr += mat_ofs_rim;
- CLAMP(mf->mat_nr, 0, mat_nr_max);
+ mp->mat_nr += mat_ofs_rim;
+ CLAMP(mp->mat_nr, 0, mat_nr_max);
}
if(crease_outer) {
/* crease += crease_outer; without wrapping */
@@ -642,7 +662,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
#ifdef SOLIDIFY_SIDE_NORMALS
- normal_quad_v3(nor, mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co);
+ normal_quad_v3(nor, mvert[ml[j-4].v].co, mvert[ml[j-3].v].co, mvert[ml[j-2].v].co, mvert[ml[j-1].v].co);
add_v3_v3(edge_vert_nos[ed->v1], nor);
add_v3_v3(edge_vert_nos[ed->v2], nor);
@@ -671,12 +691,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
MEM_freeN(edge_vert_nos);
#endif
- MEM_freeN(new_vert_arr);
- MEM_freeN(new_edge_arr);
+ BLI_array_free(new_vert_arr);
+ BLI_array_free(new_edge_arr);
MEM_freeN(edge_users);
MEM_freeN(edge_order);
}
+ if (old_vert_arr)
+ MEM_freeN(old_vert_arr);
+
/* must recalculate normals with vgroups since they can displace unevenly [#26888] */
if(dvert) {
CDDM_calc_normals(result);
@@ -689,7 +712,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
static DerivedMesh *applyModifierEM(ModifierData *md,
Object *ob,
- struct EditMesh *UNUSED(editData),
+ struct BMEditMesh *UNUSED(editData),
DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index d42c95a4ce8..5d6d6c2e82c 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -110,7 +110,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *UNUSED(ob),
- struct EditMesh *UNUSED(editData),
+ struct BMEditMesh *UNUSED(editData),
DerivedMesh *derivedData)
{
SubsurfModifierData *smd = (SubsurfModifierData*) md;
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index 258627e8481..7e85acd47e9 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -158,7 +158,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 aa8f578942c..6a84346b69e 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -93,29 +93,31 @@ void get_texture_coords(MappingInfoModifierData *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 *mf;
+ if(CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
+ MPoly *mpoly = dm->getPolyArray(dm);
+ MPoly *mp;
+ MLoop *mloop = dm->getLoopArray(dm);
char *done = MEM_callocN(sizeof(*done) * numVerts,
"get_texture_coords done");
- int numFaces = dm->getNumFaces(dm);
+ int numPolys = dm->getNumPolys(dm);
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
- MTFace *tf;
+ MLoopUV *mloop_uv;
- CustomData_validate_layer_name(&dm->faceData, CD_MTFACE, dmd->uvlayer_name, uvname);
- tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname);
+ CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, dmd->uvlayer_name, uvname);
+ mloop_uv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);
/* verts are given the UV from the first face that uses them */
- for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tf) {
- unsigned int fidx= mf->v4 ? 3:2;
+ for(i = 0, mp = mpoly; i < numPolys; ++i, ++mp) {
+ unsigned int fidx= mp->totloop - 1;
do {
- unsigned int vidx = *(&mf->v1 + fidx);
+ unsigned int lidx= mp->loopstart + fidx;
+ unsigned int vidx= mloop[lidx].v;
if (done[vidx] == 0) {
/* remap UVs from [0, 1] to [-1, 1] */
- texco[vidx][0] = (tf->uv[fidx][0] * 2.0f) - 1.0f;
- texco[vidx][1] = (tf->uv[fidx][1] * 2.0f) - 1.0f;
+ texco[vidx][0] = (mloop_uv[lidx].uv[0] * 2.0f) - 1.0f;
+ texco[vidx][1] = (mloop_uv[lidx].uv[1] * 2.0f) - 1.0f;
done[vidx] = 1;
}
@@ -157,7 +159,7 @@ void modifier_vgroup_cache(ModifierData *md, float (*vertexCos)[3])
}
/* returns a cdderivedmesh if dm == NULL or is another type of derivedmesh */
-DerivedMesh *get_cddm(Object *ob, struct EditMesh *em, DerivedMesh *dm, float (*vertexCos)[3])
+DerivedMesh *get_cddm(Object *ob, struct BMEditMesh *em, DerivedMesh *dm, float (*vertexCos)[3])
{
if(dm && dm->type == DM_TYPE_CDDM)
return dm;
@@ -177,13 +179,13 @@ DerivedMesh *get_cddm(Object *ob, struct EditMesh *em, DerivedMesh *dm, float (*
}
/* returns a derived mesh if dm == NULL, for deforming modifiers that need it */
-DerivedMesh *get_dm(Object *ob, struct EditMesh *em, DerivedMesh *dm, float (*vertexCos)[3], int orco)
+DerivedMesh *get_dm(Object *ob, struct BMEditMesh *em, DerivedMesh *dm, float (*vertexCos)[3], int orco)
{
if(dm)
return dm;
if(ob->type==OB_MESH) {
- if(em) dm= CDDM_from_editmesh(em, ob->data);
+ if(em) dm= CDDM_from_BMEditMesh(em, ob->data, FALSE, FALSE);
else dm = CDDM_from_mesh((struct Mesh *)(ob->data), ob);
if(vertexCos) {
@@ -260,5 +262,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(WeightVGProximity);
INIT_TYPE(DynamicPaint);
INIT_TYPE(Remesh);
+ INIT_TYPE(NgonInterp);
#undef INIT_TYPE
}
diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h
index ad62e073ea2..623fe996668 100644
--- a/source/blender/modifiers/intern/MOD_util.h
+++ b/source/blender/modifiers/intern/MOD_util.h
@@ -44,8 +44,8 @@ struct TexResult;
void get_texture_value(struct Tex *texture, float *tex_co, struct TexResult *texres);
void get_texture_coords(struct MappingInfoModifierData *dmd, struct Object *ob, struct DerivedMesh *dm, float (*co)[3], float (*texco)[3], int numVerts);
void modifier_vgroup_cache(struct ModifierData *md, float (*vertexCos)[3]);
-struct DerivedMesh *get_cddm(struct Object *ob, struct EditMesh *em, struct DerivedMesh *dm, float (*vertexCos)[3]);
-struct DerivedMesh *get_dm(struct Object *ob, struct EditMesh *em, struct DerivedMesh *dm, float (*vertexCos)[3], int orco);
+struct DerivedMesh *get_cddm(struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm, float (*vertexCos)[3]);
+struct DerivedMesh *get_dm(struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm, float (*vertexCos)[3], int orco);
void modifier_get_vgroup(struct Object *ob, struct DerivedMesh *dm, const char *name, struct MDeformVert **dvert, int *defgrp_index);
#endif /* __MOD_UTIL_H__ */
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index 77ce879bbf6..7cd65236c5d 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -47,6 +47,7 @@
#include "BKE_camera.h"
+#include "BKE_mesh.h"
#include "BKE_DerivedMesh.h"
#include "MOD_modifiertypes.h"
@@ -147,10 +148,12 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
Object *ob, DerivedMesh *dm)
{
float (*coords)[3], (*co)[3];
- MTFace *tface;
- int i, numVerts, numFaces;
+ MLoopUV *mloop_uv;
+ MTexPoly *mtexpoly, *mt = NULL;
+ int i, numVerts, numPolys, numLoops;
Image *image = umd->image;
- MFace *mface, *mf;
+ MPoly *mpoly, *mp;
+ MLoop *mloop;
int override_image = ((umd->flags & MOD_UVPROJECT_OVERRIDEIMAGE) != 0);
Projector projectors[MOD_UVPROJECT_MAXPROJECTORS];
int num_projectors = 0;
@@ -172,10 +175,10 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
/* make sure there are UV Maps available */
- if(!CustomData_has_layer(&dm->faceData, CD_MTFACE)) return dm;
+ if(!CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) return dm;
/* make sure we're using an existing layer */
- CustomData_validate_layer_name(&dm->faceData, CD_MTFACE, umd->uvlayer_name, uvname);
+ CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, umd->uvlayer_name, uvname);
/* calculate a projection matrix and normal for each projector */
for(i = 0; i < num_projectors; ++i) {
@@ -259,11 +262,16 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal);
}
- numFaces = dm->getNumFaces(dm);
+ numPolys = dm->getNumPolys(dm);
+ numLoops = dm->getNumLoops(dm);
/* make sure we are not modifying the original UV map */
- tface = CustomData_duplicate_referenced_layer_named(&dm->faceData,
- CD_MTFACE, uvname, numFaces);
+ mloop_uv = CustomData_duplicate_referenced_layer_named(&dm->loopData,
+ CD_MLOOPUV, uvname, numLoops);
+
+ /* can be NULL */
+ mtexpoly = CustomData_duplicate_referenced_layer_named(&dm->polyData,
+ CD_MTEXPOLY, uvname, numPolys);
numVerts = dm->getNumVerts(dm);
@@ -280,25 +288,28 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
for(i = 0, co = coords; i < numVerts; ++i, ++co)
mul_project_m4_v3(projectors[0].projmat, *co);
- mface = dm->getFaceArray(dm);
+ mpoly = dm->getPolyArray(dm);
+ mloop = dm->getLoopArray(dm);
/* apply coords as UVs, and apply image if tfaces are new */
- for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tface) {
- if(override_image || !image || tface->tpage == image) {
+ for(i = 0, mp = mpoly; i < numPolys; ++i, ++mp, ++mt) {
+ if(override_image || !image || (mtexpoly == NULL || mt->tpage == image)) {
if(num_projectors == 1) {
if(projectors[0].uci) {
- unsigned int fidx= mf->v4 ? 3:2;
+ unsigned int fidx= mp->totloop - 1;
do {
- unsigned int vidx= *(&mf->v1 + fidx);
- project_from_camera(tface->uv[fidx], coords[vidx], projectors[0].uci);
+ unsigned int lidx= mp->loopstart + fidx;
+ unsigned int vidx= mloop[lidx].v;
+ project_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci);
} while (fidx--);
}
else {
/* apply transformed coords as UVs */
- unsigned int fidx= mf->v4 ? 3:2;
+ unsigned int fidx= mp->totloop - 1;
do {
- unsigned int vidx= *(&mf->v1 + fidx);
- copy_v2_v2(tface->uv[fidx], coords[vidx]);
+ unsigned int lidx= mp->loopstart + fidx;
+ unsigned int vidx= mloop[lidx].v;
+ copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]);
} while (fidx--);
}
} else {
@@ -311,11 +322,7 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
float best_dot;
/* get the untransformed face normal */
- if(mf->v4) {
- normal_quad_v3(face_no, coords[mf->v1], coords[mf->v2], coords[mf->v3], coords[mf->v4]);
- } else {
- normal_tri_v3(face_no, coords[mf->v1], coords[mf->v2], coords[mf->v3]);
- }
+ mesh_calc_poly_normal_coords(mp, mloop + mp->loopstart, (const float (*)[3])coords, face_no);
/* find the projector which the face points at most directly
* (projector normal with largest dot product is best)
@@ -333,29 +340,31 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
}
if(best_projector->uci) {
- unsigned int fidx= mf->v4 ? 3:2;
+ unsigned int fidx= mp->totloop - 1;
do {
- unsigned int vidx= *(&mf->v1 + fidx);
- project_from_camera(tface->uv[fidx], coords[vidx], best_projector->uci);
+ unsigned int lidx= mp->loopstart + fidx;
+ unsigned int vidx= mloop[lidx].v;
+ project_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci);
} while (fidx--);
}
else {
- unsigned int fidx= mf->v4 ? 3:2;
+ unsigned int fidx= mp->totloop - 1;
do {
- unsigned int vidx= *(&mf->v1 + fidx);
+ unsigned int lidx= mp->loopstart + fidx;
+ unsigned int vidx= mloop[lidx].v;
float tco[3];
copy_v3_v3(tco, coords[vidx]);
mul_project_m4_v3(best_projector->projmat, tco);
- copy_v2_v2(tface->uv[fidx], tco);
+ copy_v2_v2(mloop_uv[lidx].uv, tco);
} while (fidx--);
}
}
}
- if(override_image) {
- tface->tpage = image;
+ if(override_image && mtexpoly) {
+ mt->tpage = image;
}
}
@@ -386,7 +395,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
- struct EditMesh *UNUSED(editData),
+ struct BMEditMesh *UNUSED(editData),
DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index 41702a74cc1..4d058197be5 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -330,7 +330,7 @@ static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData,
}
}
-static void deformVertsEM(ModifierData *md, Object *ob, struct EditMesh *editData,
+static void deformVertsEM(ModifierData *md, Object *ob, struct BMEditMesh *editData,
DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *dm = derivedData;
@@ -338,7 +338,7 @@ static void deformVertsEM(ModifierData *md, Object *ob, struct EditMesh *editDat
if(use_dm) {
if(!derivedData)
- dm = CDDM_from_editmesh(editData, ob->data);
+ dm = CDDM_from_BMEditMesh(editData, ob->data, FALSE, FALSE);
}
deformVerts(md, ob, dm, vertexCos, numVerts, 0, 0);
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index f4377e82408..15f78e15073 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -345,7 +345,7 @@ static void deformVerts(ModifierData *md, Object *ob,
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct EditMesh *editData,
+ ModifierData *md, Object *ob, struct BMEditMesh *editData,
DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *dm= derivedData;
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index e4d1d7d0eb0..45c934654d0 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -266,7 +266,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
- struct EditMesh *UNUSED(editData),
+ struct BMEditMesh *UNUSED(editData),
DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index 38de944cf45..81a6ecc99e5 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -398,7 +398,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
- struct EditMesh *UNUSED(editData),
+ struct BMEditMesh *UNUSED(editData),
DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index c1aa68d1544..f785f112ccb 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -460,8 +460,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
target_dm = CDDM_from_curve(obr);
else if (obr->type == OB_MESH) {
Mesh *me = (Mesh*)obr->data;
- if (me->edit_mesh)
- target_dm = CDDM_from_editmesh((EditMesh*)me->edit_mesh, me);
+ if (me->edit_btmesh)
+ target_dm = CDDM_from_BMEditMesh(me->edit_btmesh, me, FALSE, FALSE);
else
target_dm = CDDM_from_mesh(me, obr);
}
@@ -534,7 +534,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
- struct EditMesh *UNUSED(editData),
+ struct BMEditMesh *UNUSED(editData),
DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
diff --git a/source/blender/render/SConscript b/source/blender/render/SConscript
index c292af45ec0..5af2bf05ef3 100644
--- a/source/blender/render/SConscript
+++ b/source/blender/render/SConscript
@@ -6,7 +6,7 @@ raysources = env.Glob('intern/raytrace/*.cpp')
incs = 'intern/include #/intern/guardedalloc ../blenlib ../makesdna ../makesrna'
incs += ' extern/include ../blenkernel ../radiosity/extern/include ../imbuf'
-incs += ' ../include ../blenloader ../../../intern/smoke/extern ../../../intern/mikktspace'
+incs += ' ../include ../blenloader ../../../intern/smoke/extern ../../../intern/mikktspace ../bmesh'
incs += ' ../freestyle'
cflags_raytrace = env['CCFLAGS']
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 354490cc59c..50e3d613ce3 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -1519,7 +1519,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;
@@ -1536,7 +1536,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;
@@ -1747,8 +1747,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);
@@ -1792,7 +1792,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);
@@ -1851,7 +1851,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);
@@ -2728,8 +2728,8 @@ static void init_render_dm(DerivedMesh *dm, Render *re, ObjectRen *obr,
for(mat_iter= 0; (mat_iter < ob->totcol || (mat_iter==0 && ob->totcol==0)); mat_iter++) {
ma= give_render_material(re, ob, mat_iter+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;
@@ -3110,10 +3110,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;
@@ -3352,7 +3352,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;
@@ -3432,8 +3432,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/pixelshading.c b/source/blender/render/intern/source/pixelshading.c
index 24683ec57f7..9746a6dbd86 100644
--- a/source/blender/render/intern/source/pixelshading.c
+++ b/source/blender/render/intern/source/pixelshading.c
@@ -161,7 +161,7 @@ static void render_lighting_halo(HaloRen *har, float col_r[3])
copy_v3_v3(lvrot, lv);
mul_m3_v3(lar->imat, lvrot);
- x= MAX2(fabs(lvrot[0]/lvrot[2]) , fabs(lvrot[1]/lvrot[2]));
+ x = maxf(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2]));
/* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
inpr= 1.0/(sqrt(1.0f+x*x));
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 95cad5a4e46..49bacbaf693 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -3662,7 +3662,7 @@ void RE_sample_material_color(Material *mat, float color[3], float *alpha, const
/* Get face data */
mvert = orcoDm->getVertArray(orcoDm);
- mface = orcoDm->getFaceArray(orcoDm);
+ mface = orcoDm->getTessFaceArray(orcoDm);
if (!mvert || !mface || !mat) return;
v1=mface[face_index].v1, v2=mface[face_index].v2, v3=mface[face_index].v3;
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index a4354c290c4..ec370bc26fb 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -1204,7 +1204,7 @@ float lamp_get_visibility(LampRen *lar, const float co[3], float lv[3], float *d
copy_v3_v3(lvrot, lv);
mul_m3_v3(lar->imat, lvrot);
- x= MAX2(fabs(lvrot[0]/lvrot[2]) , fabs(lvrot[1]/lvrot[2]));
+ x = maxf(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2]));
/* 1.0f/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
inpr= 1.0f/(sqrt(1.0f+x*x));
diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c
index 89f74418563..cdc185160d5 100644
--- a/source/blender/render/intern/source/strand.c
+++ b/source/blender/render/intern/source/strand.c
@@ -974,7 +974,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
@@ -1008,7 +1008,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/SConscript b/source/blender/windowmanager/SConscript
index 368f344e5fa..edc56f8424c 100644
--- a/source/blender/windowmanager/SConscript
+++ b/source/blender/windowmanager/SConscript
@@ -10,7 +10,7 @@ sources = env.Glob('intern/*.c')
incs = '. ../editors/include ../python ../makesdna ../blenlib ../blenkernel'
incs += ' ../nodes ../imbuf ../blenloader ../render/extern/include'
incs += ' ../radiosity/extern/include'
-incs += ' ../makesrna ../gpu ../blenfont'
+incs += ' ../makesrna ../gpu ../blenfont ../bmesh'
incs += ' ../freestyle'
incs += ' #/intern/guardedalloc #/intern/memutil #/intern/ghost'
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 4fe11044d30..df4ebfd9b9f 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -90,9 +90,16 @@ static void wm_paintcursor_draw(bContext *C, ARegion *ar)
if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) {
int x = 0, y = 0;
wm_get_cursor_position(win, &x, &y);
- pc->draw(C, x - ar_other->winrct.xmin, y - ar_other->winrct.ymin, pc->customdata);
- } else {
- pc->draw(C, win->eventstate->x - ar_other->winrct.xmin, win->eventstate->y - ar_other->winrct.ymin, pc->customdata);
+ pc->draw(C,
+ x - ar_other->winrct.xmin,
+ y - ar_other->winrct.ymin,
+ pc->customdata);
+ }
+ else {
+ pc->draw(C,
+ win->eventstate->x - ar_other->winrct.xmin,
+ win->eventstate->y - ar_other->winrct.ymin,
+ pc->customdata);
}
}
}
@@ -458,7 +465,8 @@ static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple)
if(triple->x[x] > maxsize || triple->y[y] > maxsize) {
glBindTexture(triple->target, 0);
- printf("WM: failed to allocate texture for triple buffer drawing (texture too large for graphics card).\n");
+ printf("WM: failed to allocate texture for triple buffer drawing "
+ "(texture too large for graphics card).\n");
return 0;
}
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index f7da70b6c77..d78faa76855 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -82,7 +82,8 @@
# include "RNA_enum_types.h"
#endif
-static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, short context, short poll_only);
+static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports,
+ short context, short poll_only);
/* ************ event management ************** */
@@ -223,7 +224,9 @@ void wm_event_do_notifiers(bContext *C)
}
}
- if(note->window==win || (note->window == NULL && (note->reference == NULL || note->reference == CTX_data_scene(C)))) {
+ if (note->window == win ||
+ (note->window == NULL && (note->reference == NULL || note->reference == CTX_data_scene(C))))
+ {
if(note->category==NC_SCENE) {
if(note->data==ND_FRAME)
do_anim= 1;
@@ -637,7 +640,8 @@ int WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, PointerRNA *properties, ReportList *reports)
{
- wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname); /* XXX operatortype names are static still. for debug */
+ /* XXX operatortype names are static still. for debug */
+ wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname);
/* XXX adding new operator could be function, only happens here now */
op->type= ot;
@@ -818,8 +822,10 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
if(op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
wm->op_undo_depth--;
}
- else
- printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
+ else {
+ /* debug, important to leave a while, should never happen */
+ printf("invalid operator call '%s'\n", ot->idname);
+ }
/* Note, if the report is given as an argument then assume the caller will deal with displaying them
* currently python only uses this */
@@ -842,9 +848,12 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
int wrap;
if (op->opm) {
- wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER));
- } else {
- wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->flag & OP_GRAB_POINTER) || (ot->flag & OPTYPE_GRAB_POINTER));
+ wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) &&
+ ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER));
+ }
+ else {
+ wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) &&
+ ((op->flag & OP_GRAB_POINTER) || (ot->flag & OPTYPE_GRAB_POINTER));
}
/* exception, cont. grab in header is annoying */
@@ -860,7 +869,9 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
ARegion *ar= CTX_wm_region(C);
ScrArea *sa= CTX_wm_area(C);
- if(ar && ar->regiontype == RGN_TYPE_WINDOW && event && BLI_in_rcti(&ar->winrct, event->x, event->y)) {
+ if (ar && ar->regiontype == RGN_TYPE_WINDOW && event &&
+ BLI_in_rcti(&ar->winrct, event->x, event->y))
+ {
winrect= &ar->winrct;
}
else if(sa) {
@@ -895,7 +906,8 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
* this is for python to access since its done the operator lookup
*
* invokes operator in context */
-static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, short context, short poll_only)
+static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports,
+ short context, short poll_only)
{
wmWindow *window= CTX_wm_window(C);
wmEvent *event;
@@ -1297,7 +1309,8 @@ static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *eve
}
/* Warning: this function removes a modal handler, when finished */
-static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties)
+static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler,
+ wmEvent *event, PointerRNA *properties)
{
int retval= OPERATOR_PASS_THROUGH;
@@ -1615,9 +1628,10 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
if(!keymap->poll || keymap->poll(C)) {
for(kmi= keymap->items.first; kmi; kmi= kmi->next) {
if(wm_eventmatch(event, kmi)) {
-
- event->keymap_idname= kmi->idname; /* weak, but allows interactive callback to not use rawkey */
-
+
+ /* weak, but allows interactive callback to not use rawkey */
+ event->keymap_idname = kmi->idname;
+
action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
if(action & WM_HANDLER_BREAK) /* not always_pass here, it denotes removed handler */
break;
@@ -1716,7 +1730,8 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
) {
event->val = KM_DBL_CLICK;
/* removed this because in cases where we're this is used as a single click
- * event, this will give old coords, since the distance is checked above, using new coords should be ok. */
+ * event, this will give old coords,
+ * since the distance is checked above, using new coords should be ok. */
// event->x = win->eventstate->prevclickx;
// event->y = win->eventstate->prevclicky;
action |= wm_handlers_do(C, event, handlers);
@@ -2233,7 +2248,8 @@ void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
}
}
-wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
+wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers,
+ wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
{
wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler");
handler->ui_handle= func;
@@ -2249,7 +2265,8 @@ wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, w
}
/* set "postpone" for win->modalhandlers, this is in a running for() loop in wm_handlers_do() */
-void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata, int postpone)
+void WM_event_remove_ui_handler(ListBase *handlers,
+ wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata, int postpone)
{
wmEventHandler *handler;
@@ -2629,7 +2646,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
case GHOST_kEventButtonDown:
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 */
+
+ /* Note!, this starts as 0/1 but later is converted to KM_PRESS/KM_RELEASE by tweak */
+ event.val= (type==GHOST_kEventButtonDown) ? KM_PRESS:KM_RELEASE;
if (bd->button == GHOST_kButtonMaskLeft)
event.type= LEFTMOUSE;
@@ -2700,7 +2719,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
if (event.utf8_buf[0]) {
if (BLI_str_utf8_size(event.utf8_buf) == -1) {
- printf("%s: ghost detected an invalid unicode character '%d'!\n", __func__, (int)(unsigned char)event.utf8_buf[0]);
+ printf("%s: ghost detected an invalid unicode character '%d'!\n",
+ __func__, (int)(unsigned char)event.utf8_buf[0]);
event.utf8_buf[0]= '\0';
}
}
@@ -2709,19 +2729,27 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
/* assigning both first and second is strange - campbell */
switch(event.type) {
case LEFTSHIFTKEY: case RIGHTSHIFTKEY:
- event.shift= evt->shift= (event.val==KM_PRESS) ? ((evt->ctrl || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+ event.shift = evt->shift = (event.val == KM_PRESS) ?
+ ((evt->ctrl || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) :
+ FALSE;
break;
case LEFTCTRLKEY: case RIGHTCTRLKEY:
- event.ctrl= evt->ctrl= (event.val==KM_PRESS) ? ((evt->shift || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+ event.ctrl = evt->ctrl = (event.val == KM_PRESS) ?
+ ((evt->shift || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) :
+ FALSE;
break;
case LEFTALTKEY: case RIGHTALTKEY:
- event.alt= evt->alt= (event.val==KM_PRESS) ? ((evt->ctrl || evt->shift || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+ event.alt = evt->alt = (event.val == KM_PRESS) ?
+ ((evt->ctrl || evt->shift || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) :
+ FALSE;
break;
case OSKEY:
- event.oskey= evt->oskey= (event.val==KM_PRESS) ? ((evt->ctrl || evt->alt || evt->shift) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+ event.oskey = evt->oskey = (event.val == KM_PRESS) ?
+ ((evt->ctrl || evt->alt || evt->shift) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) :
+ FALSE;
break;
default:
- if(event.val==KM_PRESS && event.keymodifier==0)
+ if(event.val == KM_PRESS && event.keymodifier==0)
evt->keymodifier= event.type; /* only set in eventstate, for next event */
else if(event.val==KM_RELEASE && event.keymodifier==event.type)
event.keymodifier= evt->keymodifier= 0;
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 1c8826f5321..41a77d65622 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -393,7 +393,10 @@ void WM_read_file(bContext *C, const char *filepath, ReportList *reports)
// XXX mainwindow_set_filename_to_title(G.main->name);
- if(retval == BKE_READ_FILE_OK_USERPREFS) wm_init_userdef(C); // in case a userdef is read from regular .blend
+ if(retval == BKE_READ_FILE_OK_USERPREFS) {
+ /* in case a userdef is read from regular .blend */
+ wm_init_userdef(C);
+ }
if (retval != BKE_READ_FILE_FAIL) {
G.relbase_valid = 1;
@@ -423,13 +426,20 @@ void WM_read_file(bContext *C, const char *filepath, ReportList *reports)
CTX_wm_window_set(C, NULL); /* exits queues */
-#if 0 /* gives popups on windows but not linux, bug in report API but disable for now to stop users getting annoyed */
+#if 0
+ /* gives popups on windows but not linux, bug in report API
+ * but disable for now to stop users getting annoyed */
/* TODO, make this show in header info window */
{
Scene *sce;
- for(sce= G.main->scene.first; sce; sce= sce->id.next) {
- if(sce->r.engine[0] && BLI_findstring(&R_engines, sce->r.engine, offsetof(RenderEngineType, idname)) == NULL) {
- BKE_reportf(reports, RPT_WARNING, "Engine not available: '%s' for scene: %s, an addon may need to be installed or enabled", sce->r.engine, sce->id.name+2);
+ for (sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if (sce->r.engine[0] &&
+ BLI_findstring(&R_engines, sce->r.engine, offsetof(RenderEngineType, idname)) == NULL)
+ {
+ BKE_reportf(reports, RPT_WARNING,
+ "Engine not available: '%s' for scene: %s, "
+ "an addon may need to be installed or enabled",
+ sce->r.engine, sce->id.name+2);
}
}
}
@@ -662,8 +672,10 @@ static ImBuf *blend_file_thumb(Scene *scene, int **thumb_pt)
return NULL;
/* gets scaled to BLEN_THUMB_SIZE */
- ibuf= ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, IB_rect, OB_SOLID, err_out);
-
+ ibuf= ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera,
+ BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
+ IB_rect, OB_SOLID, err_out);
+
if(ibuf) {
float aspect= (scene->r.xsch*scene->r.xasp) / (scene->r.ysch*scene->r.yasp);
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index 4fb8751de69..c97d2b58596 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -74,7 +74,9 @@ wmGesture *WM_gesture_new(bContext *C, wmEvent *event, int type)
wm_subwindow_getorigin(window, gesture->swinid, &sx, &sy);
- if( ELEM5(type, WM_GESTURE_RECT, WM_GESTURE_CROSS_RECT, WM_GESTURE_TWEAK, WM_GESTURE_CIRCLE, WM_GESTURE_STRAIGHTLINE)) {
+ if (ELEM5(type, WM_GESTURE_RECT, WM_GESTURE_CROSS_RECT, WM_GESTURE_TWEAK,
+ WM_GESTURE_CIRCLE, WM_GESTURE_STRAIGHTLINE))
+ {
rcti *rect= MEM_callocN(sizeof(rcti), "gesture rect new");
gesture->customdata= rect;
@@ -234,6 +236,7 @@ static void draw_filled_lasso(wmGesture *gt)
short *lasso= (short *)gt->customdata;
int i;
+ BLI_begin_edgefill();
for (i=0; i<gt->points; i++, lasso+=2) {
float co[3];
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 661bd90435c..d603262227f 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -767,7 +767,9 @@ char *WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, int len)
return str;
}
-static wmKeyMapItem *wm_keymap_item_find_handlers(const bContext *C, ListBase *handlers, const char *opname, int UNUSED(opcontext), IDProperty *properties, int compare_props, int hotkey, wmKeyMap **keymap_r)
+static wmKeyMapItem *wm_keymap_item_find_handlers(
+ const bContext *C, ListBase *handlers, const char *opname, int UNUSED(opcontext),
+ IDProperty *properties, int compare_props, int hotkey, wmKeyMap **keymap_r)
{
wmWindowManager *wm= CTX_wm_manager(C);
wmEventHandler *handler;
@@ -806,7 +808,9 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(const bContext *C, ListBase *h
return NULL;
}
-static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C, const char *opname, int opcontext, IDProperty *properties, int compare_props, int hotkey, wmKeyMap **keymap_r)
+static wmKeyMapItem *wm_keymap_item_find_props(
+ const bContext *C, const char *opname, int opcontext,
+ IDProperty *properties, int compare_props, int hotkey, wmKeyMap **keymap_r)
{
wmWindow *win= CTX_wm_window(C);
ScrArea *sa= CTX_wm_area(C);
@@ -854,7 +858,9 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C, const char *op
return found;
}
-static wmKeyMapItem *wm_keymap_item_find(const bContext *C, const char *opname, int opcontext, IDProperty *properties, const short hotkey, const short sloppy, wmKeyMap **keymap_r)
+static wmKeyMapItem *wm_keymap_item_find(
+ const bContext *C, const char *opname, int opcontext,
+ IDProperty *properties, const short hotkey, const short sloppy, wmKeyMap **keymap_r)
{
wmKeyMapItem *found= wm_keymap_item_find_props(C, opname, opcontext, properties, 1, hotkey, keymap_r);
@@ -864,7 +870,9 @@ static wmKeyMapItem *wm_keymap_item_find(const bContext *C, const char *opname,
return found;
}
-char *WM_key_event_operator_string(const bContext *C, const char *opname, int opcontext, IDProperty *properties, const short sloppy, char *str, int len)
+char *WM_key_event_operator_string(
+ const bContext *C, const char *opname, int opcontext,
+ IDProperty *properties, const short sloppy, char *str, int len)
{
wmKeyMapItem *kmi= wm_keymap_item_find(C, opname, opcontext, properties, 0, sloppy, NULL);
@@ -876,7 +884,9 @@ char *WM_key_event_operator_string(const bContext *C, const char *opname, int op
return NULL;
}
-int WM_key_event_operator_id(const bContext *C, const char *opname, int opcontext, IDProperty *properties, int hotkey, wmKeyMap **keymap_r)
+int WM_key_event_operator_id(
+ const bContext *C, const char *opname, int opcontext,
+ IDProperty *properties, int hotkey, wmKeyMap **keymap_r)
{
wmKeyMapItem *kmi= wm_keymap_item_find(C, opname, opcontext, properties, hotkey, TRUE, keymap_r);
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 19c45164b53..eddd3c4f3ab 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -153,7 +153,9 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType*))
ot->name= IFACE_("Dummy Name");
}
- RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description:IFACE_("(undocumented operator)")); // XXX All ops should have a description but for now allow them not to.
+ // XXX All ops should have a description but for now allow them not to.
+ RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description:IFACE_("(undocumented operator)"));
+
RNA_def_struct_identifier(ot->srna, ot->idname);
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
@@ -1136,7 +1138,8 @@ int WM_operator_props_popup(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
{
if((op->type->flag & OPTYPE_REGISTER)==0) {
- BKE_reportf(op->reports, RPT_ERROR, "Operator '%s' does not have register enabled, incorrect invoke function.", op->type->idname);
+ BKE_reportf(op->reports, RPT_ERROR,
+ "Operator '%s' does not have register enabled, incorrect invoke function.", op->type->idname);
return OPERATOR_CANCELLED;
}
@@ -1845,7 +1848,10 @@ static void WM_OT_link_append(wmOperatorType *ot)
ot->flag |= OPTYPE_UNDO;
- WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_LOADLIB, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_DIRECTORY|WM_FILESEL_FILENAME| WM_FILESEL_RELPATH|WM_FILESEL_FILES, FILE_DEFAULTDISPLAY);
+ WM_operator_properties_filesel(
+ ot, FOLDERFILE|BLENDERFILE, FILE_LOADLIB, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH|WM_FILESEL_DIRECTORY|WM_FILESEL_FILENAME|WM_FILESEL_RELPATH|WM_FILESEL_FILES,
+ FILE_DEFAULTDISPLAY);
RNA_def_boolean(ot->srna, "link", 1, "Link", "Link the objects or datablocks rather than appending");
RNA_def_boolean(ot->srna, "autoselect", 1, "Select", "Select the linked objects");
@@ -3205,8 +3211,8 @@ static int radial_control_get_properties(bContext *C, wmOperator *op)
return 0;
/* slightly ugly; allow this property to not resolve
- correctly. needed because 3d texture paint shares the same
- keymap as 2d image paint */
+ * correctly. needed because 3d texture paint shares the same
+ * keymap as 2d image paint */
if(!radial_control_get_path(&ctx_ptr, op, "zoom_path",
&rc->zoom_ptr, &rc->zoom_prop, 2,
RC_PROP_REQUIRE_FLOAT|RC_PROP_ALLOW_MISSING))
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index fe967bbcd1c..599de5697f1 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -155,7 +155,8 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
CTX_wm_window_set(C, NULL);
}
- /* always set drawable and active to NULL, prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */
+ /* always set drawable and active to NULL,
+ * prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */
wm->windrawable= NULL;
wm->winactive= NULL;
@@ -751,7 +752,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private)
}
if(type!=GHOST_kEventWindowSize) {
- if(G.f & G_DEBUG) printf("win move event pos %d %d size %d %d\n", win->posx, win->posy, win->sizex, win->sizey);
+ if(G.f & G_DEBUG) {
+ printf("win move event pos %d %d size %d %d\n",
+ win->posx, win->posy, win->sizex, win->sizey);
+ }
}
}
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index 7a63435c215..1bf55cd96de 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -100,6 +100,7 @@ endif()
bf_intern_string
bf_intern_ghost
bf_rna
+ bf_bmesh
bf_blenkernel
bf_blenloader
bf_blenpluginapi
@@ -144,6 +145,7 @@ endif()
bf_blenfont
bf_intern_audaspace
blenkernel_blc
+ bf_bmesh
extern_binreloc
extern_minilzo
bf_intern_ghost # duplicate for linking
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index 56516f6662e..6eb2ab72e67 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -112,8 +112,38 @@ struct bPythonConstraint;
struct bConstraintOb;
struct Context;
struct ChannelDriver;
+struct BMEditMesh;
+struct Heap;
+struct HeapNode;
+struct Scene;
+struct SmallHash;
+struct SmallHashIter;
/*new render funcs */
+void EDBM_selectmode_set(struct BMEditMesh *em) {}
+void EDBM_LoadEditBMesh(struct Scene *scene, struct Object *ob) {}
+void EDBM_MakeEditBMesh(struct ToolSettings *ts, struct Scene *scene, struct Object *ob) {}
+void *g_system;
+
+struct Heap* BLI_heap_new (void){return NULL;}
+void BLI_heap_free (struct Heap *heap, void *ptrfreefp) {}
+struct HeapNode* BLI_heap_insert (struct Heap *heap, float value, void *ptr){return NULL;}
+void BLI_heap_remove (struct Heap *heap, struct HeapNode *node) {}
+int BLI_heap_empty (struct Heap *heap) {return 0;}
+int BLI_heap_size (struct Heap *heap){return 0;}
+struct HeapNode* BLI_heap_top (struct Heap *heap){return NULL;}
+void* BLI_heap_popmin (struct Heap *heap){return NULL;}
+
+void BLI_smallhash_init(struct SmallHash *hash) {}
+void BLI_smallhash_release(struct SmallHash *hash) {}
+void BLI_smallhash_insert(struct SmallHash *hash, uintptr_t key, void *item) {}
+void BLI_smallhash_remove(struct SmallHash *hash, uintptr_t key) {}
+void *BLI_smallhash_lookup(struct SmallHash *hash, uintptr_t key) { return NULL; }
+int BLI_smallhash_haskey(struct SmallHash *hash, uintptr_t key) { return 0; }
+int BLI_smallhash_count(struct SmallHash *hash) { return 0; }
+void *BLI_smallhash_iternext(struct SmallHashIter *iter, uintptr_t *key) { return NULL; }
+void *BLI_smallhash_iternew(struct SmallHash *hash, struct SmallHashIter *iter, uintptr_t *key) { return NULL; }
+
float *RE_RenderLayerGetPass(struct RenderLayer *rl, int passtype) {return (float *) NULL;}
float RE_filter_value(int type, float x) {return 0.0f;}
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name) {return (struct RenderLayer *)NULL;}
@@ -300,6 +330,8 @@ void ED_mesh_update(struct Mesh *mesh, struct bContext *C){}
void ED_mesh_vertices_add(struct Mesh *mesh, struct ReportList *reports, int count){}
void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count){}
void ED_mesh_faces_add(struct Mesh *mesh, struct ReportList *reports, int count){}
+void ED_mesh_loops_add(struct Mesh *mesh, struct ReportList *reports, int count){}
+void ED_mesh_polys_add(struct Mesh *mesh, struct ReportList *reports, int count){}
void ED_mesh_vertices_remove(struct Mesh *mesh, struct ReportList *reports, int count){}
void ED_mesh_edges_remove(struct Mesh *mesh, struct ReportList *reports, int count){}
void ED_mesh_faces_remove(struct Mesh *mesh, struct ReportList *reports, int count){}
@@ -315,6 +347,8 @@ void ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vertn
void ED_vgroup_delete(struct Object *ob, struct bDeformGroup *defgroup){}
void ED_vgroup_clear(struct Object *ob){}
void ED_vgroup_object_is_edit_mode(struct Object *ob){}
+long mesh_mirrtopo_table(struct Object *ob, char mode) { return 0; }
+intptr_t mesh_octree_table(struct Object *ob, struct BMEditMesh *em, float *co, char mode) { return 0; }
void ED_sequencer_update_view(struct bContext *C, int view){}
float ED_rollBoneToVector(struct EditBone *bone, float new_up_axis[3]){return 0.0f;}
@@ -337,7 +371,7 @@ void make_editNurb (struct Object *obedit){}
void uiItemR(struct uiLayout *layout, struct PointerRNA *ptr, char *propname, int flag, char *name, int icon){}
-struct PointerRNA uiItemFullO(struct uiLayout *layout, char *idname, char *name, int icon, struct IDProperty *properties, int context, int flag){struct PointerRNA a; return a;}
+struct PointerRNA uiItemFullO(struct uiLayout *layout, char *idname, char *name, int icon, struct IDProperty *properties, int context, int flag){struct PointerRNA a = {}; return a;}
struct uiLayout *uiLayoutRow(struct uiLayout *layout, int align){return (struct uiLayout *) NULL;}
struct uiLayout *uiLayoutColumn(struct uiLayout *layout, int align){return (struct uiLayout *) NULL;}
struct uiLayout *uiLayoutColumnFlow(struct uiLayout *layout, int number, int align){return (struct uiLayout *) NULL;}
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 674221644c4..432f0a2aa8c 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -800,6 +800,7 @@ endif()
bf_python_mathutils
bf_freestyle
bf_ikplugin
+ bf_bmesh
bf_modifiers
bf_blenkernel
bf_nodes
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 8220eb808e8..68e72bb1611 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -729,7 +729,7 @@ static int render_frame(int argc, const char **argv, void *data)
BKE_reports_init(&reports, RPT_PRINT);
- frame = MIN2(MAXFRAME, MAX2(MINAFRAME, frame));
+ frame = CLAMPIS(frame, MINAFRAME, MAXFRAME);
RE_SetReports(re, &reports);
RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, frame, frame, scene->r.frame_step);
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
index 7e7b3d2e3d4..0abea7fa28e 100644
--- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
+++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
@@ -39,6 +39,8 @@ KX_BlenderCanvas::KX_BlenderCanvas(struct wmWindow *win, RAS_Rect &rect, struct
m_win(win),
m_frame_rect(rect)
{
+ // initialize area so that it's available for game logic on frame 1 (ImageViewport)
+ m_area_rect = rect;
// area boundaries needed for mouse coordinates in Letterbox framing mode
m_area_left = ar->winrct.xmin;
m_area_top = ar->winrct.ymax;
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
index c22dc1a66cd..1cecac4001c 100644
--- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -911,16 +911,16 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, KX_Scene* scene,
MVert *mvert = dm->getVertArray(dm);
int totvert = dm->getNumVerts(dm);
- MFace *mface = dm->getFaceArray(dm);
- MTFace *tface = static_cast<MTFace*>(dm->getFaceDataArray(dm, CD_MTFACE));
- MCol *mcol = static_cast<MCol*>(dm->getFaceDataArray(dm, CD_MCOL));
+ MFace *mface = dm->getTessFaceArray(dm);
+ MTFace *tface = static_cast<MTFace*>(dm->getTessFaceDataArray(dm, CD_MTFACE));
+ MCol *mcol = static_cast<MCol*>(dm->getTessFaceDataArray(dm, CD_MCOL));
float (*tangent)[4] = NULL;
- int totface = dm->getNumFaces(dm);
+ int totface = dm->getNumTessFaces(dm);
const char *tfaceName = "";
if(tface) {
DM_add_tangent_layer(dm);
- tangent = (float(*)[4])dm->getFaceDataArray(dm, CD_TANGENT);
+ tangent = (float(*)[4])dm->getTessFaceDataArray(dm, CD_TANGENT);
}
meshobj = new RAS_MeshObject(mesh);
diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.cpp b/source/gameengine/GamePlayer/common/GPC_Canvas.cpp
index df1bf31ec12..82950f571f9 100644
--- a/source/gameengine/GamePlayer/common/GPC_Canvas.cpp
+++ b/source/gameengine/GamePlayer/common/GPC_Canvas.cpp
@@ -52,6 +52,11 @@ GPC_Canvas::GPC_Canvas(
m_height(height),
m_bannersEnabled(false)
{
+ // initialize area so that it's available for game logic on frame 1 (ImageViewport)
+ m_displayarea.m_x1 = 0;
+ m_displayarea.m_y1 = 0;
+ m_displayarea.m_x2 = width;
+ m_displayarea.m_y2 = height;
}
diff --git a/source/gameengine/Ketsji/KX_NavMeshObject.cpp b/source/gameengine/Ketsji/KX_NavMeshObject.cpp
index f92319e508b..e6f8d7175dc 100644
--- a/source/gameengine/Ketsji/KX_NavMeshObject.cpp
+++ b/source/gameengine/Ketsji/KX_NavMeshObject.cpp
@@ -112,7 +112,7 @@ bool KX_NavMeshObject::BuildVertIndArrays(float *&vertices, int& nverts,
{
DerivedMesh* dm = mesh_create_derived_no_virtual(KX_GetActiveScene()->GetBlenderScene(), GetBlenderObject(),
NULL, CD_MASK_MESH);
- int* recastData = (int*) dm->getFaceDataArray(dm, CD_RECAST);
+ int* recastData = (int*) dm->getTessFaceDataArray(dm, CD_RECAST);
if (recastData)
{
int *dtrisToPolysMap=NULL, *dtrisToTrisMap=NULL, *trisToFacesMap=NULL;
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
index 4b3e2ea33a3..a22122a245e 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
@@ -1434,11 +1434,11 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
}
MVert *mvert = dm->getVertArray(dm);
- MFace *mface = dm->getFaceArray(dm);
- numpolys = dm->getNumFaces(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
+ numpolys = dm->getNumTessFaces(dm);
numverts = dm->getNumVerts(dm);
- int* index = (int*)dm->getFaceDataArray(dm, CD_ORIGINDEX);
- MTFace *tface = (MTFace *)dm->getFaceDataArray(dm, CD_MTFACE);
+ int* index = (int*)dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ MTFace *tface = (MTFace *)dm->getTessFaceDataArray(dm, CD_MTFACE);
m_shapeType = (polytope) ? PHY_SHAPE_POLYTOPE : PHY_SHAPE_MESH;
@@ -1734,10 +1734,10 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA
* */
MVert *mvert = dm->getVertArray(dm);
- MFace *mface = dm->getFaceArray(dm);
- numpolys = dm->getNumFaces(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
+ numpolys = dm->getNumTessFaces(dm);
numverts = dm->getNumVerts(dm);
- int* index = (int*)dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ int* index = (int*)dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
MFace *mf;
MVert *mv;
@@ -1746,7 +1746,7 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA
if(CustomData_has_layer(&dm->faceData, CD_MTFACE))
{
- MTFace *tface = (MTFace *)dm->getFaceDataArray(dm, CD_MTFACE);
+ MTFace *tface = (MTFace *)dm->getTessFaceDataArray(dm, CD_MTFACE);
MTFace *tf;
vector<bool> vert_tag_array(numverts, false);